There should be a standard interface for financial primitives that abstracts away the token accounting logic and leaves only the business logic instead. To be specific, “accounting logic” consists of moving tokens between accounts, whereas “business logic” is computing how many tokens need to be moved. All financial primitives (like AMMs, lending pools, or NFT markets) require both types of logic. However, while the business logic is unique to each primitive, the accounting logic is always the same: a user gives tokens to the primitive, and the primitive gives tokens to the user. That means it’s possible to generalize the accounting logic for all financial primitives.
The purpose of this standard would be to create a universal accounting interface that could apply to any kind of financial primitive. Let’s define a financial primitive as something that takes a token as input and then gives back another token as output. In other words, it converts one form of value into another form of value.
If all primitives used a standardized accounting interface, then general accounting frameworks could live elsewhere—as independent smart contracts that handle the token accounting on behalf of various DeFi protocols. This architecture would make financial primitives more modular and hence make it easier to compose primitives, because any accounting framework could bundle token accounting across independent primitives.
Here is an example of what the interface could look like:
interface IFinancialPrimitive {
function computeOutputAmount(
uint256 inputToken,
uint256 outputToken,
uint256 specifiedAmount,
address userAddress,
bytes32 metadata
) external returns (uint256 outputAmount);
}
Here’s some examples of how it would be used for different types of primitives:
AMM:
inputToken
= DAI
outputToken
= USDC
specifiedAmount
= 100
userAddress
= [not needed]
metadata
= [slippage protection]
In this example, we are telling the AMM that Alice wants to swap 100 DAI for USDC. The AMM will then compute the amount of USDC to trade, and return ~99.9 as an outputAmount
.
Next, an accounting system (living in an external contract) would move the 100 DAI and 99.9 USDC to the appropriate wallets.
Lending pool:
inputToken
= DAI
outputToken
= aDAI
specifiedAmount
= 100
userAddress
= Alice
metadata
= [deposit, lend, or borrow]
In this example, we are telling the lending pool that Alice wants to lend 100 DAI and receive aDAI, a yield-bearing fungible token redeemable for DAI. The lending pool will compute the amount of aDAI to mint.
Next, an accounting system would move the 100 DAI and mint aDAI.
The idea for this standard came out of Shell Protocol, which partly relies on disentangling token accounting from the business logic of financial primitives. If you want to understand the context better, we go into depth about these ideas in the Shell v2, part 2 white paper, especially Section 4.1. You can also check out our reference implementation of a general accounting framework (an example of something that would interface with standardized primitives) and in particular the primitive interface (contracts/IOceanPrimitive.sol).
I’m looking for feedback before we propose an ERC. Thoughts and comments are much appreciated!