Logo
Czar102's Website

Blueprints – DeFi Composability Endgame

A long time ago, I thought of building an exchange. I didn't want it to accept "just" ERC20 tokens or any other single token type. I didn't care what kinds of tokens were traded, I wanted to be able to trade all of them. Why can't we abstract tokens' type away? Other times I wondered about derivatives and "money legos" and how tokens can be composed in a standardized way. Blueprints is the solution I have been thinking about for quite a while.

If you want to go straight to the beef without picking your mind about the context, jump straight here. You can always read the motivation later.

Composability.

Uniswap revolutionized finance forever. Yeah, swapping trustlessly is cool, but what's even cooler is that we can trade any asset we choose. Not just 500 tokens some exchange listed, any token. I can create a token, and without asking anyone for permission, we can trade it.

Composability is the ability to assemble components to create custom structures. In finance, the main operand is a financial position, and yet we aren't mature enough to have made it composable.

There could be other types of entities we'd like to compose in financial applications, but we'll focus on financial positions as a building block – others likely only require a standard interface to plug into (to create a financial position).

Positions.

The primary operand in finance is a financial position. If I buy ETH, I'm entering a position. When I short it, that's another position. I'm taking a position by taking a loan from my favorite bank. When buying insurance, I'm (yet again) entering a position.

Any financial operation is changing something about our financial position – we use verbs like "enter", "exit", "change", and "take" when describing them. But fundamentally, positions are just the things we own, and we may change some things about them so that we own something different. Changing positions is no different from trading (when I extend my loan, it's as if I sold my previous debt position to the bank, which annihilated with the bank's position, and bought another position from the bank with a longer repayment plan).

DeFi protocols express positions in many different ways. Some examples:

As we can see, the positions are expressed very differently – sometimes as an owner-position registry, sometimes ERC20 or rebasing ERC20 (I separated them because integrating with rebasing tokens requires quite different systems), other times ERC721, ERC1155, or even ERC6909.

Building.

You want to build a truly composable financial primitive. So, you want it to be compatible with all the tokens out there, right? Well, ERC20 tokens are very popular for financial primitives, you also want users to be able to use ERC721 and ERC1155. Maybe you don't even care about rebasing tokens. If you take this seriously, you end up with a 900-lines of code file and 200 more lines to manage it. That's how far we've evolved!3

So, maybe we shouldn't integrate all the tokens? Which token standard(s) should we use (and integrate with) if we're creating derivatives (lending, perps, options, insurance, stablecoins – anything that is based on other tokens)?

Even novel codebases like Uniswap v4 or Euler v2 chose to accept only ERC20 tokens. This means that despite our desire to create more custom positions to make financial positions better fitting for owners, we either need to express them in an extremely suboptimal way (using ERC20 for every single token type) or be doomed not to be compatible with mainstream "revolutionary" and "composable" products.4

Problems.

So, what problems are yet to be solved and what should an ideal system look like?

The problems:

The first problem could be solved with a library that can interact with many types of tokens, and standardize the interactions with them to a few functions, similarly to how SafeERC20 works, but for multiple token types. Unfortunately, this would:

Using a token wrapper solves all of these problems. But it also needs to be expandable to be able to wrap all kinds of tokens.

Blueprints.

My proposal to solve these problems is the Blueprints ecosystem. It is composed of the BlueprintManager and Blueprints.

BlueprintManager is an ERC6909 contract (can hold multiple tokens and avoids ERC1155 bloat) that is planned to have a deployment on every EVM network. Blueprints are smart contracts that integrate with it. They manage the creation of tokens. Anyone can create and use Blueprints. They allow for the creation of custom tokens in ways described by their logic – they describe the way created tokens behave; they give them meaning. Blueprints define the "construction" of the token. Blueprints range from simple contracts that just wrap another token standard (e.g. ERC20Wrapper<USDC>), to complex ones that describe tokens with custom logic.

