By Kevin Britz
At Astro Wallet, which was recently acquired by Coinbase, we spent the better part of the last two years researching economic abstraction in various forms. We’d like to share our findings with the greater blockchain industry in the hope that this may serve as a guide to solve many of the UX issues that decentralized applications face today.
Though not a new concept, previously only a small subsection of economic abstraction use cases have been practically feasible. In this writeup we’ll discuss how to achieve a generalized implementation today.
We’ve seen the term used loosely, so to start we’d like to give a specific definition.
Economic Abstraction — The ability to pay for any blockchain transaction and resulting operation(s) with any asset on that blockchain atomically.
Let’s give a few examples to further clarify what this covers:
- A user would like to transfer USDC, but does not have ETH to cover the transaction fee.
- A user would like to purchase a CryptoKitty on a 0x v3 relayer where the relayer is charging a ZRX fee and the seller wants DAI, but the user only has USDC.
In practice, on most blockchains this is split into two components: fee abstraction and token abstraction. If we can enable both, we have complete economic abstraction.
Fee Abstraction — The ability to pay for the blockchain transaction fee in any asset on that blockchain atomically.
Protocols generally must have a specific base token (like Ether) to ensure the security of their network. Some protocols have played with the idea of accepting any token for the transaction fee, thus enabling fee abstraction, however this isn’t suitable for most protocols. In our implementation section we’ll discuss how to construct fee abstraction on a protocol like Ethereum.
Token Abstraction — The ability to pay for the blockchain transaction’s resulting operation(s) with any asset on that blockchain atomically.
Once a transaction is executed, the resulting operation might spend any number of assets, such as purchasing a CryptoKitty with USDC or lending DAI on Compound. With token abstraction we are not limited to paying in that specific token, and instead can pay in any asset on that blockchain.
To implement fee and token abstraction, we need two core blockchain features: fee delegation and multi-op transactions. Most blockchains do not have both supported natively (Ethereum has neither), so additional construction is needed to achieve our prerequisites. In our construction we’ll look mainly at Ethereum, however this applies to most smart contract platforms.
The key to enabling these core features on Ethereum is through the use of smart contract wallets. These features do not exist on traditional addresses, but with smart contracts we can add additional logic enabling new core functionality.
Fee Delegation — The ability to designate another payer than the sender for a transaction’s fee.
Most smart contract wallets today facilitate fee delegation through the use of gas relayers. Instead of sending a transaction directly to their smart contract wallet, thus paying their own transaction fee, users can sign a message to be relayed (packaged into a transaction and sent on their behalf). Since the user’s actual account is the smart contract, both entry points are valid as long as the wallet can verify the invocation.
Multi-Operation Transactions — The ability to package multiple atomic function calls into a single transaction.
Unlike fee delegation, multi-op transactions are not yet widely utilized. This feature is necessary to facilitate multiple operations within a single atomic transaction. Wrapper contracts have been used to solve this to some effect, however they conceal metadata such as msg.sender which prevents them from being used as a generalized solution. Luckily this feature is fairly straightforward to include in smart contract wallets, however, so far Dapper is the only smart contract wallet that supports this feature.
Leveraging multi-op transactions, we can build a message passing protocol on top of the standard gas relayer architecture to enable fee abstraction. Here we provide a simple example protocol which may be extended to provide additional wallet features.
Step 0: Client wallet would like to send a transaction consisting of operations [1…n].
Step 1: Client wallet notifies the gas relayer with the transaction it would like to send, and with the asset it would like to pay the transaction fee in.
Step 2: Relayer responds with a signed quote specifying a price in the requested asset to relay the requested transaction.
Step 3: Client wallet attaches an additional operation transferring the specified value of the asset to the relayer.
Step 4: This finalized transaction with operations [1…n+1] is sent to the relayer along with the signed quote.
Step 5: Relayer validates transaction and quote then sends off the transaction to the blockchain.
This functionality also opens up the opportunity for the client wallet to request quotes from many gas relayers, only choosing to send the finalized transaction to the cheapest.
Again with the support of multi-op transactions, token abstraction becomes fairly simple to support, with the key complexity being with transaction analysis. The client wallet needs to be able to analyze a potential transaction to see which assets, and how much of those assets, will be spent (and also received) while executing the operations of the transaction.
At Astro we built an adapted Ethereum node that could run this analysis, but since this is largely an engineering challenge rather than algorithmic, we’ll leave this as an exercise for the reader.
Once we are able to determine the required and resulting assets of the operation set, the wallet can simply reach out to any number of DEXs to construct a set of swaps from and to the user’s base asset. Aggregators like 0x API are great for gathering up these required swaps, or alternatively a wallet could use a simpler, but less slippage-efficient solution such as Uniswap. With this set of swaps, the wallet may construct the finalized transaction by attaching the swap operations for the required and resulting assets before and after the user’s operations respectively.
Now that we’ve implemented both fee and token abstraction, we can combine them for complete economic abstraction.
We can also incorporate other neat features such as just-in-time approval, so that we don’t need a separate transaction to approve contracts such as 0x and Uniswap to spend our assets. This also improves user security since we only have to approve what is needed for the transaction instead of a maximum amount.
With this we can illustrate the rather complex example from our introduction to show what the finalized operation list of the transaction would look like abstracted. As we can see the user was able to pay 0x’s ETH protocol fee, the 0x relayer’s ZRX fee, the CryptoKitty seller’s DAI asking price, and the gas relayer for transmitting the transaction, all with only USDC.