Solving deployment costs with circular smart contracts

By
Adi Elimelech
|
September 5, 2022

Gas costs might be the blockchain industry biggest challenge to becoming mainstream. The solution lies in circular smart contracts.

Antic is transaction heavy, which is why we’re focused on minimizing gas costs for our users.

We believe that our success relies on the success of the ecosystem as a whole. In other words, we’re all in this together. That’s why we’ve created a series of articles to share our journey, and the lessons we discovered along the way. In the next couple of minutes, we will talk about dApp architecture, focusing on its efficiency, modularity, and scalability. 

Let’s begin with a SpaceX Analogy

With their concept of reusing boosters, SpaceX achieved incredible operational efficiency in the space industry. Let’s say the booster is the DAO, rocket fuel is gas fees, and the payload of the falcon 9 rocket is the value that you provide to users. 

Why leave the expensive booster in space where it clutters the atmosphere when you could land it, refurbish it, and use it for the next launch? In this case, it’s important to conceptually decouple the smart contract (the shell) from the value itself. The smart contract must be deployed on-chain. The deployment involves specific gas fees for the processing and/or computational power needed to deploy the contract on-chain. This energy consumption is priced and translated into "gas fees." 

The smart contract is then deployed and attached to a specific value. The concept of re-usable contracts or green contracts requires the separation of the two so that you'll be able to re-use the smart contract and attach a different value to it in the future.

Building Blocks

Off-chain Bookkeeping

The first step for efficiently reusing deployed contracts is creating an off-chain record of every deployed contract in your system. In your schema design, you may already have a Contracts table that relates to the Users table (the same principles apply, of course, to a NoSQL database). We will add a taken column to the Contract table. It’s worth noting that in most cases this will be a boolean flag, but in some systems the about-to-be-recycled contract can have more than two states. In this instance an enum makes more sense. For example, some operations are better executed in bulk or at a specific time, meaning you might have an intermediate state such as readyForRecycle. We’d suggest using a nice state machine with clear labels, rather than creating a collection of boolean flags to describe the state of an entity. This will simplify your queries..

New contracts are deployed when there are users who wish to use them, so we can assume that the default state of a contract is taken=True.

The Reset Mechanism (Last man out turns off the lights)

Let’s  continue our journey through the life cycle of our contract. The contract is deployed and populated with assets and users. In our system, the contract is a vessel for providing a certain value to one or more users, but after achieving the contract’s objective, it becomes an empty shell without a purpose. For example, let’s explore a dApp allowing users to bet on (or hedge against) the future price of a token. In this scenario, the system will match two users that want to bet one against the other and provide a contract to facilitate that bet. The users will send funds to the contract and wait until the agreed upon conditions are met. At that point in time the winning user will withdraw the funds from the contract.

In order to make the contract reusable, we need to identify all the exit paths that remove the assets and users from the contract. In our example, the winner withdrawing all funds is one path. If the users have other exit points or a way to cancel the bet by mutual agreement, this would be another. In each of these paths you identified, you will need to call a reset function that will clear the contract state and prepare it for the next batch of users. It will also emit a contractReadyForRecycle event that will let your backend know it can now mark this contract as taken=false and clear any previously saved state.

You will not be able to reuse all deployed contracts as there is no way to guarantee that users will always act as expected; some will lose access to their wallets or forget to withdraw. 

The Repopulation Mechanism

The final step in the recycling process is to use our contract at the right time. After receiving a new request, query your database for a suitable empty contract (with taken=false and optionally other parameters). If there are no available contracts you will have to deploy a new one— but if there are, you just saved yourself and your users some gas money. In your contract, identify the entry paths (analogous to the exit paths we discussed), that populate the contract with assets so that you can emit a contractInUse event for your backend to mark this contract as taken=True.

Guardrails

It is imperative for a facilitator that a DAO cannot be vacated or repopulated while it is in use, just as a landlord cannot enter an apartment while his tenants are under contract. A convenient way of making sure that you are not recycling or repopulating a DAO/Smart Contract in use is by creating a modifier that allows the action if the contract is empty and reverts it if the contract is used. Add this modifier to your setup and teardown functions.

But what about the future? 

As the industry grows, a lean on-chain imprint will become a necessity and a hallmark of good system design.

In a computing paradigm where every transaction is stored by everyone (roughly speaking), it is impractical and unsustainable to have everyone transmit as many transactions as they please. So strictly from an economical point of view, it’s always necessary to use the the shared resource (i.e. ledger) efficiently. Even if gas prices are very cheap, at a certain scale, tiny differences build up to large numbers. 

Let’s take traditional applications as an example: the client is communicating with the server using requests (usually to read and persist data from and to the database). The developer determines when and how frequently these requests are made.

In traditional system design, it is bad to make unnecessary calls to the server, it's slow and wasteful, so even though the price for every request is negligible, when scaled it is not negligible, and developers aim to avoid that, and be as efficient as possible, especially at larger scales.

In much the same way, the distributed ledger (aka the blockchain) serves as the database for web3 apps and sending transactions to the blockchain is like sending new data to the database for persistence.

We predict that DAO reuse will become a common optimization technique for dao-as-a-service companies. The practice will significantly advance decentralized economies by making them more cost-effective.