Berachain Docs 中文版
by DocsZH
  • 入门学习
    • 介绍 Berachain
      • 什么是 Berachain
      • 什么是流动性证明
      • 什么是 BeaconKit
      • 连接到 Berachain
      • 如何获得 $BERA
    • Berachain 测试网
      • Berachain 测试网 V1 与 V2
    • PoL 流动性证明
      • 流动性证明概述
      • 流动性证明参与者
      • 奖励金库
      • 激励系统
      • 原生代币系统
        • $BERA
        • $BGT
        • $HONEY
    • 治理模型
      • 治理模型概述
      • 奖励金库白名单
    • 指南
      • 流动性证明常见问题
    • 原生 dApps
      • 测试网水龙头
      • 区块浏览器
      • BEX
      • Bend
      • Berps
      • BGT Station
      • Honey Swap
    • 帮助中心
      • 常见问题
      • 名词解释
  • 开发者文档
    • 面向开发者的 Berachain
      • 流动性证明架构
      • 网络配置
      • 已部署合约
      • 开发者工具
      • 测试网水龙头
      • 测试网区块浏览器
    • 开发者快速入门
      • 智能合约部署
      • 前端部署
    • 开发者指南
      • 使用 Hardhat 部署 HelloWorld 合约
      • 使用 Foundry 部署 ERC20 合约
      • 使用 NextJS & WalletConnect 部署合约
      • 开发者外部资源
      • 非 ERC20 代币流动性证明集成
    • 已部署合约参考
  • 节点运行文档
    • Berachain 节点
      • 节点架构概述
      • BeaconKit 共识层
      • EVM 执行层
      • 节点运行快速入门
      • BeaconKit GitHub 存储库
    • 节点指南
      • 使用 Kurtosis 运行本地开发网
      • 从快照同步节点
由 GitBook 提供支持
在本页
  • 介绍
  • 方案描述
  • 先决条件
  • Forge设置
  • 合约执行
  • 测试集成
  • 运行测试
  1. 开发者文档
  2. 开发者指南

非 ERC20 代币流动性证明集成

上一页开发者外部资源下一页Berachain 节点

最后更新于6个月前

介绍

用户通常将ERC20凭证代币存入来参与流动性证明,以赚取$BGT 。然而,这种方法并不适用于所有协议。

本节将演示如何为无法自动生成质押凭证的ERC20代币,或需要实时跟踪余额的协议集成流动性证明 (PoL) 系统。例如,永续合约交易所可能希望奖励$BGT开仓用户,并在平仓时停止奖励。

通过采用本节方案,上述协议仍可参与PoL系统,同等享有PoL提供的高效率激励。

请注意,本节仅提供一种将PoL与非ERC20协议集成的可行性解决方案。该解决方案并不详尽,不是所有用例都适用。

方案描述

方案涉及创建一个虚拟的StakingToken,虚拟代币由协议代表用户质押在PoL金库中。虚拟代币用于跟踪用户的质押余额,在用户供应或提取流动性时,由协议铸造或销毁 (通过ProtocolContract实现)。

用户质押虚拟代币,赚取$BGT,如同在PoL金库中质押了ERC20凭证代币。此方案由合约中的delegateStake和delegateWithdraw实现。

先决条件

开始之前,请确保你的本地设备上满足以下条件:

  • 参考安装该软件。

Forge设置

  1. 初始化Forge并安装依赖项:

forge init pol-smart-stake --no-commit --no-git;
cd pol-smart-stake;
forge install OpenZeppelin/openzeppelin-contracts --no-commit --no-git;
  1. 创建remappings.txt文件,用于导入OpenZeppelin:

# FROM: ./pol-smart-stake

echo "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/" > remappings.txt;

合约执行

  1. 在src/StakingToken.sol中部署虚拟代币合约:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract StakingToken is ERC20, Ownable {
    constructor() ERC20("StakingToken", "STK") Ownable(msg.sender) {}

    function mint(address to, uint256 amount) external onlyOwner {
        _mint(to, amount);
    }

    function burn(address from, uint256 amount) external onlyOwner {
        _burn(from, amount);
    }
}

该合约创建了一个虚拟的ERC20代币,用于质押在PoL金库中,只有代币所有者ProtocolContract可以铸造和销毁代币。

  1. 在src/ProtocolContract.sol中部署虚拟协议合约:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "./StakingToken.sol";
import {IBerachainRewardsVault, IBerachainRewardsVaultFactory} from "./interfaces/IRewardVaults.sol";