Using Blueprints, we can describe any token. For example, we can describe a European call option in our composable universe by simply writing: EuropeanCallOption<ETH, USDC, 3000, 1 Jan 2025; 12:00 UTC>. These mean the speculative asset (ETH), base asset (USDC), strike price of $3k, and the date of expiry of UTC noon on Jan 1, 2025, respectively. EuropeanCallOption is defined by a Blueprint, which allows owners to exercise it (per option mechanics).

We can use this token further as an argument to construct more sophisticated tokens, for example, I may want to bundle it with another option on the same pair and with the same expiry, but with a $2k strike price. I get:

Basket<[EuropeanCallOption<ETH, USDC, 3000, 1 Jan 2025; 12:00 UTC>, EuropeanCallOption<ETH, USDC, 2000, 1 Jan 2025; 12:00 UTC>], [1, 1]>, where the first array specified which tokens do I want to group, and the second one defined their proportions. This is a basket of options, and I can speculate on volatility by buying/selling it. Owning it is not too interesting – it's no different than owning the underlying tokens, but it gets interesting when we compose it further: we can create a $1000 call option on this basket of options, expiring 1 month before the underlying options!

EuropeanCallOption<Basket<[EuropeanCallOption<ETH, USDC, 3000, 1 Jan 2025; 12:00 UTC>, EuropeanCallOption<ETH, USDC, 2000, 1 Jan 2025; 12:00 UTC>], [1, 1]>, USDC, 1000, 1 Dec 2024; 12:00 UTC>, done!

Now, we can create any token using a few basic primitives. Any of us can add primitives if we're missing one. This is the composability endgame.

Blueprints – technicals.

Nearly all usage of Blueprints should be done through the BlueprintManager. Blueprints have one most significant function for BlueprintManager to invoke: executeAction(bytes). Blueprints are free to interpret the argument however they want, they just have to return 4 arrays of (tokenId, amount) pairs:

With these actions, Blueprints can take and give back collateral, as well as mint and redeem (burn) their own tokens. Users can use a checksum to make sure that Blueprints don't misbehave. Hence, and because the token transfers and balances are managed solely by BlueprintManager, users don't have to trust Blueprints to know that the tokens are working predictably. It's also possible to invoke actions for other users, but the tokens charged from burn and take actions are accounted in line with approval logic – the caller needs to either be an operator for the user or have sufficient allowance that will be decreased.

Additionally, Blueprints have mint() functions available in the BlueprintManager, since it's sometimes useful for that function to be called directly, in case the receiver doesn't need to be charged – this is especially useful for tokens with gated access to minting.

Blueprints – possibilities.

With the above construction of BlueprintManager, one can integrate any token-agnostic infrastructure with it, and forget about the existence of more than one token type.

A few things that can be implemented with Blueprints:

Moreover, systems that use Blueprints instead of their own ERC1155, ERC6909, or even a multi-ERC20 token approach can always use a wrapper to wrap BlueprintManager into an ERC1155 token, ERC20 tokens, or any other kind that is useful for its integrators.

Blueprints – implementation.

A draft of the implementation of the BlueprintManager will be shared shortly.

After that, everyone will be invited to discuss the implementation and design details of the BlueprintManager. All discussions will be public, and everyone will have the opportunity to be considered a contributor to the BlueprintManager codebase.

Further, Blueprints' behavior guidelines will be published. These best practices are designed to improve the security and usability of a Blueprint, not to enforce the security of the whole system.

If you have an idea for a Blueprint, please share it! If you're building a DeFi product and are unsure whether it can be integrated with Blueprints, please reach out! We can help scope (and design) a minimal set of Blueprints that will allow your product to be implemented, and there is a great chance that we can unify liquidity for your product with existing products, or find market makers interested in taking some positions in the protocol. This also means that you can save on smart contract development and auditing costs, and ensure the composability of your product with others!

1

Uniswap v4 architecture is possibly not final.

2

Actually, these conditional tokens were developed by Gnosis; Polymarket uses them.

3

Yeah, many lines of code are comments, but still… Quite a lot of (work and) code that introduces risks – verifying the correctness of the contract is not trivial.

4

I am not criticizing Uniswap's or Euler's design choices, only noticing that something is lacking in new codebases to achieve composability.