diff --git a/README.md b/README.md
index b26ac32..ab7dd6f 100644
--- a/README.md
+++ b/README.md
@@ -40,9 +40,9 @@ The UEAFactoryV1 is the central contract responsible for deploying and managing
- `registerNewChain(bytes32 _chainHash, bytes32 _vmHash)`: Register a new chain with its VM type
- `registerUEA(bytes32 _chainHash, bytes32 _vmHash, address _UEA)`: Register a UEA implementation for a VM type
-- `deployUEA(UniversalAccount memory _id)`: Deploy a new UEA for an external chain user
-- `computeUEA(UniversalAccount memory _id)`: Compute the address of a UEA before deployment
-- `getUEAForOrigin(UniversalAccount memory _id)`: Get the UEA address for a given external chain user
+- `deployUEA(UniversalAccountId memory _id)`: Deploy a new UEA for an external chain user
+- `computeUEA(UniversalAccountId memory _id)`: Compute the address of a UEA before deployment
+- `getUEAForOrigin(UniversalAccountId memory _id)`: Get the UEA address for a given external chain user
## UEA Implementations
diff --git a/src/Interfaces/IUEA.sol b/src/Interfaces/IUEA.sol
index 3dc49b6..6f9cdb5 100644
--- a/src/Interfaces/IUEA.sol
+++ b/src/Interfaces/IUEA.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
-import {UniversalAccount, UniversalPayload} from "../libraries/Types.sol";
+import {UniversalAccountId, UniversalPayload} from "../libraries/Types.sol";
/**
* @title IUEA (Interface for Universal Executor Account)
@@ -26,7 +26,7 @@ interface IUEA {
/**
* @dev Initializes the UEA with the Universal Account information.
- * @param universalAccount The UniversalAccount struct containing:
+ * @param universalAccount The UniversalAccountId struct containing:
* - chain: The name of the external chain (e.g., "eip155:1", "eip155:900")
* - owner: The owner's address/public key from the external chain
*
@@ -35,13 +35,13 @@ interface IUEA {
* - For EVM-based UEAs: An Ethereum address (20 bytes)
* - For SVM-based UEAs: A Solana public key (32 bytes)
*/
- function initialize(UniversalAccount memory universalAccount) external;
+ function initialize(UniversalAccountId memory universalAccount) external;
/**
* @dev Returns the Universal Account information for this UEA.
- * @return The UniversalAccount struct containing the chain name and owner key.
+ * @return The UniversalAccountId struct containing the chain name and owner key.
*/
- function universalAccount() external view returns (UniversalAccount memory);
+ function universalAccount() external view returns (UniversalAccountId memory);
/**
* @dev Verifies if a signature is valid for a given message hash.
@@ -51,11 +51,11 @@ interface IUEA {
*
* @notice Implementation behavior varies by UEA type:
* - For EVM-based UEAs: Uses ECDSA recovery to verify that the signature was created by the
- * address stored in the UniversalAccount.owner field. The owner is expected to be an
+ * address stored in the UniversalAccountId.owner field. The owner is expected to be an
* Ethereum address represented as bytes.
*
* - For SVM-based UEAs: Uses a precompiled contract to verify Ed25519 signatures, where the
- * UniversalAccount.owner field contains a Solana public key. The verification is done through
+ * UniversalAccountId.owner field contains a Solana public key. The verification is done through
* a call to the VERIFIER_PRECOMPILE address.
*/
function verifyPayloadSignature(bytes32 messageHash, bytes memory signature) external view returns (bool);
diff --git a/src/Interfaces/IUEAFactory.sol b/src/Interfaces/IUEAFactory.sol
index 152d97b..48474b1 100644
--- a/src/Interfaces/IUEAFactory.sol
+++ b/src/Interfaces/IUEAFactory.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
-import {UniversalAccount} from "../libraries/Types.sol";
+import {UniversalAccountId} from "../libraries/Types.sol";
/**
* @title IUEAFactory
@@ -13,7 +13,7 @@ interface IUEAFactory {
event ChainRegistered(bytes32 indexed chainHash, bytes32 vmHash);
/// @notice Emitted when a new UEA is deployed for an external chain owner
- event UEADeployed(address indexed UEA, bytes owner, bytes32 chainHash);
+ event UEADeployed(address indexed UEA, bytes owner, uint256 sourceChainId, bytes32 chainHash);
/// @notice Emitted when a UEA implementation is registered for a specific VM type
event UEARegistered(bytes32 indexed chainHash, address UEA_Logic, bytes32 vmHash);
@@ -48,7 +48,7 @@ interface IUEAFactory {
* @param _id The Universal Account information containing chain and owner key
* @return The address of the deployed UEA
*/
- function deployUEA(UniversalAccount memory _id) external returns (address);
+ function deployUEA(UniversalAccountId memory _id) external returns (address);
/**
* @dev Returns the UEA implementation address for a given chain
@@ -71,7 +71,7 @@ interface IUEAFactory {
* @return account The Universal Account information associated with this UEA
* @return isUEA True if the address addr is a UEA contract. Else it is a native EOA of PUSH chain (i.e., isUEA = false)
*/
- function getOriginForUEA(address addr) external view returns (UniversalAccount memory account, bool isUEA);
+ function getOriginForUEA(address addr) external view returns (UniversalAccountId memory account, bool isUEA);
/**
* @dev Returns the computed UEA address for a given Universal Account ID and deployment status
@@ -79,5 +79,5 @@ interface IUEAFactory {
* @return uea The address of the UEA (computed deterministically)
* @return isDeployed True if the UEA has already been deployed
*/
- function getUEAForOrigin(UniversalAccount memory _id) external view returns (address uea, bool isDeployed);
+ function getUEAForOrigin(UniversalAccountId memory _id) external view returns (address uea, bool isDeployed);
}
diff --git a/src/UEA/UEA_EVM.sol b/src/UEA/UEA_EVM.sol
index a8ab5c9..98ebd26 100644
--- a/src/UEA/UEA_EVM.sol
+++ b/src/UEA/UEA_EVM.sol
@@ -7,7 +7,7 @@ import {IUEA} from "../Interfaces/IUEA.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {
- UniversalAccount,
+ UniversalAccountId,
UniversalPayload,
DOMAIN_SEPARATOR_TYPEHASH,
UNIVERSAL_PAYLOAD_TYPEHASH
@@ -24,7 +24,7 @@ contract UEA_EVM is ReentrancyGuard, IUEA {
using ECDSA for bytes32;
// @notice The Universal Account information
- UniversalAccount internal id;
+ UniversalAccountId internal id;
// @notice Flag to track initialization status
bool private initialized;
// @notice The nonce for the UEA
@@ -35,7 +35,7 @@ contract UEA_EVM is ReentrancyGuard, IUEA {
/**
* @inheritdoc IUEA
*/
- function initialize(UniversalAccount memory _id) external {
+ function initialize(UniversalAccountId memory _id) external {
if (initialized) {
revert Errors.AlreadyInitialized();
}
@@ -49,13 +49,7 @@ contract UEA_EVM is ReentrancyGuard, IUEA {
* @return bytes32 The domain separator.
*/
function domainSeparator() public view returns (bytes32) {
- uint256 chainId;
- /* solhint-disable no-inline-assembly */
- /// @solidity memory-safe-assembly
- assembly {
- chainId := chainid()
- }
- /* solhint-enable no-inline-assembly */
+ uint256 chainId = id.chainId;
return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, keccak256(bytes(VERSION)), chainId, address(this)));
}
@@ -63,7 +57,7 @@ contract UEA_EVM is ReentrancyGuard, IUEA {
/**
* @inheritdoc IUEA
*/
- function universalAccount() public view returns (UniversalAccount memory) {
+ function universalAccount() public view returns (UniversalAccountId memory) {
return id;
}
diff --git a/src/UEA/UEA_SVM.sol b/src/UEA/UEA_SVM.sol
index 67b124a..7dd7a54 100644
--- a/src/UEA/UEA_SVM.sol
+++ b/src/UEA/UEA_SVM.sol
@@ -5,7 +5,7 @@ import {Errors} from "../libraries/Errors.sol";
import {IUEA} from "../Interfaces/IUEA.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {
- UniversalAccount,
+ UniversalAccountId,
UniversalPayload,
DOMAIN_SEPARATOR_TYPEHASH,
UNIVERSAL_PAYLOAD_TYPEHASH
@@ -20,7 +20,7 @@ import {
contract UEA_SVM is ReentrancyGuard, IUEA {
// @notice The Universal Account information
- UniversalAccount internal id;
+ UniversalAccountId internal id;
// @notice Flag to track initialization status
bool private initialized;
// @notice The nonce for the UEA
@@ -35,13 +35,7 @@ contract UEA_SVM is ReentrancyGuard, IUEA {
* @return bytes32 The domain separator.
*/
function domainSeparator() public view returns (bytes32) {
- uint256 chainId;
- /* solhint-disable no-inline-assembly */
- /// @solidity memory-safe-assembly
- assembly {
- chainId := chainid()
- }
- /* solhint-enable no-inline-assembly */
+ uint256 chainId = id.chainId;
return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, keccak256(bytes(VERSION)), chainId, address(this)));
}
@@ -49,7 +43,7 @@ contract UEA_SVM is ReentrancyGuard, IUEA {
/**
* @inheritdoc IUEA
*/
- function initialize(UniversalAccount memory _id) external {
+ function initialize(UniversalAccountId memory _id) external {
if (initialized) {
revert Errors.AlreadyInitialized();
}
@@ -61,7 +55,7 @@ contract UEA_SVM is ReentrancyGuard, IUEA {
/**
* @inheritdoc IUEA
*/
- function universalAccount() public view returns (UniversalAccount memory) {
+ function universalAccount() public view returns (UniversalAccountId memory) {
return id;
}
diff --git a/src/UEAFactoryV1.sol b/src/UEAFactoryV1.sol
index 8e481e3..912f2c6 100644
--- a/src/UEAFactoryV1.sol
+++ b/src/UEAFactoryV1.sol
@@ -8,25 +8,23 @@ import {Errors} from "./libraries/Errors.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IUEAFactory} from "./Interfaces/IUEAFactory.sol";
-import {UniversalAccount} from "./libraries/Types.sol";
+import {UniversalAccountId} from "./libraries/Types.sol";
/**
* @title UEAFactoryV1
* @dev A factory contract for deploying and managing Universal Executor Accounts (UEA) instances.
*
- * Key Terms:
- * - UEA (Universal Executor Account): Smart contract deployed for external chain users
- * to interact with PUSH chain. Each UEA acts as a proxy for its owner.
- * - UOA (Universal Owner Address): The address of the external chain owner who
- * owns a particular UEA. This key is used for signature verification in UEAs.
- * - VM Types: Different virtual machine environments (EVM, SVM, etc.) that require
- * specific implementation logic. Each chain is registered with its VM type hash, and
- * each VM type hash is mapped to a corresponding UEA implementation contract address.
- * This allows the factory to deploy the correct UEA implementation for different
- * blockchain environments.
- * - Chain identifiers: These follow the CAIP-2 standard (e.g., "eip155:1" for Ethereum mainnet).
- * These standardized chain IDs are used to identify which blockchain an account belongs to.
- * The full identifier is hashed to produce a chainHash value for internal usage.
+ * - UEA (Universal Executor Account) : Smart contract deployed for external chain users to interact with PUSH chain.
+ * Each UEA acts as a proxy for its owner.
+ * - UOA (Universal Owner Address) : The address of the external chain owner who owns a particular UEA.
+ * This key is used for signature verification in UEAs.
+ * - VM Types : Different virtual machine environments (EVM, SVM, etc.) require specific implementation logic.
+ * Each chain is registered with a VM_TYPE_HASH, and each VM_TYPE_HASH is mapped to a corresponding UEA.
+ * This allows the factory to deploy the correct UEA implementation for different blockchain environments.
+ * - Chain identifiers : These follow the CAIP-2 standard (e.g., "eip155:1" for Ethereum mainnet).
+ * The UniversalAccountId struct uses the chainNamespace and chainId for chain identification.
+ * The full identifier is hashed to produce a chainHash value for internal usage.
+ * Note: chainHash = keccak256(abi.encode(_id.chainNamespace, _id.chainId))
*
* The contract uses OZ's Clones library to create deterministic addresses (CREATE2) for UEA instances.
* It keeps track of deployed UEAs and their corresponding user keys from external chains.
@@ -39,11 +37,11 @@ contract UEAFactoryV1 is Initializable, OwnableUpgradeable, IUEAFactory {
/// @notice Maps VM type hashes to their corresponding UEA implementation addresses
mapping(bytes32 => address) public UEA_VM;
- /// @notice Maps UniversalAccount(hash) to their deployed UEA contract addresses
+ /// @notice Maps UniversalAccountId(hash) to their deployed UEA contract addresses
mapping(bytes32 => address) public UOA_to_UEA;
/// @notice Maps UEA addresses to their Universal Account information
- mapping(address => UniversalAccount) private UEA_to_UOA;
+ mapping(address => UniversalAccountId) private UEA_to_UOA;
/// @notice Maps chain identifiers to their registered VM type hashes
mapping(bytes32 => bytes32) public CHAIN_to_VM;
@@ -152,14 +150,14 @@ contract UEAFactoryV1 is Initializable, OwnableUpgradeable, IUEAFactory {
* @notice Will revert if the account already exists, the chain is not registered,
* or if no UEA implementation is available for the chain's VM type
*/
- function deployUEA(UniversalAccount memory _id) external returns (address) {
+ function deployUEA(UniversalAccountId memory _id) external returns (address) {
bytes32 salt = generateSalt(_id);
if (UOA_to_UEA[salt] != address(0)) {
revert Errors.AccountAlreadyExists();
}
// Get the appropriate UEA Implementation based on VM type
- bytes32 chainHash = keccak256(abi.encode(_id.chain));
+ bytes32 chainHash = keccak256(abi.encode(_id.chainNamespace, _id.chainId));
(bytes32 vmHash, bool isRegistered) = getVMType(chainHash);
if (!isRegistered) {
revert Errors.InvalidInputArgs();
@@ -175,7 +173,7 @@ contract UEAFactoryV1 is Initializable, OwnableUpgradeable, IUEAFactory {
UEA_to_UOA[_UEA] = _id; // Store the inverse mapping
IUEA(_UEA).initialize(_id);
- emit UEADeployed(_UEA, _id.owner, chainHash);
+ emit UEADeployed(_UEA, _id.owner, _id.chainId, chainHash);
return _UEA;
}
@@ -186,8 +184,8 @@ contract UEAFactoryV1 is Initializable, OwnableUpgradeable, IUEAFactory {
* @notice Will revert if the chain is not registered or if no UEA implementation
* is available for the chain's VM type
*/
- function computeUEA(UniversalAccount memory _id) public view returns (address) {
- bytes32 chainHash = keccak256(abi.encode(_id.chain));
+ function computeUEA(UniversalAccountId memory _id) public view returns (address) {
+ bytes32 chainHash = keccak256(abi.encode(_id.chainNamespace, _id.chainId));
(bytes32 vmHash, bool isRegistered) = getVMType(chainHash);
if (!isRegistered) {
revert Errors.InvalidInputArgs();
@@ -216,7 +214,7 @@ contract UEAFactoryV1 is Initializable, OwnableUpgradeable, IUEAFactory {
}
/// @inheritdoc IUEAFactory
- function getOriginForUEA(address addr) external view returns (UniversalAccount memory account, bool isUEA) {
+ function getOriginForUEA(address addr) external view returns (UniversalAccountId memory account, bool isUEA) {
account = UEA_to_UOA[addr];
// If the address has no associated Universal Account (owner.length == 0),
@@ -230,8 +228,8 @@ contract UEAFactoryV1 is Initializable, OwnableUpgradeable, IUEAFactory {
}
/// @inheritdoc IUEAFactory
- function getUEAForOrigin(UniversalAccount memory _id) external view returns (address uea, bool isDeployed) {
- // Generate salt from the UniversalAccount struct
+ function getUEAForOrigin(UniversalAccountId memory _id) external view returns (address uea, bool isDeployed) {
+ // Generate salt from the UniversalAccountId struct
bytes32 salt = generateSalt(_id);
// Check if we already have a mapping
@@ -255,7 +253,7 @@ contract UEAFactoryV1 is Initializable, OwnableUpgradeable, IUEAFactory {
* @param _id The Universal Account information
* @return A unique salt derived from the account information
*/
- function generateSalt(UniversalAccount memory _id) public pure returns (bytes32) {
+ function generateSalt(UniversalAccountId memory _id) public pure returns (bytes32) {
return keccak256(abi.encode(_id));
}
}
diff --git a/src/libraries/Types.sol b/src/libraries/Types.sol
index d7e5900..37c40ae 100644
--- a/src/libraries/Types.sol
+++ b/src/libraries/Types.sol
@@ -2,8 +2,9 @@
pragma solidity 0.8.26;
// User Struct
-struct UniversalAccount {
- string chain; // Chain identifier of the owner account (e.g., "eip155:1")
+struct UniversalAccountId {
+ string chainNamespace; // Chain namespace identifier of the owner account (e.g., "eip155" or "solana")
+ uint256 chainId; // Chain ID of the source chain of the owner of this UEA.
bytes owner; // Owner's public key or address in bytes format
}
diff --git a/test/UEAFactory.t.sol b/test/UEAFactory.t.sol
index 540c47c..9939596 100644
--- a/test/UEAFactory.t.sol
+++ b/test/UEAFactory.t.sol
@@ -74,9 +74,9 @@ contract UEAFactoryTest is Test {
solanaChainId = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
solanaAddress = "HGyAQb8SeAE6X6RfhgMpGWZQuVYU8kgA5tKitaTrUHfh";
- // Store chain hashes for reuse
- ethereumChainHash = keccak256(abi.encode("ETHEREUM"));
- solanaChainHash = keccak256(abi.encode("SOLANA"));
+ // Store chain hashes for reuse - now includes both chainNamespace and chainId
+ ethereumChainHash = keccak256(abi.encode("eip155", 1));
+ solanaChainHash = keccak256(abi.encode("solana", 101));
// Register chains
factory.registerNewChain(ethereumChainHash, EVM_HASH);
@@ -88,7 +88,7 @@ contract UEAFactoryTest is Test {
}
function testRegisterNewChain() public {
- bytes32 chainHash = keccak256(abi.encode("KOVAN"));
+ bytes32 chainHash = keccak256(abi.encode("KOVAN", 42));
factory.registerNewChain(chainHash, EVM_HASH);
// Verify the chain was registered
@@ -98,7 +98,7 @@ contract UEAFactoryTest is Test {
}
function testRegisterUEA() public {
- bytes32 chainHash = keccak256(abi.encode("KOVAN"));
+ bytes32 chainHash = keccak256(abi.encode("KOVAN", 42));
factory.registerNewChain(chainHash, EVM_HASH);
factory.registerUEA(chainHash, EVM_HASH, address(ueaEVMImpl));
@@ -112,8 +112,8 @@ contract UEAFactoryTest is Test {
address[] memory implementations = new address[](2);
// Use different chains than those in setUp
- chainHashes[0] = keccak256(abi.encode("KOVAN"));
- chainHashes[1] = keccak256(abi.encode("METIS"));
+ chainHashes[0] = keccak256(abi.encode("KOVAN", 42));
+ chainHashes[1] = keccak256(abi.encode("METIS", 1088));
vmHashes[0] = EVM_HASH;
vmHashes[1] = EVM_HASH;
@@ -134,7 +134,7 @@ contract UEAFactoryTest is Test {
}
function testRevertWhenRegisteringSameChainTwice() public {
- bytes32 chainHash = keccak256(abi.encode("KOVAN"));
+ bytes32 chainHash = keccak256(abi.encode("KOVAN", 42));
factory.registerNewChain(chainHash, EVM_HASH);
// Try to register the same chain again
@@ -143,7 +143,7 @@ contract UEAFactoryTest is Test {
}
function testRevertWhenRegisteringZeroAddressUEA() public {
- bytes32 chainHash = keccak256(abi.encode("KOVAN"));
+ bytes32 chainHash = keccak256(abi.encode("KOVAN", 42));
factory.registerNewChain(chainHash, EVM_HASH);
// Try to register zero address as UEA
@@ -152,7 +152,7 @@ contract UEAFactoryTest is Test {
}
function testRevertWhenRegisteringUEAWithWrongVMHash() public {
- bytes32 chainHash = keccak256(abi.encode("KOVAN"));
+ bytes32 chainHash = keccak256(abi.encode("KOVAN", 42));
factory.registerNewChain(chainHash, EVM_HASH);
// Try to register UEA with wrong VM hash
@@ -161,7 +161,7 @@ contract UEAFactoryTest is Test {
}
function testRevertWhenRegisteringUEAWithUnregisteredChain() public {
- bytes32 chainHash = keccak256(abi.encode("UNREGISTERED"));
+ bytes32 chainHash = keccak256(abi.encode("UNREGISTERED", 999));
// Try to register UEA for unregistered chain
vm.expectRevert(Errors.InvalidInputArgs.selector);
@@ -174,8 +174,8 @@ contract UEAFactoryTest is Test {
address[] memory implementations = new address[](1); // Mismatched length
// Register chains first (use different chains than in setUp)
- chainHashes[0] = keccak256(abi.encode("KOVAN"));
- chainHashes[1] = keccak256(abi.encode("METIS"));
+ chainHashes[0] = keccak256(abi.encode("KOVAN", 42));
+ chainHashes[1] = keccak256(abi.encode("METIS", 1088));
factory.registerNewChain(chainHashes[0], EVM_HASH);
factory.registerNewChain(chainHashes[1], EVM_HASH);
@@ -186,23 +186,24 @@ contract UEAFactoryTest is Test {
}
function testDeployUEA() public {
- // Use ETHEREUM chain which is already registered in setUp
- bytes memory ownerBytes = abi.encodePacked(makeAddr("newowner"));
- UniversalAccount memory _id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ // Use eip155 chain which is already registered in setUp
+ bytes memory newOwnerBytes = abi.encodePacked(makeAddr("newowner"));
+ UniversalAccountId memory _id = UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: newOwnerBytes});
address ueaAddress = factory.deployUEA(_id);
assertTrue(factory.hasCode(ueaAddress));
// Check the owner
- (UniversalAccount memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
- assertEq(keccak256(abi.encode(retrievedAccount.chain)), keccak256(abi.encode(_id.chain)));
+ (UniversalAccountId memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
+ assertEq(keccak256(abi.encode(retrievedAccount.chainNamespace)), keccak256(abi.encode(_id.chainNamespace)));
assertEq(keccak256(retrievedAccount.owner), keccak256(_id.owner));
assertTrue(isUEA);
}
function testRevertWhenDeployingUEAForUnregisteredChain() public {
- bytes memory ownerBytes = abi.encodePacked(makeAddr("owner"));
- UniversalAccount memory _id = UniversalAccount({chain: "UNREGISTERED", owner: ownerBytes});
+ bytes memory testOwnerBytes = abi.encodePacked(makeAddr("owner"));
+ UniversalAccountId memory _id =
+ UniversalAccountId({chainNamespace: "UNREGISTERED", chainId: 999, owner: testOwnerBytes});
// Try to deploy UEA for unregistered chain
vm.expectRevert(Errors.InvalidInputArgs.selector);
@@ -211,11 +212,12 @@ contract UEAFactoryTest is Test {
function testRevertWhenDeployingUEAWithNoImplementation() public {
// Register chain but no implementation
- bytes32 chainHash = keccak256(abi.encode("NEW_CHAIN"));
+ bytes32 chainHash = keccak256(abi.encode("NEW_CHAIN", 888));
factory.registerNewChain(chainHash, MOVE_VM_HASH);
- bytes memory ownerBytes = abi.encodePacked(makeAddr("owner"));
- UniversalAccount memory _id = UniversalAccount({chain: "NEW_CHAIN", owner: ownerBytes});
+ bytes memory testOwnerBytes = abi.encodePacked(makeAddr("owner"));
+ UniversalAccountId memory _id =
+ UniversalAccountId({chainNamespace: "NEW_CHAIN", chainId: 888, owner: testOwnerBytes});
// Try to deploy UEA with no implementation
vm.expectRevert(Errors.InvalidInputArgs.selector);
@@ -223,9 +225,10 @@ contract UEAFactoryTest is Test {
}
function testRevertWhenDeployingSameUEATwice() public {
- // Use a new owner with ETHEREUM chain
- bytes memory ownerBytes = abi.encodePacked(makeAddr("uniqueowner"));
- UniversalAccount memory _id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ // Use a new owner with eip155 chain
+ bytes memory uniqueOwnerBytes = abi.encodePacked(makeAddr("uniqueowner"));
+ UniversalAccountId memory _id =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: uniqueOwnerBytes});
factory.deployUEA(_id);
@@ -235,9 +238,10 @@ contract UEAFactoryTest is Test {
}
function testComputeUEA() public {
- // Use ETHEREUM chain which is already registered in setUp
- bytes memory ownerBytes = abi.encodePacked(makeAddr("uniquecomputeowner"));
- UniversalAccount memory _id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ // Use eip155 chain which is already registered in setUp
+ bytes memory uniqueComputeOwnerBytes = abi.encodePacked(makeAddr("uniquecomputeowner"));
+ UniversalAccountId memory _id =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: uniqueComputeOwnerBytes});
address computedAddress = factory.computeUEA(_id);
assertTrue(computedAddress != address(0));
@@ -248,9 +252,10 @@ contract UEAFactoryTest is Test {
}
function testGetUEAForOrigin() public {
- // Use ETHEREUM chain which is already registered in setUp
- bytes memory ownerBytes = abi.encodePacked(makeAddr("uniquegetowner"));
- UniversalAccount memory _id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ // Use eip155 chain which is already registered in setUp
+ bytes memory uniqueGetOwnerBytes = abi.encodePacked(makeAddr("uniquegetowner"));
+ UniversalAccountId memory _id =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: uniqueGetOwnerBytes});
// Test for non-deployed UEA
(address uea, bool isDeployed) = factory.getUEAForOrigin(_id);
@@ -267,7 +272,7 @@ contract UEAFactoryTest is Test {
}
function testSwapImplementation() public {
- // Use ETHEREUM chain which is already registered in setUp
+ // Use eip155 chain which is already registered in setUp
address initialImpl = factory.getUEA(ethereumChainHash);
// Deploy a new implementation
@@ -280,15 +285,17 @@ contract UEAFactoryTest is Test {
}
function testMultipleOwners() public {
- // Create two different owners for ETHEREUM chain
+ // Create two different owners for eip155 chain
(address owner1, uint256 owner1PK) = makeAddrAndKey("owner1");
(address owner2, uint256 owner2PK) = makeAddrAndKey("owner2");
bytes memory ownerBytes1 = abi.encodePacked(owner1);
bytes memory ownerBytes2 = abi.encodePacked(owner2);
- UniversalAccount memory account1 = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes1});
- UniversalAccount memory account2 = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes2});
+ UniversalAccountId memory account1 =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes1});
+ UniversalAccountId memory account2 =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes2});
// Compute UEA addresses
address computedUEA1 = factory.computeUEA(account1);
@@ -299,45 +306,50 @@ contract UEAFactoryTest is Test {
}
function testMultipleDeployments() public {
- // Deploy 10 UEAs for ETHEREUM chain
+ // Deploy 10 UEAs for eip155 chain
for (uint256 i = 0; i < 10; i++) {
(address testOwner, uint256 testOwnerPK) = makeAddrAndKey(string(abi.encodePacked("testOwner", i)));
- bytes memory ownerBytes = abi.encodePacked(testOwner);
- UniversalAccount memory _id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ bytes memory testOwnerBytes = abi.encodePacked(testOwner);
+ UniversalAccountId memory _id =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: testOwnerBytes});
address ueaAddress = factory.deployUEA(_id);
assertTrue(factory.hasCode(ueaAddress));
- (UniversalAccount memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
- assertEq(keccak256(retrievedAccount.owner), keccak256(ownerBytes));
+ (UniversalAccountId memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
+ assertEq(keccak256(retrievedAccount.owner), keccak256(testOwnerBytes));
assertTrue(isUEA);
}
}
function testUEAOwnerChange() public {
- // Deploy UEA for original owner on ETHEREUM chain
- bytes memory ownerBytes = abi.encodePacked(makeAddr("originalOwner"));
- UniversalAccount memory _id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ // Deploy UEA for original owner on eip155 chain
+ bytes memory originalOwnerBytes = abi.encodePacked(makeAddr("originalOwner"));
+ UniversalAccountId memory _id =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: originalOwnerBytes});
address ueaAddress = factory.deployUEA(_id);
// Create a new owner
(address newOwner, uint256 newOwnerPK) = makeAddrAndKey("newOwner");
bytes memory newOwnerBytes = abi.encodePacked(newOwner);
- UniversalAccount memory newAccount = UniversalAccount({chain: "ETHEREUM", owner: newOwnerBytes});
+ UniversalAccountId memory newAccount =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: newOwnerBytes});
// The owner mapping can't be changed - a new UEA would need to be deployed
- (UniversalAccount memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
- assertEq(keccak256(retrievedAccount.owner), keccak256(ownerBytes));
- assertEq(keccak256(abi.encode(retrievedAccount.chain)), keccak256(abi.encode(_id.chain)));
+ (UniversalAccountId memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
+ assertEq(keccak256(retrievedAccount.owner), keccak256(originalOwnerBytes));
+ assertEq(keccak256(abi.encode(retrievedAccount.chainNamespace)), keccak256(abi.encode(_id.chainNamespace)));
assertTrue(isUEA);
// Deploy UEA for new owner - this should be a different address
address newUEAAddress = factory.deployUEA(newAccount);
assertNotEq(ueaAddress, newUEAAddress);
- (UniversalAccount memory newRetrievedAccount, bool isNewUEA) = factory.getOriginForUEA(newUEAAddress);
+ (UniversalAccountId memory newRetrievedAccount, bool isNewUEA) = factory.getOriginForUEA(newUEAAddress);
assertEq(keccak256(newRetrievedAccount.owner), keccak256(newOwnerBytes));
- assertEq(keccak256(abi.encode(newRetrievedAccount.chain)), keccak256(abi.encode(newAccount.chain)));
+ assertEq(
+ keccak256(abi.encode(newRetrievedAccount.chainNamespace)), keccak256(abi.encode(newAccount.chainNamespace))
+ );
assertTrue(isNewUEA);
}
@@ -346,7 +358,7 @@ contract UEAFactoryTest is Test {
vm.prank(nonOwner);
vm.expectRevert(abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, nonOwner));
- bytes32 chainHash = keccak256(abi.encode("APTOS"));
+ bytes32 chainHash = keccak256(abi.encode("APTOS", 1));
factory.registerNewChain(chainHash, MOVE_VM_HASH);
// Test that owner can register implementations
@@ -360,7 +372,7 @@ contract UEAFactoryTest is Test {
}
function testDeploymentCreate2() public {
- UniversalAccount memory _id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ UniversalAccountId memory _id = UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes});
address ueaAddress = factory.deployUEA(_id);
bytes32 salt = factory.generateSalt(_id);
@@ -369,7 +381,7 @@ contract UEAFactoryTest is Test {
}
function testComputeUEAAddressNonEVM() public {
- UniversalAccount memory _id = UniversalAccount({chain: "SOLANA", owner: ownerNonEVM});
+ UniversalAccountId memory _id = UniversalAccountId({chainNamespace: "solana", chainId: 101, owner: ownerNonEVM});
address ueaAddress = factory.deployUEA(_id);
address computedAddress = factory.computeUEA(_id);
@@ -381,11 +393,11 @@ contract UEAFactoryTest is Test {
}
function testMissingImplementation() public {
- bytes32 moveChainHash = keccak256(abi.encode("APTOS"));
+ bytes32 moveChainHash = keccak256(abi.encode("APTOS", 1));
factory.registerNewChain(moveChainHash, MOVE_VM_HASH);
- // Create an UniversalAccount with VM type that has no implementation
- UniversalAccount memory _id = UniversalAccount({chain: "APTOS", owner: ownerBytes});
+ // Create an UniversalAccountId with VM type that has no implementation
+ UniversalAccountId memory _id = UniversalAccountId({chainNamespace: "APTOS", chainId: 1, owner: ownerBytes});
// Try to deploy with missing implementation
vm.expectRevert(Errors.InvalidInputArgs.selector);
@@ -394,14 +406,14 @@ contract UEAFactoryTest is Test {
function testMultipleChainsSameVM() public {
// Register two different chains with the same VM type (EVM)
- bytes32 ethereumChainHash = keccak256(abi.encode("ETHEREUM"));
- bytes32 polygonChainHash = keccak256(abi.encode("POLYGON"));
+ bytes32 ethereumChainHashLocal = keccak256(abi.encode("eip155", 1));
+ bytes32 polygonChainHash = keccak256(abi.encode("POLYGON", 137));
// Polygon is not registered yet
factory.registerNewChain(polygonChainHash, EVM_HASH);
// We already registered EVM implementation for Ethereum, should work for Polygon too
- (bytes32 vmHashEth, bool isRegisteredEth) = factory.getVMType(ethereumChainHash);
+ (bytes32 vmHashEth, bool isRegisteredEth) = factory.getVMType(ethereumChainHashLocal);
(bytes32 vmHashPoly, bool isRegisteredPoly) = factory.getVMType(polygonChainHash);
// Verify both chains use the same VM type
@@ -410,12 +422,14 @@ contract UEAFactoryTest is Test {
assertTrue(isRegisteredPoly);
// Both chains should use the same implementation
- assertEq(factory.getUEA(ethereumChainHash), factory.getUEA(polygonChainHash));
+ assertEq(factory.getUEA(ethereumChainHashLocal), factory.getUEA(polygonChainHash));
// Deploy UEAs for both chains and verify they have different addresses despite same VM
- UniversalAccount memory ethAccount = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ UniversalAccountId memory ethAccount =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes});
- UniversalAccount memory polyAccount = UniversalAccount({chain: "POLYGON", owner: ownerBytes});
+ UniversalAccountId memory polyAccount =
+ UniversalAccountId({chainNamespace: "POLYGON", chainId: 137, owner: ownerBytes});
address ethUEA = factory.deployUEA(ethAccount);
@@ -440,7 +454,7 @@ contract UEAFactoryTest is Test {
assertEq(factory.owner(), newOwner);
// Try to register a chain with old owner, should fail
- bytes32 chainHash = keccak256(abi.encode("TestChain"));
+ bytes32 chainHash = keccak256(abi.encode("TestChain", 123));
vm.expectRevert(abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, address(this)));
factory.registerNewChain(chainHash, MOVE_VM_HASH);
@@ -466,13 +480,13 @@ contract UEAFactoryTest is Test {
// Register multiple chains
string[] memory chains = new string[](3);
- chains[0] = "ETHEREUM"; // Ethereum
+ chains[0] = "eip155"; // Ethereum
chains[1] = "POLYGON"; // Polygon
chains[2] = "BSC"; // BSC
// Register chains that aren't already registered
for (uint256 i = 1; i < 3; i++) {
- bytes32 chainHash = keccak256(abi.encode(chains[i]));
+ bytes32 chainHash = keccak256(abi.encode(chains[i], i == 1 ? 137 : 56)); // Polygon (137) and BSC (56)
// Check if chain is already registered
(, bool isRegistered) = factory.getVMType(chainHash);
if (!isRegistered) {
@@ -484,23 +498,28 @@ contract UEAFactoryTest is Test {
address[] memory deployedUEAs = new address[](5);
for (uint256 i = 0; i < 5; i++) {
string memory chain = chains[i % 3]; // Cycle through chains
+ uint256 chainId = i % 3 == 0 ? 1 : (i % 3 == 1 ? 137 : 56); // Ethereum, Polygon, BSC chain IDs
- UniversalAccount memory account = UniversalAccount({chain: chain, owner: ownerValues[i]});
+ UniversalAccountId memory account =
+ UniversalAccountId({chainNamespace: chain, chainId: chainId, owner: ownerValues[i]});
bytes32 salt = factory.generateSalt(account);
deployedUEAs[i] = factory.deployUEA(account);
// Verify mappings are consistent
assertEq(factory.UOA_to_UEA(salt), deployedUEAs[i]);
- (UniversalAccount memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(deployedUEAs[i]);
+ (UniversalAccountId memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(deployedUEAs[i]);
assertEq(keccak256(retrievedAccount.owner), keccak256(ownerValues[i]));
- assertEq(keccak256(abi.encode(retrievedAccount.chain)), keccak256(abi.encode(chain)));
+ assertEq(keccak256(abi.encode(retrievedAccount.chainNamespace)), keccak256(abi.encode(chain)));
assertTrue(isUEA);
}
// Verify all deployed accounts are retrievable
for (uint256 i = 0; i < 5; i++) {
- UniversalAccount memory account = UniversalAccount({chain: chains[i % 3], owner: ownerValues[i]});
+ string memory chain = chains[i % 3];
+ uint256 chainId = i % 3 == 0 ? 1 : (i % 3 == 1 ? 137 : 56); // Ethereum, Polygon, BSC chain IDs
+ UniversalAccountId memory account =
+ UniversalAccountId({chainNamespace: chain, chainId: chainId, owner: ownerValues[i]});
bytes32 salt = factory.generateSalt(account);
assertEq(factory.UOA_to_UEA(salt), deployedUEAs[i]);
}
@@ -508,11 +527,12 @@ contract UEAFactoryTest is Test {
function testChainConfigChanges() public {
// Create a new chain and register it
- bytes32 chainHash = keccak256(abi.encode("KOVAN"));
+ bytes32 chainHash = keccak256(abi.encode("KOVAN", 42));
factory.registerNewChain(chainHash, EVM_HASH);
// Deploy an account with the initial implementation
- UniversalAccount memory account = UniversalAccount({chain: "KOVAN", owner: ownerBytes});
+ UniversalAccountId memory account =
+ UniversalAccountId({chainNamespace: "KOVAN", chainId: 42, owner: ownerBytes});
// Get initial implementation address
address initialImpl = factory.getUEA(chainHash);
@@ -524,7 +544,7 @@ contract UEAFactoryTest is Test {
UEA_EVM newImpl = new UEA_EVM();
// Change implementation for EVM type
- bytes32 evmChainHash = keccak256(abi.encode("ETHEREUM"));
+ bytes32 evmChainHash = keccak256(abi.encode("eip155", 1));
factory.registerUEA(evmChainHash, EVM_HASH, address(newImpl));
// Verify implementation has changed
@@ -535,7 +555,8 @@ contract UEAFactoryTest is Test {
(address owner2, uint256 owner2PK) = makeAddrAndKey("owner2");
bytes memory owner2Key = abi.encodePacked(owner2);
- UniversalAccount memory account2 = UniversalAccount({chain: "KOVAN", owner: owner2Key});
+ UniversalAccountId memory account2 =
+ UniversalAccountId({chainNamespace: "KOVAN", chainId: 42, owner: owner2Key});
// Compute address with new implementation
address newUEAAddress = factory.computeUEA(account2);
@@ -546,14 +567,15 @@ contract UEAFactoryTest is Test {
function testMappingConsistency() public {
// Deploy a UEA
- UniversalAccount memory account = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ UniversalAccountId memory account =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes});
address ueaAddress = factory.deployUEA(account);
// Test getOriginForUEA
- (UniversalAccount memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
+ (UniversalAccountId memory retrievedAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
assertEq(keccak256(retrievedAccount.owner), keccak256(ownerBytes));
- assertEq(keccak256(abi.encode(retrievedAccount.chain)), keccak256(abi.encode(account.chain)));
+ assertEq(keccak256(abi.encode(retrievedAccount.chainNamespace)), keccak256(abi.encode(account.chainNamespace)));
assertTrue(isUEA);
// Test getUEAForOrigin
@@ -563,16 +585,17 @@ contract UEAFactoryTest is Test {
// Test with non-existent UEA
address randomAddr = makeAddr("random");
- (UniversalAccount memory randomAccount, bool isRandomUEA) = factory.getOriginForUEA(randomAddr);
+ (UniversalAccountId memory randomAccount, bool isRandomUEA) = factory.getOriginForUEA(randomAddr);
assertFalse(isRandomUEA);
assertEq(randomAccount.owner.length, 0);
- assertEq(bytes(randomAccount.chain).length, 0);
+ assertEq(bytes(randomAccount.chainNamespace).length, 0);
// Test with non-existent owner key but predictable address
(address newOwner, uint256 newOwnerPK) = makeAddrAndKey("newOwner");
bytes memory newOwnerKey = abi.encodePacked(newOwner);
- UniversalAccount memory newAccount = UniversalAccount({chain: "ETHEREUM", owner: newOwnerKey});
+ UniversalAccountId memory newAccount =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: newOwnerKey});
// Compute without deploying
address computedAddress = factory.computeUEA(newAccount);
@@ -591,7 +614,8 @@ contract UEAFactoryTest is Test {
assertFalse(factory.hasCode(address(0x123)));
// Newly deployed UEA should have code
- UniversalAccount memory account = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ UniversalAccountId memory account =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes});
address ueaAddress = factory.deployUEA(account);
assertTrue(factory.hasCode(ueaAddress));
@@ -603,8 +627,10 @@ contract UEAFactoryTest is Test {
bytes memory owner2Key = abi.encodePacked(makeAddr("owner2"));
// Create accounts for the same chain but different owners
- UniversalAccount memory account1 = UniversalAccount({chain: "ETHEREUM", owner: owner1Key});
- UniversalAccount memory account2 = UniversalAccount({chain: "ETHEREUM", owner: owner2Key});
+ UniversalAccountId memory account1 =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: owner1Key});
+ UniversalAccountId memory account2 =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: owner2Key});
// Deploy both UEAs
address uea1 = factory.deployUEA(account1);
@@ -614,8 +640,8 @@ contract UEAFactoryTest is Test {
assertTrue(uea1 != uea2);
// Verify the owner keys are mapped correctly
- (UniversalAccount memory retrievedAccount1, bool isUEA1) = factory.getOriginForUEA(uea1);
- (UniversalAccount memory retrievedAccount2, bool isUEA2) = factory.getOriginForUEA(uea2);
+ (UniversalAccountId memory retrievedAccount1, bool isUEA1) = factory.getOriginForUEA(uea1);
+ (UniversalAccountId memory retrievedAccount2, bool isUEA2) = factory.getOriginForUEA(uea2);
assertEq(keccak256(retrievedAccount1.owner), keccak256(owner1Key));
assertEq(keccak256(retrievedAccount2.owner), keccak256(owner2Key));
@@ -629,37 +655,38 @@ contract UEAFactoryTest is Test {
address randomAddr = makeAddr("randomNative");
// Check if it's correctly identified as a native account
- (UniversalAccount memory account, bool isUEA) = factory.getOriginForUEA(randomAddr);
+ (UniversalAccountId memory account, bool isUEA) = factory.getOriginForUEA(randomAddr);
assertFalse(isUEA);
// For native accounts, both owner and chain should be empty
assertEq(account.owner.length, 0);
- assertEq(bytes(account.chain).length, 0);
+ assertEq(bytes(account.chainNamespace).length, 0);
}
// Test for comparing native and UEA accounts
function testCompareNativeAndUEAAccounts() public {
// Create and deploy a UEA
- bytes memory ownerBytes = abi.encodePacked(makeAddr("uea_owner"));
- UniversalAccount memory uea_id = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ bytes memory ueaOwnerBytes = abi.encodePacked(makeAddr("uea_owner"));
+ UniversalAccountId memory uea_id =
+ UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ueaOwnerBytes});
address ueaAddress = factory.deployUEA(uea_id);
// Create a random native address
address nativeAddr = makeAddr("native_user");
// Get account info for both
- (UniversalAccount memory ueaAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
- (UniversalAccount memory nativeAccount, bool isNativeUEA) = factory.getOriginForUEA(nativeAddr);
+ (UniversalAccountId memory ueaAccount, bool isUEA) = factory.getOriginForUEA(ueaAddress);
+ (UniversalAccountId memory nativeAccount, bool isNativeUEA) = factory.getOriginForUEA(nativeAddr);
// UEA should have proper data and be a UEA
assertTrue(isUEA);
- assertEq(keccak256(ueaAccount.owner), keccak256(ownerBytes));
- assertEq(keccak256(abi.encode(ueaAccount.chain)), keccak256(abi.encode("ETHEREUM")));
+ assertEq(keccak256(ueaAccount.owner), keccak256(ueaOwnerBytes));
+ assertEq(keccak256(abi.encode(ueaAccount.chainNamespace)), keccak256(abi.encode("eip155")));
// Native account should be marked as not a UEA and have empty data
assertFalse(isNativeUEA);
assertEq(nativeAccount.owner.length, 0);
- assertEq(bytes(nativeAccount.chain).length, 0);
+ assertEq(bytes(nativeAccount.chainNamespace).length, 0);
}
// Test for multiple native accounts all returning empty data
@@ -672,11 +699,11 @@ contract UEAFactoryTest is Test {
// Check all addresses are correctly identified as native with empty data
for (uint256 i = 0; i < nativeAddrs.length; i++) {
- (UniversalAccount memory account, bool isUEA) = factory.getOriginForUEA(nativeAddrs[i]);
+ (UniversalAccountId memory account, bool isUEA) = factory.getOriginForUEA(nativeAddrs[i]);
assertFalse(isUEA);
assertEq(account.owner.length, 0);
- assertEq(bytes(account.chain).length, 0);
+ assertEq(bytes(account.chainNamespace).length, 0);
}
}
}
diff --git a/test/UEA_EVM.t.sol b/test/UEA_EVM.t.sol
index 4835609..ed2bdee 100644
--- a/test/UEA_EVM.t.sol
+++ b/test/UEA_EVM.t.sol
@@ -43,13 +43,13 @@ contract UEA_EVMTest is Test {
ownerBytes = abi.encodePacked(owner);
// Register EVM chain and implementation
- bytes32 evmChainHash = keccak256(abi.encode("ETHEREUM"));
+ bytes32 evmChainHash = keccak256(abi.encode("eip155", 1));
factory.registerNewChain(evmChainHash, EVM_HASH);
factory.registerUEA(evmChainHash, EVM_HASH, address(ueaEVMImpl));
}
modifier deployEvmSmartAccount() {
- UniversalAccount memory _owner = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ UniversalAccountId memory _owner = UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes});
address smartAccountAddress = factory.deployUEA(_owner);
evmSmartAccountInstance = UEA_EVM(payable(smartAccountAddress));
@@ -57,18 +57,18 @@ contract UEA_EVMTest is Test {
}
function testUEAImplementation() public view {
- bytes32 evmChainHash = keccak256(abi.encode("ETHEREUM"));
+ bytes32 evmChainHash = keccak256(abi.encode("eip155", 1));
assertEq(address(factory.getUEA(evmChainHash)), address(ueaEVMImpl));
}
function testUniversalAccount() public deployEvmSmartAccount {
- UniversalAccount memory account = evmSmartAccountInstance.universalAccount();
- assertEq(account.chain, "ETHEREUM");
+ UniversalAccountId memory account = evmSmartAccountInstance.universalAccount();
+ assertEq(account.chainNamespace, "eip155");
assertEq(account.owner, ownerBytes);
}
function testDeploymentCreate2() public deployEvmSmartAccount {
- UniversalAccount memory _owner = UniversalAccount({chain: "ETHEREUM", owner: ownerBytes});
+ UniversalAccountId memory _owner = UniversalAccountId({chainNamespace: "eip155", chainId: 1, owner: ownerBytes});
bytes32 salt = factory.generateSalt(_owner);
assertEq(address(evmSmartAccountInstance), address(factory.UOA_to_UEA(salt)));
assertEq(address(evmSmartAccountInstance), address(factory.computeUEA(_owner)));
diff --git a/test/UEA_SVM.t.sol b/test/UEA_SVM.t.sol
index 0a563a7..f856162 100644
--- a/test/UEA_SVM.t.sol
+++ b/test/UEA_SVM.t.sol
@@ -40,13 +40,14 @@ contract UEA_SVMTest is Test {
svmSmartAccountImpl = new UEA_SVM();
// Register SVM chain and implementation
- bytes32 svmChainHash = keccak256(abi.encode("SOLANA"));
+ bytes32 svmChainHash = keccak256(abi.encode("solana", 101));
factory.registerNewChain(svmChainHash, SVM_HASH);
factory.registerUEA(svmChainHash, SVM_HASH, address(svmSmartAccountImpl));
}
modifier deploySvmSmartAccount() {
- UniversalAccount memory _owner = UniversalAccount({chain: "SOLANA", owner: ownerBytes});
+ UniversalAccountId memory _owner =
+ UniversalAccountId({chainNamespace: "solana", chainId: 101, owner: ownerBytes});
address smartAccountAddress = factory.deployUEA(_owner);
svmSmartAccountInstance = UEA_SVM(payable(smartAccountAddress));
@@ -54,7 +55,7 @@ contract UEA_SVMTest is Test {
}
function testRegisterChain() public view {
- bytes32 svmChainHash = keccak256(abi.encode("SOLANA"));
+ bytes32 svmChainHash = keccak256(abi.encode("solana", 101));
(bytes32 vmHash, bool isRegistered) = factory.getVMType(svmChainHash);
assertEq(vmHash, SVM_HASH);
assertTrue(isRegistered);
@@ -65,8 +66,8 @@ contract UEA_SVMTest is Test {
}
function testUniversalAccount() public deploySvmSmartAccount {
- UniversalAccount memory account = svmSmartAccountInstance.universalAccount();
- assertEq(account.chain, "SOLANA");
+ UniversalAccountId memory account = svmSmartAccountInstance.universalAccount();
+ assertEq(account.chainNamespace, "solana");
assertEq(account.owner, ownerBytes);
}
diff --git a/test/coverage/src/UEA/UEA_EVM.sol.gcov.html b/test/coverage/src/UEA/UEA_EVM.sol.gcov.html
index d471052..c179c1e 100644
--- a/test/coverage/src/UEA/UEA_EVM.sol.gcov.html
+++ b/test/coverage/src/UEA/UEA_EVM.sol.gcov.html
@@ -78,7 +78,7 @@
7 : : import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
8 : : import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
9 : : import {
- 10 : : UniversalAccount,
+ 10 : : UniversalAccountId,
11 : : UniversalPayload,
12 : : DOMAIN_SEPARATOR_TYPEHASH,
13 : : UNIVERSAL_PAYLOAD_TYPEHASH
@@ -95,7 +95,7 @@
24 : : using ECDSA for bytes32;
25 : :
26 : : // @notice The Universal Account information
- 27 : : UniversalAccount internal id;
+ 27 : : UniversalAccountId internal id;
28 : : // @notice Flag to track initialization status
29 : : bool private initialized;
30 : : // @notice The nonce for the UEA
@@ -106,7 +106,7 @@
35 : : /**
36 : : * @inheritdoc IUEA
37 : : */
- 38 : 38 : function initialize(UniversalAccount memory _id) external {
+ 38 : 38 : function initialize(UniversalAccountId memory _id) external {
39 [ # ]: 0 : if (initialized) {
40 : 0 : revert Errors.AlreadyInitialized();
41 : : }
@@ -134,7 +134,7 @@
63 : : /**
64 : : * @inheritdoc IUEA
65 : : */
- 66 : 1 : function universalAccount() public view returns (UniversalAccount memory) {
+ 66 : 1 : function universalAccount() public view returns (UniversalAccountId memory) {
67 : 1 : return id;
68 : : }
69 : :
diff --git a/test/coverage/src/UEA/UEA_SVM.sol.gcov.html b/test/coverage/src/UEA/UEA_SVM.sol.gcov.html
index df27ec7..d2770c4 100644
--- a/test/coverage/src/UEA/UEA_SVM.sol.gcov.html
+++ b/test/coverage/src/UEA/UEA_SVM.sol.gcov.html
@@ -76,7 +76,7 @@
5 : : import {IUEA} from "../Interfaces/IUEA.sol";
6 : : import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
7 : : import {
- 8 : : UniversalAccount,
+ 8 : : UniversalAccountId,
9 : : UniversalPayload,
10 : : DOMAIN_SEPARATOR_TYPEHASH,
11 : : UNIVERSAL_PAYLOAD_TYPEHASH
@@ -91,7 +91,7 @@
20 : :
21 : : contract UEA_SVM is ReentrancyGuard, IUEA {
22 : : // @notice The Universal Account information
- 23 : : UniversalAccount internal id;
+ 23 : : UniversalAccountId internal id;
24 : : // @notice Flag to track initialization status
25 : : bool private initialized;
26 : : // @notice The nonce for the UEA
@@ -120,7 +120,7 @@
49 : : /**
50 : : * @inheritdoc IUEA
51 : : */
- 52 : 7 : function initialize(UniversalAccount memory _id) external {
+ 52 : 7 : function initialize(UniversalAccountId memory _id) external {
53 [ # ]: 0 : if (initialized) {
54 : 0 : revert Errors.AlreadyInitialized();
55 : : }
@@ -132,7 +132,7 @@
61 : : /**
62 : : * @inheritdoc IUEA
63 : : */
- 64 : 1 : function universalAccount() public view returns (UniversalAccount memory) {
+ 64 : 1 : function universalAccount() public view returns (UniversalAccountId memory) {
65 : 1 : return id;
66 : : }
67 : :
diff --git a/test/coverage/src/UEAFactoryV1.sol.gcov.html b/test/coverage/src/UEAFactoryV1.sol.gcov.html
index 327f2f4..862331e 100644
--- a/test/coverage/src/UEAFactoryV1.sol.gcov.html
+++ b/test/coverage/src/UEAFactoryV1.sol.gcov.html
@@ -79,7 +79,7 @@
8 : : import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
9 : : import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
10 : : import {IUEAFactory} from "./Interfaces/IUEAFactory.sol";
- 11 : : import {UniversalAccount} from "./libraries/Types.sol";
+ 11 : : import {UniversalAccountId} from "./libraries/Types.sol";
12 : :
13 : : /**
14 : : * @title UEAFactoryV1
@@ -110,11 +110,11 @@
39 : : /// @notice Maps VM type hashes to their corresponding UEA implementation addresses
40 : : mapping(bytes32 => address) public UEA_VM;
41 : :
- 42 : : /// @notice Maps UniversalAccount(hash) to their deployed UEA contract addresses
+ 42 : : /// @notice Maps UniversalAccountId(hash) to their deployed UEA contract addresses
43 : : mapping(bytes32 => address) public UOA_to_UEA;
44 : :
45 : : /// @notice Maps UEA addresses to their Universal Account information
- 46 : : mapping(address => UniversalAccount) private UEA_to_UOA;
+ 46 : : mapping(address => UniversalAccountId) private UEA_to_UOA;
47 : :
48 : : /// @notice Maps chain identifiers to their registered VM type hashes
49 : : mapping(bytes32 => bytes32) public CHAIN_to_VM;
@@ -223,7 +223,7 @@
152 : : * @notice Will revert if the account already exists, the chain is not registered,
153 : : * or if no UEA implementation is available for the chain's VM type
154 : : */
- 155 : 49 : function deployUEA(UniversalAccount memory _id) external returns (address) {
+ 155 : 49 : function deployUEA(UniversalAccountId memory _id) external returns (address) {
156 : 49 : bytes32 salt = generateSalt(_id);
157 [ + ]: 49 : if (UOA_to_UEA[salt] != address(0)) {
158 : 1 : revert Errors.AccountAlreadyExists();
@@ -257,7 +257,7 @@
186 : : * @notice Will revert if the chain is not registered or if no UEA implementation
187 : : * is available for the chain's VM type
188 : : */
- 189 : 8 : function computeUEA(UniversalAccount memory _id) public view returns (address) {
+ 189 : 8 : function computeUEA(UniversalAccountId memory _id) public view returns (address) {
190 : 10 : bytes32 chainHash = keccak256(abi.encode(_id.chain));
191 : 10 : (bytes32 vmHash, bool isRegistered) = getVMType(chainHash);
192 [ # ]: 10 : if (!isRegistered) {
@@ -287,7 +287,7 @@
216 : : }
217 : :
218 : : /// @inheritdoc IUEAFactory
- 219 : 28 : function getOriginForUEA(address addr) external view returns (UniversalAccount memory account, bool isUEA) {
+ 219 : 28 : function getOriginForUEA(address addr) external view returns (UniversalAccountId memory account, bool isUEA) {
220 : 28 : account = UEA_to_UOA[addr];
221 : :
222 : : // If the address has no associated Universal Account (owner.length == 0),
@@ -301,8 +301,8 @@
230 : : }
231 : :
232 : : /// @inheritdoc IUEAFactory
- 233 : 4 : function getUEAForOrigin(UniversalAccount memory _id) external view returns (address uea, bool isDeployed) {
- 234 : : // Generate salt from the UniversalAccount struct
+ 233 : 4 : function getUEAForOrigin(UniversalAccountId memory _id) external view returns (address uea, bool isDeployed) {
+ 234 : : // Generate salt from the UniversalAccountId struct
235 : 4 : bytes32 salt = generateSalt(_id);
236 : :
237 : : // Check if we already have a mapping
@@ -326,7 +326,7 @@
255 : : * @param _id The Universal Account information
256 : : * @return A unique salt derived from the account information
257 : : */
- 258 : 12 : function generateSalt(UniversalAccount memory _id) public pure returns (bytes32) {
+ 258 : 12 : function generateSalt(UniversalAccountId memory _id) public pure returns (bytes32) {
259 : 75 : return keccak256(abi.encode(_id));
260 : : }
261 : : }