One of the main goals of Partitura is to provide the best user experience and the opportunity to use blockchain composability for any type of user, regardless of their experience level - whether they are an experienced "degen" or a beginner. During R&D, we realized that the problem is not so much with the integration of all protocols, but with how to avoid overwhelming users with the abundance of options and not confusing them. We wanted to find the ultimate solution for basic DeFi blocks, such as swap, earn, transact.*, etc.*And a lot of people mentioned ‘intents’ during our conversations so we decided to dive deeper into the topic and were surprised at how it can be useful and how deep the rabbit hole is.
From our point of view, intents are the user's expressed intentions for completing an action. The desired result describes the intent, which may include input data or a state (e.g., "I have A"), and may indicate the process for executing the action.
From a technical point of view, an intent is a signed message (order) that describes the output state and the intention "I want B," without specifying the exact set of actions or transactions. The execution of the order is assigned to pathfinders - autonomous agents whose task is to efficiently fill intents with a set of actions that lead to the user's desired result based on the input data.
The result of their work is a route or resolution - a set of actions or transactions that lead to the user's desired intention.
In simple terms, a transaction is a specific action that results in a state change, which may not always lead to the desired outcome or may only partially achieve it. For example, the transaction erc20.approve
is not generally the user's ultimate goal, but rather a supporting transaction that includes a set of actions.
An intent's resolution is a set of transactions that lead to a specific desired outcome for the user. For instance, the combination of two transactions dai.approve
and router.swap
is the resolution when the intent is to "swap DAI on ETH."
The paradigm shift from transaction-based to intent-based has already begun, and one of the places where we can see the changes is in swaps. So, let's take a look at different approaches to swapping tokens.
In the typical scenario of swapping token A for token B through the A/B pool, it is not a complete intent (unless the user intentionally wants to make an exchange through a specific pool) since it may not provide the user with the most efficient route. We can consider this approach a transaction-based method.
With the advent of routers, exchanging tokens has become more efficient through the calculation of routes among all possible liquidity pools. In this case, the user's intent is described as "swap token A for token B," and an application finds the most optimal route.
In addition, certain assets can be derived from other tokens (such as wETH, wstETH, cTokens, and aTokens) and may not be represented in pools.
In this case, the most efficient approach may involve not only liquidity pools, but also other protocols.
Off-chain order books existed before Automated Market Makers (AMM) and can be considered as the first intent-based solution because their form of order is similar to how intents can look. In the off-chain order book model, a user signs a message containing the description of their intention. For a long time, this approach wasn't efficient, and we eventually got the AMM model. However, the real power of this approach is only realized in collaboration with on-chain liquidity. In cases where an order can be fulfilled with another order, pathfinders can replace it with an AMM swap.
By combining all of these approaches, we can derive the most efficient method for swapping token A with token B, which may include several other intents. As we can see, even a simple action like a swap can be executed in three different ways. Furthermore, each of these ways can involve different protocols, multiple off-chain order books (such as CoW Swap, 1inch fusion, UniswapX), and various automated market maker (AMM) pools (like Uniswap and Curve). This complexity makes the process more confusing, especially when trying to calculate the most gas-efficient approach.
Following the last two cases we can notice that there is something what helps to find optimal routes or match orders. Different protocols call this process different (solving/resolving/filling) So we will call it pathfinding. And paths for intents can be found in different ways and on different levels:
If the route is calculated on the client side before a user signs or executes any action, this is considered client-side resolution. It does not matter whether the route is calculated on the frontend or obtained from an API. The key characteristic is that the user receives the resulting route, and this route cannot be changed during execution.
An example of this can be seen in any Swap-like decentralized exchange: when a user inputs data, the dApp shows the calculated route and re-calculates it every N-seconds. The route is included in the transaction data and cannot be changed after the user signs the transaction.
This solution is cost-effective in terms of calculation and gas. However, it may not be the most optimal approach since signing and broadcasting take time, and conditions can change at the time of execution, resulting in a non-optimal route. Moreover, this approach can be exploited with MEV. If the route can be calculated on the frontend without using third-party APIs, it would make this approach more fault-tolerant.
Another approach is to find the solution for the user's intent after they have signed it. This method is used by CoW Swap, 1inch Fusion, and UniswapX in the context of swaps. In this case, the user's intention to "Swap A on B" will be matched with the opposite intention to "Swap B on A" by the pathfinder and executed together.
This approach may require more off-chain resources, but it can be more effective, less susceptible to manipulation, and can require fewer on-chain operations in the context of swaps. However, this scheme cannot function without a third-party pathfinder, which makes it dependent and less fault-tolerant.
The last approach is not using in swaps due to its inefficiency in this context but there are other types of intents with are suitable for such pathfinding so we have to mention it for the full picture.
Let’s sum up the information below and get the ultimate way to find the best way for the user’s swap intent:
And see that even a simple action can be resolved in different ways, include different pathfinding types and the result can contain more that one transaction which should be executed at the same time. So we considered only one case but there are much more challenges with other intents such as earn, borrow, transact, etc.
Keep in touch!