User Proxy Factory
UserProxyFactoryV4 deploys one UserProxyV4 clone for each user. It uses OpenZeppelin’s EIP-1167
minimal-clone pattern and CREATE2, so a client can compute a user’s proxy address before the
proxy exists.
The factory is ownerless. Its implementation is immutable and created in the constructor. The
factory stores only the proxyOf mapping; it has no administrator, pause switch, or upgrade path.
Predict the address
Section titled “Predict the address”Call predictProxy(user) with the user’s address. The factory derives the deterministic salt as:
keccak256(abi.encode("AgentSwap.UserProxy.v4", user))The result is the address produced by the factory’s deterministic clone deployment for that user. It can be pinned in client state or approvals before a deployment transaction is sent.
The prediction is tied to the canonical factory, its immutable implementation, and the user address. A client should derive the address from the factory rather than accept an arbitrary proxy address.
Deploy a proxy
Section titled “Deploy a proxy”Call deploy(user) from any account. The factory:
- Rejects
user == address(0)withZeroAddress. - Reads
proxyOf[user]. - If an address is already stored, returns it without deploying another clone.
- Otherwise deploys the deterministic clone, calls
init(user), stores the result, emitsProxyDeployed, and returns the proxy address.
The caller does not become the owner. init(user) sets the proxy owner to user, and the factory
calls it during deployment. The proxy rejects a second initialization with AlreadyInitialized.
Idempotence
Section titled “Idempotence”deploy(user) is idempotent after the first successful deployment. Repeated calls for the same
user return the address in proxyOf[user] and do not deploy or initialize a second proxy. The
address returned by predictProxy(user) is therefore the address clients should expect from
deploy(user) for the canonical factory.
Deployment surface
Section titled “Deployment surface”| Function | Purpose |
|---|---|
predictProxy(address user) |
Return the deterministic proxy address without deploying. |
deploy(address user) |
Deploy and initialize the user’s clone, or return the stored address. |
implementation() |
Return the immutable UserProxyV4 implementation address. |
proxyOf(address user) |
Read the stored proxy address for a user. |
The proxy’s init(address) entry point is called as part of deployment. It is not a second factory
deployment mechanism.
Successful first deployment emits:
ProxyDeployed(address indexed user, address indexed proxy)There is no factory owner to transfer, renounce, or use to change routing policy. Agent policy is stored in each proxy and is controlled by that proxy’s owner. See agent delegation.
Supported deployments
Section titled “Supported deployments”The verified User Proxy deployment is documented for Base 8453, Arbitrum One 42161, and Robinhood Chain 4663. It is not a deployment on BNB Smart Chain 56. That chain distinction is specific to the User Proxy; the Intents address table is a separate reference and must not be copied here.
See proxy addresses and ABI for the deployment addresses and selectors.
Client sequence
Section titled “Client sequence”A client can call predictProxy(user) first, use that address for the user’s proxy setup, and
call deploy(user) when the clone should exist. It can then read proxyOf(user) to confirm the
factory’s stored mapping. The factory does not require the caller to be the user.