contract ProtocolContract {
    StakingToken public stakingToken;
    IBerachainRewardsVault public rewardVault;

    mapping(address => uint256) public userActivity;

    constructor(address _vaultFactory) {
        // Create new staking token
        stakingToken = new StakingToken();

        // Create vault for newly created token
        address vaultAddress = IBerachainRewardsVaultFactory(_vaultFactory)
            .createRewardsVault(address(stakingToken));

        rewardVault = IBerachainRewardsVault(vaultAddress);
    }

    function addActivity(address user, uint256 amount) external {
        // Protocol actions/logic here
        userActivity[user] += amount;

        // Mint StakingTokens
        stakingToken.mint(address(this), amount);

        // Stake tokens in RewardVault on behalf of user
        stakingToken.approve(address(rewardVault), amount);
        rewardVault.delegateStake(user, amount);
    }

    function removeActivity(address user, uint256 amount) external {
        // Protocol actions/logic here
        require(userActivity[user] >= amount, "Insufficient user activity");
        userActivity[user] -= amount;

        // Withdraw tokens from the RewardVault
        rewardVault.delegateWithdraw(user, amount);

        // Burn the withdrawn StakingTokens
        stakingToken.burn(address(this), amount);
    }
}

该合约是任意协议合约的简单用例:

  • userActivity表示特定于该协议的内部核算和运作逻辑。

  • addActivity和removeActivity余下功能是用于铸造和销毁虚拟代币StakingTokens,并与相关的奖励金库交互,以体现用户的质押/解除质押操作。

  1. 在src/interfaces/IRewardVaults.sol中添加PoL接口:

pragma solidity ^0.8.19;

interface IBerachainRewardsVault {
    function delegateStake(address account, uint256 amount) external;

    function delegateWithdraw(address account, uint256 amount) external;

    function getTotalDelegateStaked(
        address account
    ) external view returns (uint256);

    function balanceOf(address account) external returns (uint256);
}

interface IBerachainRewardsVaultFactory {
    function createRewardsVault(
        address stakingToken
    ) external returns (address);
}

这些接口定义了从Factory合约中启动新的奖励金库,以及与之交互的方法。

测试集成

现在,对所有部署进行整体测试,以确保上述集成操作符合预期。以下是ProtocolContract的测试套件示例。

请检查每项测试,以便更加了解如何应对并成功处理各种情况。


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "forge-std/Test.sol";
import "../src/ProtocolContract.sol";
import {IBerachainRewardsVault, IBerachainRewardsVaultFactory} from "../src/interfaces/IRewardVaults.sol";

contract ProtocolContractTest is Test {
    ProtocolContract public protocol;
    IBerachainRewardsVault public rewardVault;

    address public user1 = address(0x1);
    address public user2 = address(0x2);

    function setUp() public {
        IBerachainRewardsVaultFactory vaultFactory = IBerachainRewardsVaultFactory(
                0x2B6e40f65D82A0cB98795bC7587a71bfa49fBB2B
            );
        protocol = new ProtocolContract(address(vaultFactory));
        rewardVault = protocol.rewardVault();
    }

    function testAddActivity() public {
        protocol.addActivity(user1, 1);
        assertEq(protocol.userActivity(user1), 1);
        assertEq(rewardVault.balanceOf(user1), 1);
    }

    function testRemoveActivity() public {
        protocol.addActivity(user1, 2);
        protocol.removeActivity(user1, 1);
        assertEq(protocol.userActivity(user1), 1);
        assertEq(rewardVault.balanceOf(user1), 1);
    }

    function testMultipleUsers() public {
        protocol.addActivity(user1, 1);
        protocol.addActivity(user2, 2);
        assertEq(rewardVault.balanceOf(user1), 1);
        assertEq(rewardVault.balanceOf(user2), 2);
    }
}

运行测试

最后,运行测试程序,以检查上述集成是否按预期工作:

# FROM: ./pol-smart-stake

forge test --rpc-url https://bartio.rpc.berachain.com/;

# [Expected Output]:
# [⠊] Compiling...x
# No files changed, compilation skipped

# Ran 3 tests for test/StakingToken.t.sol:ProtocolContractTest
# [PASS] testAddActivity() (gas: 252067)
# [PASS] testMultipleUsers() (gas: 371503)
# [PASS] testRemoveActivity() (gas: 272693)
# Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.73s (1.22ms CPU time)

奖励金库
奖励金库
Foundry安装文档