> For the complete documentation index, see [llms.txt](https://www.docszh.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.docszh.com/berachain-docs/developers/developer-guides/advanced-pol.md).

# 非 ERC20 代币流动性证明集成

### 介绍 <a href="#introduction" id="introduction"></a>

用户通常将ERC20凭证代币存入[奖励金库](/berachain-docs/learn/proof-of-liquidity/rewardvaults.md)来参与流动性证明，以赚取`$BGT` 。然而，这种方法并不适用于所有协议。

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

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

{% hint style="danger" %}
请注意，本节仅提供一种将PoL与非ERC20协议集成的可行性解决方案。该解决方案并不详尽，不是所有用例都适用。
{% endhint %}

### 方案描述 <a href="#description-of-approach" id="description-of-approach"></a>

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

用户质押虚拟代币，赚取`$BGT`，如同在PoL金库中质押了ERC20凭证代币。此方案由[奖励金库](/berachain-docs/learn/proof-of-liquidity/rewardvaults.md)合约中的`delegateStake`和`delegateWithdraw`实现。

### 先决条件

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

* 参考[Foundry安装文档](https://book.getfoundry.sh/getting-started/installation)安装该软件。

### Forge设置

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

```bash
forge init pol-smart-stake --no-commit --no-git;
cd pol-smart-stake;
forge install OpenZeppelin/openzeppelin-contracts --no-commit --no-git;
```

2. 创建`remappings.txt`文件，用于导入OpenZeppelin：

```bash
# FROM: ./pol-smart-stake

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

### 合约执行

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

```solidity
// 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`可以铸造和销毁代币。

2. **在**`src/ProtocolContract.sol`**中部署虚拟协议合约：**

```solidity
// 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`，并与相关的奖励金库交互，以体现用户的质押/解除质押操作。

3. **在**`src/interfaces/IRewardVaults.sol`**中添加PoL接口：**

```solidity
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`的测试套件示例。

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

```solidity

// 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);
    }
}
```

### 运行测试 <a href="#run-the-test" id="run-the-test"></a>

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

```bash
# 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)
```
