Skip to content

Instantly share code, notes, and snippets.

@BlinkyStitt
Last active October 30, 2019 05:47
Show Gist options
  • Save BlinkyStitt/f74644300bcfa5b0968b8b8d8c2b0286 to your computer and use it in GitHub Desktop.
Save BlinkyStitt/f74644300bcfa5b0968b8b8d8c2b0286 to your computer and use it in GitHub Desktop.
I wrote out some solidity as some psuedocode to figure out how to do https://github.com/Synthetixio/synthetix/issues/295
I'll convert this to actual web3 calls instead of solidity once I'm sure I have all the right order of operations.
How does this look?
```solidity
function maximumRewardedArb() public view
rateNotStale("ETH")
rateNotStale("SNX")
notPaused
returns (uint max_eth_to_convert, uint tokens_bought, uint reward_tokens)
{
/* Ensure there is enough more sETH than ETH in the Uniswap pool */
uint seth_in_uniswap = synth.balanceOf(uniswapAddress);
uint eth_in_uniswap = uniswapAddress.balance;
require(eth_in_uniswap.divideDecimal(seth_in_uniswap) < uint(divisor-off_peg_min).divideDecimal(divisor), "sETH/ETH ratio is too high");
/* Get the amount of ETH needed to restore the peg */
uint max_eth_to_convert = maxConvert(eth_in_uniswap, seth_in_uniswap, divisor, divisor-off_peg_min);
/* Get the amount of sETH that will be purchased for that max amount of ETH */
uint tokens_bought = uniswapExchange.getEthToTokenInputPrice(max_eth_to_convert);
/* Get the amount of SNX that should be rewarded */
uint snx_rate = exchangeRates.rateForCurrency("SNX");
uint eth_rate = exchangeRates.rateForCurrency("ETH");
reward_tokens = eth_rate.multiplyDecimal(tokens_bought).divideDecimal(snx_rate);
/* Check reward */
let snx_in_rewarder = synthetix.balance(self);
if snx_in_rewarder < reward_tokens {
/* there isn't enough SNX available to pay the full reward. what should we do? Calculate a new tokens_bought based on snx_in_rewarder? */
}
(max_eth_to_convert, tokens_bought, reward_tokens)
}
```
While writing this, I noticed a few things:
* arbSynthRate calls "transfer" without checking the returned value
* I think arbSynthRate can call "transfer" with too many tokens. If transfer is called with too large of a number, what happens? Does some transfer happen, or does none of it happen?
@BlinkyStitt
Copy link
Author

BlinkyStitt commented Oct 30, 2019

I think this is better:

function maximumRewardedArb() public view
    rateNotStale("ETH")
    rateNotStale("SNX")
    notPaused
    returns (uint max_eth_to_convert, uint tokens_bought, uint reward_tokens)
{
    /* Ensure there is enough more sETH than ETH in the Uniswap pool */
    uint seth_in_uniswap = synth.balanceOf(uniswapAddress);
    uint eth_in_uniswap = uniswapAddress.balance;
    require(eth_in_uniswap.divideDecimal(seth_in_uniswap) < uint(divisor-off_peg_min).divideDecimal(divisor), "sETH/ETH ratio is too high");

    /* calculate the sETH we have to buy to be rewarded all of the SNX in this contract */
    uint snx_in_rewarder = synthetix.balance(self);
    uint snx_rate = exchangeRates.rateForCurrency("SNX");
    uint eth_rate = exchangeRates.rateForCurrency("ETH");

    uint tokens_to_buy = snx_rate.multiplyDecimal(snx_in_rewarder).divideDecimal(eth_rate);

    /* calculate the ETH we have to send to receive all of the SNX in this contract */
    uint eth_to_convert = uniswapExchange.getEthToTokenOutputPrice(tokens_to_buy);

    /* Get the amount of ETH needed to restore the peg */
    uint eth_to_restore_peg = maxConvert(eth_in_uniswap, seth_in_uniswap, divisor, divisor-off_peg_min);

    /* if buying this much eth would break the peg, reduce eth_to_convert and recalculate */
    if eth_to_convert > eth_to_restore_peg {
        eth_to_convert = eth_to_restore_peg;

        tokens_to_buy = uniswapExchange.getEthToTokenInputPrice(eth_to_convert);
    }

    reward_tokens = eth_rate.multiplyDecimal(tokens_to_buy).divideDecimal(snx_rate);

    (eth_to_convert, tokens_to_buy, reward_tokens)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment