Skip to content

Commit

Permalink
docs: roll v4.0.0-beta.6
Browse files Browse the repository at this point in the history
docs: update README
  • Loading branch information
PaulRBerg committed Jun 29, 2023
1 parent dcf94b2 commit 82d14b9
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 75 deletions.
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Common Changelog](https://common-changelog.org/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

[4.0.0-beta.6]: https://github.com/PaulRBerg/prb-proxy/compare/v4.0.0-beta.5...v4.0.0-beta.6
[4.0.0-beta.5]: https://github.com/PaulRBerg/prb-proxy/compare/v4.0.0-beta.4...v4.0.0-beta.5
[4.0.0-beta.4]: https://github.com/PaulRBerg/prb-proxy/compare/v4.0.0-beta.3...v4.0.0-beta.4
[4.0.0-beta.3]: https://github.com/PaulRBerg/prb-proxy/compare/v4.0.0-beta.2...v4.0.0-beta.3
Expand All @@ -14,6 +15,37 @@ The format is based on [Common Changelog](https://common-changelog.org/), and th
[1.0.1]: https://github.com/PaulRBerg/prb-proxy/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/PaulRBerg/prb-proxy/releases/tag/v1.0.0

## [4.0.0-beta.6] - 2023-06-29

### Changed

- Change `proxies` getter to `getProxy` ([#100](https://github.com/PaulRBerg/prb-proxy/pull/118)) (@PaulRBerg)
- Improve documentation in NatSpec comments (@PaulRBerg)
- Make the registry in charge of plugins ([#120](https://github.com/PaulRBerg/prb-proxy/pull/120)) (@PaulRBerg)
- Make the `owner` an immutable variable ([#120](https://github.com/PaulRBerg/prb-proxy/pull/120)) (@PaulRBerg)
- Rename `methodList` to `methods`
- Use `owner` instead of `tx.origin` as CREATE2 salt ([#130](https://github.com/PaulRBerg/prb-proxy/pull/130)) (@PaulRBerg)

### Added

- Add `deployAndExecuteAndInstallPlugin` function ([#134](https://github.com/PaulRBerg/prb-proxy/pull/134)) (@PaulRBerg)
- Add `deployAndInstallPlugin` function ([#131](https://github.com/PaulRBerg/prb-proxy/pull/131)) (@PaulRBerg)
- Add new getters for reading the plugins and the permissions ([#120](https://github.com/PaulRBerg/prb-proxy/pull/120)) (@PaulRBerg)
- Store plugin methods in reverse mapping ([#131](https://github.com/PaulRBerg/prb-proxy/pull/131)) (@PaulRBerg)

### Removed

- Remove `deployAndExecuteFor` function ([#113](https://github.com/PaulRBerg/prb-proxy/pull/113)) (@PaulRBerg)
- Remove `minGasReserve` storage variable ([#114](https://github.com/PaulRBerg/prb-proxy/pull/114)) (@PaulRBerg)
- Remove `nextSeeds` storage variable ([#130](https://github.com/PaulRBerg/prb-proxy/pull/130)) (@PaulRBerg)
- Remove `PRBProxyAnnex` ([#120](https://github.com/PaulRBerg/prb-proxy/pull/120)) (@PaulRBerg)
- Remove proxy storage ([#120](https://github.com/PaulRBerg/prb-proxy/pull/120)) (@PaulRBerg)
- Remove `transferOwnership` functionality ([#119](https://github.com/PaulRBerg/prb-proxy/pull/119)) (@PaulRBerg)

### Fixed

- Check for plugin method collisions ([#129](https://github.com/PaulRBerg/prb-proxy/pull/129)) (@PaulRBerg)

## [4.0.0-beta.5] - 2023-05-30

### Changed
Expand Down
116 changes: 45 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,22 @@
[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg

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. Externally owned accounts (EOAs) do not have this functionality; they are limited to
interacting with only one contract per transaction.
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`][se-3667]
- Use of [CREATE2][eip-1014] 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
- 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.

## Background

The concept of a proxy contract has gained popularity thanks to DappHub, the team responsible for creating the decentralized stablecoin
[DAI](https://makerdao.com). DappHub created [DSProxy](https://github.com/dapphub/ds-proxy), 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](https://book.getfoundry.sh/), 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:

1. PRBProxy is deployed with [CREATE2][eip-1014], which allows clients to pre-compute the proxy contract's address.
2. The `CREATE2` salts are generated in a way that eliminates the risk of front-running.
3. The proxy owner is immutable, and so it cannot be changed during any `DELEGATECALL`.
4. PRBProxy uses high-level Solidity code that is easier to comprehend and less prone to errors.
5. PRBProxy offers more features than DSProxy.

Using CREATE2 eliminates the risk of a [chain reorg](https://en.bitcoin.it/wiki/Chain_Reorganization) 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, allowing users to even safely send funds to the proxy before it is deployed.

## Install

### Foundry
Expand Down Expand Up @@ -81,78 +59,76 @@ PRBProxy is available as an npm package:
pnpm add @prb/proxy
```

## Usage

There are multiple ways to deploy a proxy:

- Call the `deploy` function.
- Call the `deployFor` function, which accepts the owner as an argument.
- Call the `deployAndExecute` function, which deploys the proxy and executes a delegate call to a target contract in a single transaction.
## Background

Once the proxy is deployed, you can start interacting with target contracts by ABI-encoding the target's functions and pass the data to the `execute`
function on the proxy.
The concept of a forwarding proxy has gained popularity thanks to DappHub, the developer team behind the decentralized stablecoin
[DAI](https://makerdao.com). DappHub created [DSProxy](https://github.com/dapphub/ds-proxy), 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.

### Addresses
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](https://book.getfoundry.sh/), it was time for an update.

The registry and the enshrined target are deployed at the same address on the following chains:
Enter PRBProxy, the modern successor to DSProxy; a "DSProxy 2.0", if you will. It improves upon DSProxy in several ways:

| Contract | Chain | [Chain ID](https://chainlist.org/) | Address |
| -------- | ----------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Registry | Ethereum Goerli Testnet | 5 | [0xa87bc4C1Bc54E1C1B28d2dD942A094A6B665B8C9](https://goerli.etherscan.io/address/0xa87bc4C1Bc54E1C1B28d2dD942A094A6B665B8C9#code) |
1. PRBProxy is deployed with [CREATE2][eip-1014], which allows clients to pre-compute the proxy contract's address.
2. The `CREATE2` salts are generated in a way that eliminates the risk of front-running.
3. The proxy owner is immutable, and so it cannot be changed during any `DELEGATECALL`.
4. PRBProxy uses high-level Solidity code that is easier to comprehend and less prone to errors.
5. PRBProxy offers more features than DSProxy.

### Targets
Using CREATE2 eliminates the risk of a [chain reorg](https://en.bitcoin.it/wiki/Chain_Reorganization) 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.

To make use of PRBProxy, you need a so-called "target". Target contract consist of stateless scripts and are the key to leveraging PRBProxy for
transaction composition.
## Usage

As an example, here's a target contract that wraps ETH into WETH (the ERC-20 version of ETH) and deposits the resulting WETH into a DeFi protocol
called Acme:
There are multiple ways to deploy a proxy:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.18 <=0.9.0;
| 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 |

interface AcmeLike {
function depositCollateral(address token, uint256 collateralAmount);
}
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.

interface WethLike {
function deposit() external payable;
}
### Documentation

function wrapEthAndDepositCollateral(AcmeLike acme) external payable override {
uint256 depositAmount = msg.value;
See this repository's [wiki](https://github.com/PaulRBerg/prb-proxy/wiki) page for guidance on how to write plugins, targets, and front-end
integrations.

// Convert the received ETH to WETH.
WethLike weth = WethLike(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
weth.deposit{ value: depositAmount }();
### Addresses

// Deposit the WETH as collateral into the Acme DeFi protocol.
acme.depositCollateral(address(weth), depositAmount);
}
```
The registry is deployed on the following chain:

For more examples of target contracts, see the [Targets][targets] wiki.
| Contract | Chain | [Chain ID](https://chainlist.org/) | Address |
| ---------------- | -------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| PRBProxyRegistry | Goerli Testnet | 5 | [0x33e200B5fb5e0C57d370d5202c26A35d07A46B98](https://goerli.etherscan.io/address/0x33e200B5fb5e0C57d370d5202c26A35d07A46B98#code) |

### Frontends

Integrating PRBProxy into a frontend app is a straightforward process:
Integrating PRBProxy into a frontend app would look something like this:

1. Begin by calling the `getCurrentProxy` function on the registry to determine if the user already has a proxy.
2. If the user does not have a proxy, ask them to deploy one by calling either the `deploy` or `deployFor` function.
1. Begin by calling the `getProxy` function on the registry to determine if the user already has a proxy.
2. If the user does not have a proxy, deploy one for them using one of the deploy methods outlined above.
3. Interact with your desired target contract using the `execute` function.
4. Going forward, treat the proxy address as the user of your system.
4. Install relevant plugins, which can make the proxy react to your protocol events.
5. 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][frontends]
wiki. Additionally, Maker's developer guide, [Working with DSProxy][dsproxy-guide], 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.

## Gas Efficiency

It costs 528,529 gas to deploy a PRBProxy, whereas a DSProxy costs 596,198 gas - a reduction in deployment costs of roughly 12%.
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 costs when calling execute are instead related to the logic being executed in the target contract.
majority of gas cost when calling `execute` is due to the target contract.

## Contributing

Expand Down Expand Up @@ -210,7 +186,6 @@ If you discover any bugs or security issues, please report them via [Telegram](h
## Acknowledgments

- [ds-proxy](https://github.com/dapphub/ds-proxy) - DappHub's proxy, which powers the Maker protocol.
- [wand](https://github.com/nmushegian/wand) - attempt to build DSProxy 2.0, started by one of the original authors of DSProxy.
- [dsa-contracts](https://github.com/Instadapp/dsa-contracts) - InstaDapp's DeFi Smart Accounts.

## License
Expand All @@ -221,7 +196,6 @@ This project is licensed under MIT.

[eip-1014]: https://eips.ethereum.org/EIPS/eip-1014
[frontends]: https://github.com/PaulRBerg/prb-proxy/wiki/Frontends
[targets]: https://github.com/PaulRBerg/prb-proxy/wiki/Targets
[se-3667]: https://ethereum.stackexchange.com/questions/3667/difference-between-call-callcode-and-delegatecall/3672
[dsproxy-guide]:
https://github.com/makerdao/developerguides/blob/9ded1b68228e6cd70885f1326349c6bf087b9573/devtools/working-with-dsproxy/working-with-dsproxy.md
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@prb/proxy",
"description": "Proxy contract to compose Ethereum transactions on behalf of the owner",
"version": "4.0.0-beta.5",
"version": "4.0.0-beta.6",
"author": {
"name": "Paul Razvan Berg",
"url": "https://github.com/PaulRBerg"
Expand Down
2 changes: 1 addition & 1 deletion src/PRBProxyRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract PRBProxyRegistry is IPRBProxyRegistry {
//////////////////////////////////////////////////////////////////////////*/

/// @inheritdoc IPRBProxyRegistry
string public constant override VERSION = "4.0.0-beta.5";
string public constant override VERSION = "4.0.0-beta.6";

/*//////////////////////////////////////////////////////////////////////////
USER-FACING STORAGE
Expand Down
2 changes: 1 addition & 1 deletion test/registry/version/version.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Registry_Test } from "../Registry.t.sol";
contract Version_Test is Registry_Test {
function test_Version() external {
string memory actualVersion = registry.VERSION();
string memory expectedVersion = "4.0.0-beta.5";
string memory expectedVersion = "4.0.0-beta.6";
assertEq(actualVersion, expectedVersion, "registry version mismatch");
}
}
2 changes: 1 addition & 1 deletion test/utils/Precompiles.sol

Large diffs are not rendered by default.

0 comments on commit 82d14b9

Please sign in to comment.