Estimate Clipper Prices

In order to assist in integrating Clipper with DEX Aggregators & Resolvers, offchain state information that is used to calculate Clipper prices is made available in a read-only endpoint that can be queried frequently. This state information can then be used to accurately estimate Clipper price quotes when combined with onchain state information (pulled and maintained by the aggregators themselves).

You can view code to see how to implement it, in our section Complete Swap Flow

1. Get pool data

Make a GET call to https://api.clipper.exchange/rfq/pool?chain_id={CHAIN_ID}&fieldset=offchain-data

This endpoint returns a JSON blob that holds Clipper's offchain state information. Note that this response is modified from the standard response to the endpoint by removing any calls to the onchain contracts for response speed.

The API response will look like the following:

{
"pool":
	{"chain_id": 137, "address": "0x6Bfce69d1Df30FD2B2C8e478EDEC9dAa643Ae3B8", "num_assets": 6, "k": 0.15, "default_time_in_seconds": 60},
"assets":
	[
		{"name": "ETH", "address": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", "price_in_usd": 1645.27, "listing_weight": 125},
		{"name": "MATIC", "address": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", "price_in_usd": 0.8834, "listing_weight": 100},
		{"name": "WBTC", "address": "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6", "price_in_usd": 23016.805, "listing_weight": 178},
		{"name": "USDC", "address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", "price_in_usd": 1.0, "listing_weight": 178},
		{"name": "DAI", "address": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063", "price_in_usd": 1.0, "listing_weight": 250},
		{"name": "USDT", "address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", "price_in_usd": 1.0, "listing_weight": 305}
	],
"pairs":
	[{"assets": ["ETH", "MATIC"], "fee_in_basis_points": 4.0}, {"assets": ["ETH", "WBTC"], "fee_in_basis_points": 4.0}, {"assets": ["ETH", "USDC"], "fee_in_basis_points": 8.0}, {"assets": ["ETH", "DAI"], "fee_in_basis_points": 8.0}, {"assets": ["ETH", "USDT"], "fee_in_basis_points": 8.0}, {"assets": ["MATIC", "WBTC"], "fee_in_basis_points": 6.0}, {"assets": ["MATIC", "USDC"], "fee_in_basis_points": 9.0}, {"assets": ["MATIC", "DAI"], "fee_in_basis_points": 10.0}, {"assets": ["MATIC", "USDT"], "fee_in_basis_points": 10.0}, {"assets": ["WBTC", "USDC"], "fee_in_basis_points": 5.0}, {"assets": ["WBTC", "DAI"], "fee_in_basis_points": 5.0}, {"assets": ["WBTC", "USDT"], "fee_in_basis_points": 5.0}, {"assets": ["USDC", "DAI"], "fee_in_basis_points": 1.0}, {"assets": ["USDC", "USDT"], "fee_in_basis_points": 1.0}, {"assets": ["DAI", "USDT"], "fee_in_basis_points": 1.0}]
}

💡 To obtain more details about the endpoint, its parameters, and the response, please refer to the API Reference in the pool section.

2. Estimate Clipper Prices using On- and Off- chain Data

  1. Convert (using decimals) the onchain balances of the Clipper Pool - the quantity vector q - into human-readable terms (i.e., a balance of 100 ETH instead of 1e20 ETH.

  2. Calculate the fee-adjustment multiplier for the swapping pair M = (10000-fee_in_basis_points)/10000 (10,000 = number of basis points in 100%).

  3. Solve for a swap from asset X to asset Y through root-finding or a closed form solution. Let pX, qX, wX, and inX represent the current price, quantity, listing weight, and swap input of asset X, and similarly pY, qY, wY, and outY represent the current price, quantity, listing weight, and swap output of asset Y. Exactly one of inX or outY should be unknown. That unknown quantity is then found by solving an indifference pricing equation relating current utility from the assets X and Y to the utility from those assets after the swap:

(pXqX)1kwXk+(pYqY)1kwYk=(pX(qX+MinX))1kwXk+(pY(qYoutY))1kwYk\frac{(pX \cdot {qX})^{1-k}}{{wX}^k} + \frac{(pY \cdot {qY})^{1-k}}{{wY}^k} \\ = \\ \frac{(pX \cdot ({qX + M\cdot{inX}}))^{1-k}}{{wX}^k} + \frac{(pY \cdot ({qY}-{outY}))^{1-k}}{{wY}^k}

Checks should be done to ensure an intermediate solution to this equation before attempting to solve:

  • If outY is specified:

    • outY should be no larger than qY.

    • The LHS of the formula (current utility) should be larger than the RHS (utility after swap) evaluated at inX=0

    • The LHS of the formula should be smaller than the RHS when evaluated at very large inX

  • If inX is specified:

    • The LHS of the formula (current utility) should not be smaller than the RHS (utility after swap) evaluated at outY=qY

    • The LHS of the formula should be smaller than the RHS when evaluated at outY=0

Closed Formed Solution

In practice, this is the preferred way to solve the equation because it tends to be faster and more consistent. It is more numerically unstable in the worst case since it requires 1/(1-k) exponentiation, but in practice Clipper’s k tends to be small, making 1/(1-k) ≈ 1

  • If inX is specified, then:

outY=qY[((pXqX)1kwXk+(pYqY)1kwYk(pX(qX+MinX))1kwXk)wYk]11kpY{outY} = {qY}-\frac{\left[\left(\frac{(pX \cdot {qX})^{1-k}}{{wX}^k} + \frac{(pY \cdot {qY})^{1-k}}{{wY}^k} - \frac{(pX \cdot ({qX + M\cdot{inX}}))^{1-k}}{{wX}^k} \right)\cdot wY^k\right]^{\frac{1}{1-k}}}{pY}
  • If outY is specified, then:

inX=1M[[((pXqX)1kwXk+(pYqY)1kwYk(pY(qYoutY))1kwYk)wXk]11kpXqX]{inX} = \frac{1}{M}\cdot\left[\frac{\left[\left(\frac{(pX \cdot {qX})^{1-k}}{{wX}^k} + \frac{(pY \cdot {qY})^{1-k}}{{wY}^k} - \frac{(pY \cdot ({qY}-{outY}))^{1-k}}{{wY}^k}\right)\cdot {wX}^k\right]^{\frac{1}{1-k}}}{pX}-{qX}\right]

Root Finding

A good initial guess (for a Newton method solver) for inX or outY is the FMV of the other value.

  • If inX is specified, then try:

outYMinXpX/pYoutY \approx M \cdot inX \cdot pX/pY
  • If outY is specified, try:

inX(outYpY)/(MpX)inX \approx (outY \cdot pY) / (M*pX)

In practice, the actual Clipper price quote will also depend on the amount of time the quote is alive for, as well as the most recent price update. These should result in only small changes from the estimated quotes produced by this process.

Final Check: Output Value No Larger than Input Value

Finally, we enforce that the FMV (according to our price_in_usd values) of the contributed input is at least the FMV of the output. This constraint will typically only bind when the Clipper pool is very far off target allocations, since in general fees plus slippage will be sufficient to ensure the condition.

If inX was specified and outY has been calculated to solve the formula, then as a final check:

outYmin[outY,(inXpX)/pY]outY \equiv \min\left[outY, (inX \cdot pX) / {pY} \right]

If outY is specified and inX has been calculated to solve the formula, then as a final check:

inXmax[inX,(outYpY)/pX]inX \equiv \max\left[inX, (outY \cdot pY) / {pX} \right]

Note that these tests are done without regard to fees.

Last updated