SIP272: Atomic Swaps  Dynamic Fees
Author  

Status  Approved 
Type  Governance 
Network  Ethereum 
Implementor  TBD 
Release  TBD 
Proposal  Loading status... 
Created  20220817 
Simple Summary
This SIP proposes to incorporate dynamic fees into the atomic swap methodology.
Abstract
The dynamic fee model can be calibrated to fit the slippage function of any designated order book, hence higher fees would be levied as per the directional flow of the trade, resulting in more compensation to snx stakers when they take on larger positions. The calibrated dynamic model takes the following form:
$$ G(x,y) = 2 \frac {\frac{2}{3} u_0 (x ^ {3/2}  y^ {3/2} ) + \frac{1}{2} u_1 (x^2  y^2)}{x  y} $$
 cumulative trade volume in USD is updated at each interaction, where trades into synth increase
cumulativeVolume
and out of synth lowers the amount  $x$ is the posttrade and $y$ the pretrade cumulative volume in USD
 In case cumulative volume flips signs, due to a significant trade in the opposing direction, then $G(x,0)$ is used to compute the fee
 All trades will have to route through
sUSD
 The frequency by which
cumulativeVolume
resets is configurable via SCCP, denotedatomicKBlocks
 $u_{0}$ and $u_{1}$ are calibrated offchain for each synth, as shown in this repo
Motivation
The Synthetix protocol spot trading product is an attempt at being a market maker that offers trading through the use of an oracle reading. This is different from the approach offered by most other AMMs, which in contrast use the composition of liquidity pools in order to gauge a price and subsequently incorporate slippage into the trade in order to compensate LPs.
The usage of oracle sources to execute a fill results in the Synthetix protocol being a constant target of latency arbitrage aimed at picking off advantageous pricing. To compensate, fees have been increased to a point at which the product itself failing at its mission of offering a venue for cheap spot trading. Though latency is as much of a problem for amm's as it is for Synthetix, the difference lies in AMM fees from small random trades which more make up for the capital losses incurred by price adjustments; as well as the slippage incorporated ensuring these lp price adjustments are efficient.
From Synthetix's perspective, attempts at this tackling this problem have sought to maintain a no slippage policy at the protocol level. The Fee reclamation mechanism tackles the latency issue but breaks composability and is unattractive due to the extreme uncertainty on price execution that it causes. The second iteration was the original atomic mechanism, which uses univ3 as an additional lively oracle source. Although uniswap is a very effective lowlatency oracle source, it still suffers from the impact of a 1 block delay. This opens up a small gap for oracle frontrunning. Hence, this sips aims at addressing this issue while giving the protocol ability to fine tune execution based on the volatility of the synth.
Function Derivation
The function that would be used to fit an order book curve takes the following form:
$$ f(x) = u_0 \sqrt x + u_1 x $$
However, given the necessity to ensure that the curve is size of volume flow invariant, then the integral, F(x) is used. F(x) represents the area under the slippage curve and is not affected by the size of an individual trade. Hence the weighted average fee can be computed with, F(x)/x
for executing a trade when cumulative volume goes from 0
to x
. However to make the outputted numbers quasiequivalent to those obtained via f(x)
, 2F(x)/x
is used as the base function for querying dynamic fees.
Deriving the fee that pushes cumulative volume from y
to x
is then obtained with the function G(x,y)
found under the abstract section which is a simple transformation of F(x)/x
.
Proof Of Concept
In order to showcase the model's ability to replicate order books of any form this figure is used, where we show the slippage incurred when executing orders of different sizes in different markets:
 The x axis represents the market order amount in dollar millions
 The y axis is the slippage in bp for different order book and models of order books, calculated by computing the delta between best prevailing spot price and the average price expected from executing an order of a certain magnitude (shown in the xaxis).
 The
uni 5bp
line is the slippage incurred when trading on the Uniswap 5 bp ETH/USDC pool  The
cex
is the slippage incurred from trading on the binance ETH/USDT orderbook.  The dashed lines, represent the modeled curves, fitted based on the
uni5bp
andcex
order books data.
The proposed model can replicate any order book to a certain degree of precision with the help of the least squares optimization algorithm, an implementation demonstrating this capability is available in this repository.
It is important to mention that a no slippage policy can be still configured into a specific synth, simply by setting the functional parameters (u0
, u1
) to zero.
The table below displays the slippage incurred when trading on the uniswap5bp
pool and on the binance ETH/USDT
pool and the dynamic fees executed with the calibrated models that replicate those order books:
Trade  uni  uni_model  cex  cex_model 

$25,000  0.00  0.33  0.00  0.27 
$525,000  6.72  6.89  4.39  5.40 
$1,025,000  13.44  13.51  8.14  10.20 
$1,525,000  20.21  20.18  12.77  14.67 
$2,025,000  27.03  26.89  17.63  18.81 
$2,525,000  33.90  33.66  17.63  22.62 
$3,025,000  40.81  40.47  24.68  26.11 
$3,525,000  47.79  47.34  26.94  29.26 
$4,025,000  54.85  54.25  26.94  32.08 
$4,525,000  61.99  61.22  26.94  34.58 
$5,000,000  68.83  67.88  26.94  36.64 
A interactive copy of the slippage expected with the uni parameters can be found in this link
Specification
The specification includes the following fundamental sections:
 Dynamic Fee Computation Workflow
 Cumulative Volume Structure
 Pricing Methodology
 Functional Parameter Structure
 Dynamic Fee Bounds
Dynamic Fee Computation Workflow
The dynamic fee computation can be found in this workflow:
 block number delta refers to the delta between the current onchain blocknumber and the one saved in the
