Exchanger with constant liquidity(demo)

This exchanger with constant liquidity which has the only dApp as backend.

The algorithm of calculations is extremely simple:

X — amount of token A which dApp has
Y — amount of token A which dApp has
a — you paid with token of sort A
b — payout with token of sort B

X ⋅ Y = const
(X + a) ⋅ (Y - b) = const

First, the account is replenished with assets, information about their number is entered into the account state via Data Transaction. Next, an exchange script is installed on the account:

    {-# STDLIB_VERSION 3 #-}
    {-# CONTENT_TYPE DAPP #-}
    {-# SCRIPT_TYPE ACCOUNT #-}
    let owner =  base58'3PAuNJUgQ1bSdmVwGcWKFRj5nKbEudubQFm'
    let LiquidAssetId = base58'7FzrHF1pueRFrPEupz6oiVGTUZqe8epvC7ggWUx8n1bd'
    let WAVESID = unit
    let comission = 0

    @Callable(contextObj)
    func exchanger(minTokenRecieve: Int) = {       
        let wavesAmount = getIntegerValue(this, "wavesAmount")
        let liquidAmount = getIntegerValue(this, "liquidAmount")
        # check and extract info about payment
        let payment = match(contextObj.payment) {
            case p:AttachedPayment => p
            case _ => throw("Payment not attached")
        }
        let assetIdReceived = payment.assetId
        let tokenReceiveAmount = payment.amount
            # the amount of sent assets are determined in the next block
            if (assetIdReceived == WAVESID)
                then
                (
                    let tokenSendAmount =  (fraction(liquidAmount,tokenReceiveAmount,tokenReceiveAmount + wavesAmount))
                    if(tokenSendAmount < minTokenRecieve) then(throw("Price has changed dramaticaly. Receiving token amount don't satisfy specified price level")) else
                    let assetIdSent = LiquidAssetId
                    # successful execution result is updating information about actual balance and supply into the state and transfer tokens to the caller
                    ScriptResult(
                    WriteSet([DataEntry("liquidAmount", liquidAmount -  tokenSendAmount ),DataEntry("wavesAmount",  wavesAmount + tokenReceiveAmount )]),
                    TransferSet([ScriptTransfer(contextObj.caller, tokenSendAmount, assetIdSent)])
                    )
                )
            else ( if (assetIdReceived == LiquidAssetId)
                then
                (
                    let tokenSendAmount =  (fraction(wavesAmount,tokenReceiveAmount,tokenReceiveAmount + liquidAmount))
                    if(tokenSendAmount < minTokenRecieve) then(throw("Price has changed dramaticaly. Receiving token amount don't satisfy specified price level")) else
                    let assetIdSent = WAVESID
                    # successful execution result is updating information about actual balance and supply into the state and transfer tokens to the caller
                    ScriptResult(
                    WriteSet([DataEntry("liquidAmount", liquidAmount + tokenReceiveAmount  ),DataEntry("wavesAmount", wavesAmount - tokenSendAmount)]),
                    TransferSet([ScriptTransfer(contextObj.caller, tokenSendAmount, assetIdSent)])
                    )
                )
            else throw("Asset is not allowed"))
    }
    @Callable(contextObj)
    func withdraw() =   {
        let LiquidBalance = this.assetBalance(LiquidAssetId)
        let WavesBalance = this.wavesBalance()
        if (contextObj.caller.bytes == owner)
         then (
             ScriptResult(
                    WriteSet([DataEntry("liquidAmount", "withdrawn"  ),DataEntry("wavesAmount", "withdrawn")]),
                    TransferSet([ScriptTransfer(contextObj.caller,LiquidBalance, LiquidAssetId), ScriptTransfer(contextObj.caller,WavesBalance,unit)])
                    )
         )
        else throw("You are not exchanger's owner")
        }

    @Verifier(contextObj)
    func verify() = false
1 Like