Design and Implementation of Upgradeable Smart Contracts Using Logic/Data Separation and Solidity Libraries
This article describes a practical approach to making Ethereum smart contracts upgradeable by separating business logic and data into distinct contracts, leveraging Solidity libraries, the using keyword, and an entry contract to manage funds and facilitate seamless contract upgrades.
Background: The project required a trustworthy third‑party credit guarantee for a distributed e‑commerce system built on Ethereum. Because smart contracts are immutable once deployed, a mechanism for upgradeability was needed before the first release.
Design: To avoid the pitfalls of a monolithic contract that cannot be changed, the architecture splits contracts into two categories – a logic contract that contains only business logic and a data contract that stores state and provides getter/setter functions. The chosen relationship is a one‑to‑one mapping between logic and data contracts.
Practice – Data Contract: The data contract defines state variables and corresponding set and get functions. (Image of data contract code omitted for brevity.)
Practice – Logic Contract: The logic contract is implemented as a Solidity library , which is a single instance that can be updated without redeploying the whole system, saving gas and avoiding ripple effects.
Entry Contract: An entry contract calls the library to manipulate the data contract and also handles fund custody. It includes a kill function that transfers funds to a new entry contract during upgrades.
Solidity using Keyword: The using keyword allows a contract to attach library functions to a type (e.g., using SomeLibrary for uint; ), enabling concise calls such as number.add(3) . In the project, using LogicLibrary for address lets the entry contract invoke library methods directly on the data contract address.
Inter‑contract Return Issue: During testing, returning dynamic‑length strings from one contract to another caused errors because the EVM does not support variable‑size return data for external calls. The workaround is to expose getter functions for each string field and let the client assemble the full result.
Deployment: The contracts are compiled and deployed with Truffle. Library linking is performed via deployer.link , which embeds the library bytecode into the dependent contracts without explicit code changes.
Final Architecture: After refactoring, the system achieves upgradeability while preserving existing order data and funds. The architecture diagram (image) shows the entry contract, logic library, and data contract interacting together.
Future Work: Remaining challenges include the immutability of the data contract, the need for clients to interact with both contracts, and the absence of a proxy contract that would make upgrades transparent to dApp users.
References: Writing upgradable contracts in Solidity , Solidity’s ‘using’ keyword , and other related articles.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.