BSV 区块链上的 DeFi :Uniswap

Posted sCrypt 智能合约

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BSV 区块链上的 DeFi :Uniswap相关的知识,希望对你有一定的参考价值。

Uniswap

Uniswap 是所谓的 Decentralized Exchange,它允许个人或称为流动性提供者,将 Token 汇集到智能合约中提供流动性。

概述

我们实现了 Uniswap V1,它只在 BSV 和 Token 之间直接交换。如@state 装饰器所示,我们使用一个带有 @state 装饰器 的有状态合约来表示池子。它包含两个 Token :一个用于我们正在交换的 Token (第 7 行),另一个是治理 Token (第 11 行),称为流动性池(LP) Token 。该池将 BSV 直接存储在 UTXO 中(以 satoshis 为单位),将 Token 存储在对应的公钥哈希下(第 3 行)。

contract Uniswap 
    // pool's public key
    PubKey poolPubkey;

    // the main token
    @state
    ERC20 token;

    // the liquidity pool governance token
    @state
    ERC20 lpToken;

    ...

Uniswap 合约源代码

增加流动性

任何人都可以通过调用函数 addLiquidity 向池中添加流动性。有两种情况(在第 9 行检查):

  1. 首次增加流动性:可以存入任意数量的 BSV 和 Token 。
  2. 添加更多流动性: BSV 和 Token 存入的比率必须与池中的现有比率相匹配(第 22 行)。
// add bsv and token to liquidity pool
public function addLiquidity(PubKey sender, Sig senderSig, int tokenAmount, int senderBalance, int senderKeyIndex, int oldTokenBalance,
                            int lpSenderBalance, int lpSenderKeyIndex, int newBsvBalance, SigHashPreimage txPreimage) 
    require(checkSig(senderSig, sender));

    int oldBsvBalance = SigHash.value(txPreimage);
    
    // mint new lp tokens for the liquidity provider
    if (oldBsvBalance == 0) 
        // initialize pool
        
        // initially, just mint new lp tokens per the amount of new bsvs deposited
        int lpMint = newBsvBalance;
        require(this.lpToken.mint(sender, lpSenderBalance, lpMint, lpSenderKeyIndex));
     else 
        // add more liquidity

        int bsvAmount = newBsvBalance - oldBsvBalance;
        
        // deposit ratio must be the same with current pool ration
        // i.e., oldBsvBalance / oldTokenBalance == bsvAmount / tokenAmount
        require(oldBsvBalance * tokenAmount == bsvAmount * oldTokenBalance);

        // mint new lp tokens, proportinal to the amount of new bsvs deposited
        int lpMint = this.lpToken.totalSupply() * bsvAmount / oldBsvBalance;
        require(this.lpToken.mint(sender, lpSenderBalance, lpMint, lpSenderKeyIndex));
    

    // transfer tokens to the pool
    require(this.token.transferFrom(sender, this.poolPubkey, tokenAmount, senderBalance, senderKeyIndex, oldTokenBalance, senderKeyIndex));
    
    require(this.propagateState(newBsvBalance, txPreimage));

存入 BSV 后,新的 LP Token 在第 26 行按比例铸造给流动性提供者。 Token 在第 30 行转移到池子对应的账户。

例如,如果池中有 10 个 BSV 和 100 个 LP Token ,而 Alice 又向其中存入了 5 个 BSV ,则将向她铸造 50 个新的 LP Token 。

移除流动性

流动性提供者调用函数 removeLiquidity 来提取他们的资金,包括 BSV 和 Token 。

// remove bsv and token from liquidity pool
public function removeLiquidity(PubKey sender, int lpAmount, Sig senderSig, int oldTokenBalance, int senderKeyIndex, int senderBalance,
                                int lpSenderBalance, int lpSenderKeyIndex, SigHashPreimage txPreimage) 
    require(checkSig(senderSig, sender));

    int oldBsvBalance = SigHash.value(txPreimage);
    
    // withdraw amount
    int bsvAmount = oldBsvBalance * lpAmount / this.lpToken.totalSupply();
    int tokenAmount = oldTokenBalance * lpAmount / this.lpToken.totalSupply();

    // burn the lp tokens
    require(this.lpToken.burn(sender, lpSenderBalance, lpAmount, lpSenderKeyIndex));

    // transfer tokens from pool to the sender
    require(this.token.transferFrom(this.poolPubkey, sender, tokenAmount, oldTokenBalance, senderKeyIndex, senderBalance, senderKeyIndex));
    // transfer bsvs to the sender
    int newBsvBalance = oldBsvBalance - bsvAmount;
    
    require(this.propagateState(newBsvBalance, txPreimage));

流动性提供者拥有的 LP Token 的数量来提取流动性(第 9 行和第 10 行)。提款后,LP Token 在第 13 行被烧毁。第 16 行将 Token 从池子中转移到流动性提供者。第 18 行和第 20 行对 BSV 做同样的事情。

请注意,除了合约输出之外,还需要在同一交易中的另一个输出将 BSV 返回给流动性提供者。

BSV -> Token

用户调用函数 swapBsvToToken 将 BSV 兑换成 Token 。在池子收到 BSV 后(在第 7 行计算),第 10 行计算要返回的 Token 数量,第 13 行将它们返回给用户。

// swap bsvs for tokens
public function swapBsvToToken(PubKey sender, int tokenAmount, Sig senderSig, int oldTokenBalance, int senderKeyIndex, int senderBalance,
                                    int newBsvBalance, SigHashPreimage txPreimage) 
    require(checkSig(senderSig, sender));

    int oldBsvBalance = SigHash.value(txPreimage);
    int bsvAmount = newBsvBalance - oldBsvBalance;

    // calculate tokens in return
    int tokensAmount = this.getAmount(bsvAmount, oldBsvBalance, oldTokenBalance);

    // transfer tokens from pool to the sender
    require(this.token.transferFrom(this.poolPubkey, sender, tokensAmount, oldTokenBalance, senderKeyIndex, senderBalance, senderKeyIndex));

    require(this.propagateState(newBsvBalance, txPreimage));

Token -> BSV

用户调用函数 swapTokenToBsv 将 Token 兑换成 BSV 。第 9 行计算要返回的 BSV 数量。第 13 行将 Token 转移到池子中。

// swap tokens for bsvs
public function swapTokenToBsv(PubKey sender, int tokenAmount, Sig senderSig, int senderBalance, int senderKeyIndex, int oldTokenBalance,
                            int lpSenderBalance, SigHashPreimage txPreimage) 
    require(checkSig(senderSig, sender));

    int oldBsvBalance = SigHash.value(txPreimage);

    // calculate bsvs in return
    int bsvsAmount = this.getAmount(tokenAmount, oldTokenBalance, oldBsvBalance);
    int newBsvBalance = oldBsvBalance - bsvsAmount;

    // transfer tokens to the pool
    require(this.token.transferFrom(sender, this.poolPubkey, tokenAmount, senderBalance, senderKeyIndex, oldTokenBalance, senderKeyIndex));        
    
    require(this.propagateState(newBsvBalance, txPreimage));

removeLiquidity 类似,需要另一个输出来将 BSV 返回给用户。

讨论

我们已经演示了如何在 BSV 区块链上实现一个基本的类似 Uniswap 的合约。有很多方法可以扩展它以使其更实用。

  • 价格公式:我们使用以下代码来确定价格,仅基于 BSV 和 Token 储备。它被称为恒定和公式,可能导致池子被排空。为了避免耗尽,可以使用更复杂的公式,如恒定乘积公式 (x * y = k),如 Uniswap 中。
// use reserve ratio as price
function getAmount(int input, int inputReserve, int outputReserve) : int 
    return outputReserve * input / inputReserve;

  • 流动性挖矿:我们可以对每次交换收取费用,并用这些费用来奖励流动性提供者。
  • 允许用户直接将一个 Token 换成另一个 Token 。

TokenSwap 实际上已经实现了以上所有以及更多。

致谢

本作品灵感来源于陈诚的这篇文章

以上是关于BSV 区块链上的 DeFi :Uniswap的主要内容,如果未能解决你的问题,请参考以下文章

BSV资讯感应合约大幅推进BSV区块链上的NFT和智能合约方案

BSV 区块链上的计算外包示例

BSV应用范例区块链上的自我主权身份

活动回顾 | 波兰大会展现出BSV区块链上的全新商业机会

活动回顾 | 波兰大会展现出BSV区块链上的全新商业机会

活动回顾 | 波兰大会展现出BSV区块链上的全新商业机会