Cost-Effective Smart Contract Deployment: Minimal Proxy (EIP-1167)

Every new contract on the network means paying again to deploy the same code. We implement a minimal proxy turnkey: one logic serves many instances, and deployment cost drops several times over. Let's discuss your task — we'll come back with an estimate and a plan.

Blockchain Development Services

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Minimal proxy: why contract deployment eats the budget

Every new contract instance in the EVM is a repeated write of the entire bytecode into the network's storage.

The cost of deploying a contract comes not from logic but from volume: the network charges for every 32 bytes of code, and when deploying dozens of identical instances via a factory, you pay for the same code multiple times.

The minimal proxy eliminates exactly this duplication: instead of a copy of the logic, a short pointer contract is placed on-chain, delegating all calls to a single already-deployed implementation instance.

The mechanics are simple. The proxy stores the implementation address and, via DELEGATECALL, executes its code in its own context — with its own storage, its own balance, and its own address.

The implementation bytecode is deployed once, and each new instance costs exactly as much as the proxy itself occupies — tens of bytes instead of kilobytes.

Deployment gas drops by an order of magnitude, and this is not a one-time saving: it scales with every new entity you create.

The second cost item is upgrades. Without a proxy, any logic change means redeploying the bytecode and migrating state: old instances remain on the previous version, new ones live separately, and the history diverges.

With a minimal proxy, you change the implementation address — all instances immediately start running on the new logic, and the state stays in place. Redeploying bytecode turns into a single pointer-update transaction.

The cost of the solution is also known, and it must be factored in advance. A proxy cannot have a constructor — initial parameters are passed through a separate initialization function, which must be protected against repeated calls.

The proxy's and the implementation's storage live in the same slot, so the order of variables is fixed from day one: rearranging fields during an upgrade breaks the state.

Code readability in the network explorer drops — you see the proxy, and the logic has to be viewed at the implementation address.

It is precisely at these boundaries that teams most often stumble when adopting the pattern without scrutiny. Next, we break down how this is addressed: where the minimal proxy delivers the maximum gain, and where it is cheaper to keep direct deployment.

How a minimal proxy reduces deployment cost

A minimal proxy is a wrapper contract that stores the address of the logic and delegates all calls to it via DELEGATECALL.

The bytecode of such a proxy fits into a few dozen bytes versus thousands for a full-fledged contract, so only a small wrapper is written to the blockchain, while the heavy logic is deployed once.

When cloning a contract, each new instance costs an order of magnitude less gas than a full re-publication of the code.

What bytecode reduction gives

Deployment is the most expensive operation on the network: gas is charged for every byte written. The proxy template removes the body of the logic from the transaction, leaving only a reference to it.

On a stream of similar contracts — tokens, storages, instances for each client — this shifts the cost from "every time anew" to "once plus cheap copies."

Contract factory and shared logic

A contract factory deploys the proxy at a predictable address and passes the parameters of a specific instance to the constructor. The logic remains shared: a behavior update is made in one place and picked up by all clones. A side effect is predictable addresses, which are convenient to bake into integrations in advance.

Measurable effect

Option When it fits Limitations
Full deployment Unique logic, a single contract Maximum transaction cost, code duplication
Proxy template (EIP-1167) Many similar instances Logic is shared, state is individual to each
Contract factory A stream of clones with parameters Requires careful handling of addresses and permissions

In practice, switching to a minimal proxy reduces the instance bytecode by tens of times and lowers deployment gas by an order of magnitude — with a stream of hundreds of clones, the difference in transaction cost becomes decisive.

The approach is standardized in EIP-1167, so it is compatible with most build and verification tools.

What if the logic needs to be updated? The proxy stores the implementation address separately, so changing the logic does not require re-issuing the clones — only one shared part is updated.

Implementing a minimal proxy: stages of engineering work

Implementing a minimal proxy starts with an audit of the contracts: we look at which logic contracts are reused between instances, where bytecode is duplicated, and which functions must remain immutable.

Based on the results, we record what is moved into the shared implementation and what stays in the proxy — this determines both the deployment scheme and the amount of storage per instance.

Next, we structure the process so that the factory is predictable and logic upgrades do not break already created instances.

  1. Contract audit. We analyze the current code, identify shared libraries and functions, and check where storage is tied to the address and cannot be moved into the proxy without changes.
  2. Designing the deployment scheme. We determine how the proxy references the implementation, how state is initialized, and how the rights to upgrade logic and to manage instances are separated.
  3. Factory setup. We build a factory that deploys proxies deterministically, with address verification and protection against re-initialization.
  4. Proxy testing. We run through the scenarios: instance creation, calls via delegation, implementation upgrades, rollback, and behavior when there are errors in the logic.
  5. Testing on a testnet. We deploy the factory and several instances, verify the addresses, the gas cost of creation, and the correctness of state after calls.
  6. Handover of the solution. We deliver the configured factory, deployment scripts, the storage scheme, and instructions for adding new instances.
  7. Post-launch support. We assist with the first production deployment and establish the procedure for upgrading logic without migrating already created proxies.

This order eliminates the main risk — when proxies have been created but the logic cannot be upgraded without reissuing all instances. The audit and tests in the early stages reveal this before production launch, not after.

How is a minimal proxy different from a regular proxy?

A minimal proxy is a contract that contains no application logic at all. All it has is an instruction to delegate calls and a hardcoded implementation address.

Any call that arrives at the proxy's address goes through DELEGATECALL to the implementation contract, and the code executes in the context of the proxy's storage. The proxy itself stores neither variables nor state — only an immutable address compiled into the bytecode. That is exactly why its size is tens of bytes rather than kilobytes.

A regular upgradeable proxy is structured differently. It stores the implementation address in a storage slot, which means it can change it: add an upgradeTo function, check administrator rights, update the variable.

You have to pay for this: the upgrade logic is code, code takes up space in the bytecode, and the slot holding the address must be protected from collisions with the implementation's storage.

Hence entire schemes like EIP-1967, where the implementation address is placed in a pseudo-random slot so that it does not overlap with the logic's variables.

The difference in deployment cost is a direct consequence of the difference in size. When deployed, a minimal proxy writes only a short bytecode to the blockchain, so it costs an order of magnitude less than a full-fledged upgradeable proxy with upgrade logic.

When you spin up hundreds or thousands of identical instances — for example, one contract per user or per lot — this difference accumulates into multiples in total deployment costs.

The flip side: a minimal proxy is immutable. The implementation address is hardcoded into the bytecode, and it cannot be changed after deployment — you won't be able to update the logic of already created instances.

An upgradeable proxy provides that capability, but adds a management layer on top of delegation: who has the right to upgrade, how the slots are protected, what happens if there is an error in the new implementation.

This is not "better" or "worse" — it is a choice between saving on deployment and flexibility of upgrades.

In practice, the choice is this: if the logic is final and will not change, and there are many instances — a minimal proxy. If the contract will evolve, and there are only one or two instances — an upgradeable proxy, where the overhead of management is justified.

A mixed option also occurs: an upgradeable implementation plus minimal proxies pointing to it — then the logic can be updated once for all clones.

Case: reducing deployment cost by 10x for a marketplace network

The client — a network of regional marketplaces — was rolling out a new trading contract for each city and category.

Every deployment pulled the full bytecode with the logic for lots, bids, and settlements: the same code was shipped to the network dozens of times, and gas had to be paid for it again each time.

By the tenth contract the bottleneck became obvious: launching a new storefront took hours and ran into the cost of writing code to the blockchain.

We split the logic into two layers. The shared part — trading rules, fees, roles — was moved into a single reference implementation contract. Each new storefront became a minimal proxy: a short contract that stores the implementation address and delegates calls to it.

Such a proxy fits into a few dozen bytes, so only a reference is written to the network, not the entire code.

What changed in numbers

Metric Before After
Gas per storefront deployment reference ~1/10 of the reference
Time to launch a new storefront hours minutes
Editing logic across all storefronts per each contract one implementation

We separately addressed upgradability: a controller is attached to the proxy, which switches the implementation address. A change to trading rules is rolled out to all storefronts at once, without redeployment and without state migration — the data stays in place.

We honestly noted the limitation: the proxy does not store its own logic, so all of it must live in the implementation, and the constructor is replaced with an explicit initializer.

The result: the network scales to new cities without gas costs growing proportionally to the number of contracts, and launching a storefront is no longer a separate engineering task.

The approach relies on EIP-1167 — the minimal proxy standard, battle-tested on thousands of contracts.

Doubts and guarantees: compatibility, migration, rollback

A proxy contract is a separate addressing layer, and the main technical risk here is not gas savings, but the fact that logic and storage live separately.

The Minimal proxy (EIP-1167) delegates calls to the implementation via delegatecall, so the state remains at the proxy address, while the code lives at the logic address.

This raises two practical questions: what to do if the implementation needs to be upgraded, and what will happen to the already accumulated user data.

Can the logic be upgraded without losing the state and the contract address?

Yes, if the architecture is designed in advance. The proxy address is immutable — only the pointer to the implementation changes, while the storage stays in place.

What is critical is something else: the order and types of variables in the new code must match the old ones, otherwise the data will "shift". That is why we lock down the storage layout before the first deployment and verify every upgrade on a testnet with a real state snapshot.

What if a rollback is needed? A rollback is done by reverting the pointer to the previous implementation — provided that its address is saved and the state has not changed irreversibly.

We keep a history of implementations and describe which operations are reversible and which are not.

How are access rights set up? The roles for upgrading, pausing, and withdrawing funds are separated and moved into a dedicated management contract. The keys are a multisig, not a single wallet.

Is it compatible with the current stack? The Minimal proxy is a standard, understood by all major block explorers, wallets, and verification tools. There is one limitation: the logic must not use a constructor for initialization — the initial values are set via a separate call.

After the work is done, the client receives:

  • the sources of the proxy and the implementation with compiler settings;
  • the storage layout with compatibility rules for upgrades;
  • the management contract with a role matrix and signature thresholds;
  • deployment and upgrade scripts, reproducible on a testnet;
  • a rollback procedure with a list of reversible operations;
  • a report on the checks and the results of tests on a real state snapshot;
  • documentation on addresses, roles, and the procedure to follow in case of an incident.

Describe your task — we will come back with an estimate and a plan: which contracts are already on-chain, how the storage is set up, and what is planned to be changed.