Primitive RMM SDK
0x801D
December 31st, 2021
tags: 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:

  • Structured Products
  • Vault Strategies
  • Swapping

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.

Discord

We have an open server with specific channels for discussing products:

For Developers

Comprehensive documentation of the sdk is here.

Entities

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:

  • Engine entity
  • Calibration entity
  • Pool entity

Engine Entity

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 Entity

Calibration extends the Engine, enabling a pool id to be deterministically computed based on the parameters:

  • strike price (in wei)
  • implied volatility (sigma)
  • maturity (expiry date)
  • gamma (100% - swap fee %)

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.

Pool Entity

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.

Simulating Pools

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.

Creating Pools

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.

Creating the Pool Entity

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.

Managers

Along with the entities are "managers". These expose easy functions to encode function selectors and arguments to build a transaction's calldata.

Periphery Manager

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.

Multicall Example

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:

  • Given an amount of $ value to provide, denominated in one token, compute amount of liquidity tokens that could be minted (i.e. $ to provide / $ value per liquidity token)
  • Given an amount of LP tokens, compute how much of each side of the pool is required
  • Compute the amount needed to swap to get the other side of the pool
  • Add the swap transaction to an array of calldata
  • Push the allocate liquidity calldata to the same array
  • Wrap the calldata in a multicall!

There are nuances here, but that's the general idea.

Encoding function data

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:

  • Roll positions (update a liquidity position from one expiration to another)
  • Single-asset liquidity provision (zaps)
  • Distribute liquidity across curves at different implied volatilities
  • Tokenless AMM

Factory Manager

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.

Dependencies

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.

Helpful links

Community

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:

Published on Mirror

Published on Primitive Blog

Learn More

Visit the website

Visit the docs

Follow Primitive on twitter

Arweave TX
XubOUHOsvt3pMBTE5BBSDKwH5RworGcMdV1aDJwl80g
Ethereum Address
0x801D5e44960C5934181B04290Ec7F6A27d96cFF1
Content Digest
719kLkcROTWn7w1pv6ZI8jtQDVg0DEECCPp0PXsXM-Y