blog
We are excited to open source the RMM SDK, a developer tool that makes it easier to build on top of the RMM protocol.
Interacting with any web3 protocol comes with hurdles: parsing on-chain data, modeling smart contract state, and displaying information in a clear way. This developer kit exposes several "entities", which are models of the smart contracts, and "managers" to help construct transactions (but not execute them!). Use the SDK to easily tap into the RMM protocol, derive useful information for users, and safely build transactions for them.
The Primitive team is using the SDK to build an innovative liquidity product on top of RMMs, and now anyone can do that with it being open source. The RMM protocol is designed to be maximally composable through its oracle-less, dependency minimized architecture. These are some of the straightforward use cases for the app layer of RMMs:
Tools like this will be used to increase adoption of these unique liquidity tokens for everyone using Primitive, from liquidity staking to volatility harvesting vaults. This SDK remains narrowly focused on the main smart contracts, while being powerful enough to build several products from it.
We have an open server with specific channels for discussing products:
Comprehensive documentation of the sdk is here.
These products all need to tap into a property of the Primitive pool's underlying math, whether that is calculating amounts for swaps, or computing the deterministic pool ids that are dependent on curve parameters. There are three typescript classes which are used as models to make this easily accessible:
The Engine entity is utilized to deterministically compute the address for pairs, the smart contract called "Primitive Engine". It needs the Primitive Factory address and the two token addresses to be instantiated, that's it!
Calibration extends the Engine, enabling a pool id to be deterministically computed based on the parameters:
These two entities are designed to be stateless, i.e. they are not instantiated with on-chain data, only the parameters, token addresses, and Primitive Factory address.
The Pool goes further with extending the Calibration, but it can also be instantiated from on-chain data. This pool models the entire state of a pool: its reserves, invariant, and calibration parameters. Along with it, the model exposes useful functions to derive information for users, e.g. amount much liquidity they receive for when providing an amount of tokens.
A simulated pool model can be instantiated using fromReferencePrice
. The user must pass in a referencePrice
of the asset to infer what the reserves would be. This can be useful to determine the arguments for creating pools or allocating liquidity to a new pool based on its parameters, rather than on-chain state.
If a user were to create a new pool, they should be asked for a reference price, which can then be used to instantiate the pool's theoretical reserves. From this, the optimal amounts of liquidity to add can be computed, and then the transaction could be constructed.
An easy way to build the Pool entity is available through the peripheral contracts. The Primitive Manager smart contract has a function uri
which accepts a poolId
as an argument. Calling this will return some encoded json data, which can be decoded and then passed directly to the Pool entity's from
method, returning a Pool entity that's "synced" to the same block as the uri
call.
This is the optimal way to instantiate the pools, as a bundle of uri
calls can be batched in a multicall.
Along with the entities are "managers". These expose easy functions to encode function selectors and arguments to build a transaction's calldata.
This class is designed to match the Primitive Manager smart contract's public functions. Primitive Manager inherits a Multicall contract, making it possible to bundle several transactions to the Primitive Manager in a single transaction.
For example, a "zap" is a way to provide liquidity to a two-or-more token pool with only one token. How it works: some of the tokens are first swapped to the token of the other side(s) of the pool, and then all the tokens are provided as liquidity. With multicall, its possible to do this without an on-chain function!
It takes two steps:
There are nuances here, but that's the general idea.
Each of the static methods on the PeripheryManager expose an easy way to build ready-to-send transaction payloads to the on-chain PrimitiveManager contract. Mix and match these methods to build all kinds of useful functions!
Here are some ideas:
The factory contract only has a single function deploy
. This manager has a static method to encode this function selector with two token addresses, which will deploy a new PrimitiveEngine contract.
This SDK relies on an ethers.js wrapper: web3-units.
Along with that, it uses the Uniswap Token Entity from their sdk-core package.
Primitive pools have a trading function, which the Pool entity computes using the typescript implementation in rmm-math.
Go tell your friends about the oracle-free derivative protocol launching soon with concentrated and fungible liquidity.
To meet the rest of us, join the discord: