PRBProxy is a proxy contract that allows for the composition of Ethereum transactions on behalf of the contract owner, acting as a smart wallet that enables multiple contract calls within a single transaction. In Ethereum, externally owned accounts (EOAs) do not have this functionality; they are limited to interacting with only one contract per transaction.
Some key features of PRBProxy include:
- Forwarding calls with
DELEGATECALL
- Use of CREATE2 to deploy the proxies at deterministic addresses.
- A unique registry system ensures that each user has a distinct proxy.
- An access control system that permits third-party accounts (called "envoys") to call target contracts on behalf of the owner.
- A plugin system that enables the proxy to respond to callbacks.
- Reversion with custom errors rather than reason strings for improved error handling.
- Comprehensive documentation via NatSpec comments.
- Development and testing using Foundry.
Overall, PRBProxy is a powerful tool for transaction composition, providing numerous features and benefits not available through EOAs.
First, run the install step:
forge install PaulRBerg/prb-proxy@release-v4
Your .gitmodules
file should now contain the following entry:
[submodule "lib/prb-proxy"]
branch = "release-v4"
path = "lib/prb-proxy"
url = "https://github.com/PaulRBerg/prb-proxy"
Finally, add this to your remappings.txt
file:
prb-proxy/=lib/prb-proxy/src/
PRBProxy is available as an npm package:
pnpm add @prb/proxy
The concept of a forwarding proxy has gained popularity thanks to DappHub, the developer team behind the decentralized stablecoin DAI. DappHub created DSProxy, a widely used tool that allows for the execution of multiple contract calls in a single transaction. Major DeFi players like Maker, Balancer, and DeFi Saver all rely on DSProxy.
However, as the Ethereum ecosystem has evolved since DSProxy's launch in 2017, the tool has become outdated. With significant improvements to the Solidity compiler and new EVM OPCODES, as well as the introduction of more user-friendly development environments like Foundry, it was time for an update.
Enter PRBProxy, the modern successor to DSProxy; a "DSProxy 2.0", if you will. It improves upon DSProxy in several ways:
- PRBProxy is deployed with CREATE2, which allows clients to pre-compute the proxy contract's address.
- The
CREATE2
salts are generated in a way that eliminates the risk of front-running. - The proxy owner is immutable, and so it cannot be changed during any
DELEGATECALL
. - PRBProxy uses high-level Solidity code that is easier to comprehend and less prone to errors.
- PRBProxy offers more features than DSProxy.
Using CREATE2 eliminates the risk of a chain reorg overriding the proxy contract owner, making PRBProxy a more secure alternative to DSProxy. With DSProxy, users must wait for several blocks to be mined before assuming the contract is secure. However, PRBProxy eliminates this risk entirely, making it possible to safely send funds to the proxy before it is deployed.
There are multiple ways to deploy a proxy:
Function | Description |
---|---|
deploy |
Deploy a proxy for msg.sender |
deployFor |
Deploy a proxy for the provided owner |
deployAndExecute |
Deploy a proxy for msg.sender , and delegate calls to the provided target |
deployAndInstallPlugin |
Deploy a proxy for msg.sender , and installs the provided plugin |
deployAndExecuteAndInstall |
Deploy a proxy for msg.sender , delegate calls to the provided target, and installs the provided plugin |
Once the proxy is deployed, you can start interacting with target contracts by calling the execute
function on the proxy by passing the ABI-encoding
function signatures and data.
See this repository's wiki page for guidance on how to write plugins, targets, and front-end integrations.
The registry is deployed on the following chain:
Contract | Chain | Chain ID | Address |
---|---|---|---|
PRBProxyRegistry | Goerli Testnet | 5 | 0x33e200B5fb5e0C57d370d5202c26A35d07A46B98 |
Integrating PRBProxy into a frontend app would look something like this:
- Begin by calling the
getProxy
function on the registry to determine if the user already has a proxy. - If the user does not have a proxy, deploy one for them using one of the deploy methods outlined above.
- Interact with your desired target contract using the
execute
function. - Install relevant plugins, which can make the proxy react to your protocol events.
- Going forward, treat the proxy address as the user of your system.
However, this is just scratching the surface. For more examples of how to use PRBProxy in a frontend environment, check out the Frontends wiki. Additionally, Maker's developer guide, Working with DSProxy, provides an in-depth exploration of the proxy concept that can also help you understand how to use PRBProxy. Just be sure to keep in mind the differences outlined throughout this document.
It costs ~528,529 gas to deploy a PRBProxy, whereas a DSProxy costs 596,198 gas - a reduction in deployment costs of roughly 12%.
The execute
function in PRBProxy is slightly more expensive than in its counterpart, due to the safety checks in our implementation. However, the
majority of gas cost when calling execute
is due to the target contract.
Feel free to dive in! Open an issue, start a discussion, or submit a PR.
You will need the following software on your machine:
In addition, familiarity with Solidity is requisite.
Clone this repository including submodules:
$ git clone --recurse-submodules -j8 git@github.com:PaulRBerg/prb-proxy.git
Then, inside the project's directory, run this to install the Node.js dependencies:
$ pnpm install
Now you can start making changes.
You will need the following VSCode extensions:
While I have strict standards for code quality and test coverage, it's important to note that this project may not be entirely risk-free. Although I have taken measures to ensure the security of PRBProxy, it has not yet been audited by a third-party security researcher.
Please be aware that this software is experimental and is provided on an "as is" and "as available" basis. I do not offer any warranties, and I cannot be held responsible for any direct or indirect loss resulting from the continued use of this codebase.
If you discover any bugs or security issues, please report them via Telegram.
- ds-proxy - DappHub's proxy, which powers the Maker protocol.
- dsa-contracts - InstaDapp's DeFi Smart Accounts.
This project is licensed under MIT.