40,000 USDC
View results
Submission Details
Severity: gas

[G‑01] Consider using clones

All optimizations were benchmarked using the protocol's tests using the following config: solc version 0.8.18, optimizer on, 200 runs, viaIR = true. In most cases forge test --gas-report was used

Each optimization was submitted individually.

Gas Optimizations

Issue Instances Total Gas Saved
[G‑01] Consider using clones * -70% cheaper deployment gas
[G‑02] ReentrancyGuard can be safely removed 1 42725
[G‑03] computeEscrowAddress() can be internal instead of public 1 55863 + 193
[G‑04] Redundant zero address checks 2 237
[G‑05] Input validation should be done in the beginning 2 110649(in the revert case)
[G‑06] Emit after the transfer has been made in case it fails 2 1381(in the revert case)
[G‑07] The bytecode can be removed from the function params 1 27
[G‑08] Nested ifs are cheaper than && 1 19

[G‑01] Consider using clones

For each escrow, the factory has to deploy a new copy of the entire contract which is very expensive. But because we are deploying exactly the same contract repeatedly, using minimal proxies is a much more gas efficient way to do it.

What is a minimal proxy?

Minimal Proxy Contracts are used to create lightweight and gas-efficient instances of a smart contract by reusing the logic of an existing contract. Instead of deploying a new copy of the entire contract each time like the factory does, minimal proxy contracts act as a thin layer that forwards calls to an already deployed implementation contract

A clone contract is like a proxy that cannot be upgraded. Because proxies are very small relative to the implementation contract, they are cheap to deploy.

Like the proxy pattern, clones delegate all calls to the implementation contract but keep state in their own storage.

A good example is Manifold or Gnosis, both use the clone pattern when creating a new safe/project and when you are interacting with the contract, you are actually interacting with a clone of it.

Gas savings

So i decided to rewrite the contracts to use clones to see what the gas savings are. A gist containing all the differences can be found here. It took me less than 5 minutes to rewrite everything.

Gas Savings for newEscrow() obtained via protocol's tests(median was used because the avg isnt accurate here): 431540 gas

MED
Before 627057
After 195517

As you can see that is almost a -70% gas reduction for deploying a new escrow which is a lot.

Please note that the only problem is that runtime gas will be a bit bigger because we are using delegatecall and we cant use immutables because there is no constructor(however that is still possible using this library).
However even if the runtime gas is a bit bigger, that is not a problem because only one person is interacting with that contract and deployment gas is more important here.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.