cumulativeVolume
structure for the synth being traded into or out of x
,y
and the functionG(x,y)
are the variables referred to in the Abstract section
Cumulative Volume Structure
cumulativeVolume
is a nested structure that takes the following form:
{currencyKey:
{'blockNumber': blockNumber,
'cumulativeVolume':cumulativeVolume}}
Each time someone trades a synth, volume traded in USD
terms is computed using the price obtained with the atomicPrice
methodology denoted in SIP158. Note that usage of the price incorporating directionality of the source currencyKey being sUSD and destination currencyKey the synth being traded into is preferable.
The following logic is then applied when updating the structure:
 In situations in which more than
atomicKBlocks
blocks have passed since the last time the structure is updated, then thecumulativeVolume
is first reset to zero for that synth, before being updated with the latest volume being traded.  otherwise, the
cumulativeVolume
is updated cumulatively for thesynth
being traded into or out from. In case the direction of the trade is into a synth fromsUSD
the number incorporated into structure is a positive number, otherwise it's a negative number. Hence trades within the sameatomicKBlocks
blocks in different direction cancel out the the dynamic fee applied.
Functional Parameters
functionalParameters
is a nested structure that takes the following form:
{currencyKey:
{'u0': u0,
'u1': u1}}
The parameters are saved in a structure and configurable via SCCP per currencyKey
Pricing Methodology
The exchange would take place with the following computation, assuming a cumulativeVolume
y, having the same sign as x and a price P
of the synth in USD terms:
 if the sourceCurrencyKey is
sUSD
:
$$
SrcAmount * \frac{1}{P} * [1  baseFee  G(x,y)] => DestAmount
$$
 Otherwise:
$$ SrcAmount * P * [1 baseFee  G(x,y)] => DestAmount $$
Dynamic Fee Bounds
Dynamic fee are bounded between 0 and a variable specified via SCCP, denoted maxAtomicDynamicFee
Fee Pool Distribution
The dynamic fee will be sent to the fee pool (or burned depending on the implementation of SIP255) upon every atomic exchange. Hence, the fee pool should receive SourceAmount*Price*(baseFee + dynamicFee)
upon execution of a trade.
Technical Specification
Pending SC engineers input.
Test Cases
System Configurations:
kBlocks
: 1 Current
cumulativeVolume
structure:
{'sETH':
{'blockNumber': 10,
'cumulativeVolume':0}}
functionalParameters
structure as calibrated here foruni_slippage
:
{'sETH':
{'u0': 1.314892e03,
'u1': +1.434469e05}}

atomic baseFee set to 0

G(x,y) can be simulated with the help of this spread sheet.
Trade Example 1:

At blockNumber 10, Swap 1m sUSD to sETH with atomic price at 1,600$ per ETH

Is block number delta (i.e. 0) larger than kBlocks >> False

Set
a) y = 0
b) x = 1m$

Is Sign of x (1m$) is different from sign of y (0) >> True

Compute dynamic Fee as G(1m,0):
$$ G(1m,0) = 2 \frac {\frac{2}{3} * (1.314892 * 10^{3}) * (1m ^ {3/2}  0^ {3/2} ) + \frac{1}{2} * (1.434469 * 10^{5}) * (1m^2  0^2)}{1m  0} => 12.59 bp $$
 Send user 1m / 1600 * (112.59 bp) = 624.21 sETH


At blockNumber 11, Swap 624.21 sETH to sUSD with atomic price at 1,600$ per ETH

Is block number delta larger than kBlocks >> True

Set
a) y = 0 (reset)
b) x =  624.21 sETH * 1600 =  998,736$
c) update latest blocknumber to 11

Is Sign of x ( 998,736$) is different from sign of y (0) >> True

Compute dynamic Fee as G(998,736,0): 12.59 bp

Send user 624.21 * 1600 * (112.59 bp) = 997,479 sUSD

Trade Example 2:

At blockNumber 10, Swap 100k sUSD to sETH with atomic price at 1,600$ per ETH

Is block number delta larger than kBlocks >> False

Set
a) y = 0
b) x = 100k$

Is Sign of x (100k$) is different from sign of y (0) >> True

Compute dynamic Fee as G(100k,0): 0.88 bp

Send user 100k / 1600 * (10.88 bp) = 62.494 sETH


At blockNumber 10, Swap 30 sETH with atomic price at 1,600$ per ETH

Is block number delta larger than kBlocks >> False

Set
a) y = 100k$
b) x = 100k$  30 * 1600 = 52k$

Is Sign of x (52k$) is different from sign of y (100k$) >> False

Compute dynamic Fee as G(52k$,100k$): 2.63 bp

Send user 30 * 1600 * (12.63 bp) = 47,987 sUSD


At blockNumber 10, Swap 40 sETH with atomic price at 1,600$ per ETH

Is block number delta larger than kBlocks >> False

Set
a) y = 52k$
b) x = 52k$  40*1600 = 12k$

Is Sign of x (12k$) is different from sign of y (52k$) >> True

Compute dynamic Fee as G(12k$,0): 0.47 bp

Send user 40 * 1600 * (10.47 bp) = 63,997 sUSD

Configurable Values (Via SCCP)
 $u_{0}$ and $u_{1}$ can be configurable per synth, allowing the Spartan Council to finetune slippage based on the asset in mind.
atomicKBlocks
would also be configurable per synth, specifying the number of block intervals at which slippage resetsmaxAtomicDynamicFee
Copyright
Copyright and related rights waived via CC0.