Alpaca Finance
搜索文档…
💻
与 Alpaca Finance 集成

与 Alpaca Finance 集成

Alpaca Finance 允许 DeFi 应用程序和最终用户与其核心协议集成。一个简单的例子,就是开发人员可以构建一个自动复投协议,将用户的资金存入 Alpaca Finance 的存款池,并为用户复投收益以提高 gas 的使用效率和便利性。本文档的目的是帮助开发人员与我们的协议集成,以确保生态系统的整体安全。

智能合约集成

本节将介绍如何直接透过智能合约与 Alpaca Finance 集成。

贷款 (Lending)

Alpaca Finance 允许用户通过将加密资产存入我们的存款池,来赚取来自加密资产的利息收入。这些资产将会提供予来农民来开启杠杆仓位。任何与 EVM 兼容并部署在 BNB Chain 上的智能合约都可以与 Alpaca Finance 的借贷协议集成。
要将基础代币存入 Alpaca Finance 的存款池,首先应获取可用存款池及其相应的基础代币的列表。
  • 请参阅此处查看所有存款池合约地址的详细列表。
在向存款池存款之前,作为存款人的智能合约必须首先批准要存入的基础代币的支出限额。这将为Alpaca 的智能合约提供从发送方提取代币的能力。
1
// JavaScript
2
import { ERC20 } from '../typechain/ERC20'
3
import { MaxUint256 } from '@ethersproject/constants'
4
5
...
6
7
const yourSmartContractAddress = 'xxx'
8
tokenERC20.approve(yourSmartContractAddress, MaxUint256);
Copied!
上面的 JavaScript 代码段落是关于如何批准代币的最大可能支出限额的简化流程。请注意,使用 MaxUint256 可能会带来安全风险,建议使用用户输入的确实代币数量。
存款是通过调用 deposit 方法并在 amountToken 参数中指定存款金额来进行的。 amountToken 的数据类型 (data type) 是 uint256 而该参数必须被格式化为存款代币的小数位 (例如,BNB使用 18 个小数位,1 BNB = 100000000000000000001*1E18)。存款代币如果是 BNB 的情况,存款池将为 BNB 包装成 wBNB,但交易必须包含足够的 BNB 作为原生代币发送。
1
// Solidity
2
address vaultContractAddress = '0xd7D069493685A581d27824Fc46EdA46B7EfC0063'; // BNB Vault
3
if (msg.value == 0) { // if no native token is sent, then it is a ERC20/BEP20 token deposit
4
IERC20(tokenAddess).safeTransferFrom(address(msg.sender), address(this), amountToken);
5
}
6
// Allow transfer to vault
7
SafeToken.safeApprove(tokenAddess, vaultContractAddress, amountToken);
8
// Deposit to vaultDeposit to vault
9
IVault(vaultContractAddress).deposit(amountToken);
Copied!
如果存款成功,存款池将铸造”计息代币” (interest-bearing tokens 即 ibTokens) 并将这些铸造的代币返还给调用者。
请注意,基于计息代币的设计,返回的计息代币数量将不等于提供的原生代币数量。deposit 方法的调用者必须正确记录用户在存款池中的存款份额,请阅读本文下方 “计息代币的计算” 部分的详细说明。
来自贷款的利息将计入 ibTokens。为了实现借贷收益,ibTokens 必须被提取,将原生代币 + 收到的利息赎回。您将会注意到,ibToken 的兑换价格在提款时会更高,这代表利息已经被产生。因此,您将在提款时收到额外的原生代币。
从存款池中赎回原生代币时,需要提取的 ibTokens 数量必须要提供给 Vault 合约的 withdraw 方法。
1
// Solidity
2
address vaultContractAddress = '0xd7D069493685A581d27824Fc46EdA46B7EfC0063'; // BNB Vault
3
IVault(vaultContractAddress).withdraw(ibTokenAmount);
Copied!
原生代币将会返回给调用者。如果返回的代币是 BNB,Vault 合约将为 WBNB 解除包装为 BNB。

计息代币的计算

计息代币(ibToken)是代表存款人在存款池份额的代币。 ibTokens 将随着时间的推移从借贷中获得利息。任何希望使用 Alpaca Finance 存款池的 DeFi 协议都应该正确理解和实施 ibTokens 的计算,以反映用户在存款池的实际份额。
因此,当存款池首次上线时,ibToken 与实际原生代币之间的比率才会为 1:1,之后 ibToken 的价值将随着借贷利息的累计而继续增加(ibToken 相对于原生代币的价值将仅单向提升。价值不会减少)。例如,让我们假设价格: 1 ibBNB = 1.0292 BNB ,这代表着存款 1.0292 BNB将获得 1 ibBNB 作为回报。另一方面,兑换1 ibBNB 将获得1.0292 BNB 作为回报。赎回 ibBNB 时的额外 BNB 来自累计的利息。
了解 ibTokens 价值的这一基本机制非常重要,因为与 Alpaca Finance 的借贷存款池集成的DeFi协议可能需要准确计算用户在存款池中的份额。否则将可能带来安全风险和经济损失。bEarn.fi ValueDeFi 被攻击的情况就是这样,这些协议始终将 ibTokens 和相关代币的的比率理解为 1:1 (阅读对 bEarn.fi ValueDeFi 的攻击的分析)。
此外,虽然 Alpaca 不支持闪电贷 (flash loans),但在外部非 Alpaca 存款池中,可能存在透过攻击来操纵 ibToken 价格的风险,变相的闪电贷攻击。如果没有准备,ibToken 的价格可能会在攻击者的交易范围内发生巨大变化。这就是为什么单单依靠智能合约来计算 ibToken 的价格是不足够的。我们建议项目有一个价格预言机 (Price Oracle) 来提供 ibTokens 与原生代币的当前比率,以防止上述此类攻击。
因此,我们将为您展示计算 ibTokens 价格的最安全和正确的方法。

直接从智能合约计算

由智能合约计算 ibToken 代币价格是最简单的方法,但为了稳健性,它不能是您唯一依赖的方法。
1
// Solidity
2
address vaultContractAddress = '0xd7D069493685A581d27824Fc46EdA46B7EfC0063'; // BNB Vault
3
IVault vault = IVault(vaultContractAddress);
4
uint256 ibTokenAmount = ...;
5
uint256 ibTokenPrice = vault.totalToken()).div(vault.totalSupply();
6
uint256 underlyingTokenAmount = ibTokenAmount.mul(ibTokenPrice);
Copied!
上面的代码段落示范了通过在相关存款池中提取 totalTokentotalSupply 的数值来计算ibToken 的价格。

从 Alpaca API 中提取 ibToken 价格

Alpaca Finance 提供了一个 API 来提取当前的 ibToken 价格,通过向 endpoint /ibTokens 发送一个 GET 的 REST 请求就能提取任何 ibToken 价格。与 Alpaca API 的集成需要身份验证,因此如果您想使用这个服务,请联系我们。
API 的示例结果如下:
1
{
2
"status": {
3
"code": 1000,
4
"messages": [
5
"OK"
6
]
7
},
8
"data": [
9
{
10
"symbol": "ibALPACA",
11
"baseTokenPerShare": "1.051108636596531492",
12
"lendingApr": "0.0003638488758058",
13
"stakingApr": "0.0"
14
},
15
{
16
"symbol": "ibBNB",
17
"baseTokenPerShare": "1.025808940627339553",
18
"lendingApr": "9.7785294844178225",
19
"stakingApr": "316693.265280905443641"
20
},
21
{
22
"symbol": "ibBUSD",
23
"baseTokenPerShare": "0.972337256352625836",
24
"lendingApr": "0.368330890561667",
25
"stakingApr": "2269.786601379154162"
26
},
27
{
28
"symbol": "ibUSDT",
29
"baseTokenPerShare": "0.913094694500682622",
30
"lendingApr": "0.0012775198722327",
31
"stakingApr": "0.0"
32
},
33
{
34
"symbol": "ibBTCB",
35
"baseTokenPerShare": "1.000006160536069502",
36
"lendingApr": "6.5534019786376696",
37
"stakingApr": "0.0"
38
},
39
{
40
"symbol": "ibETH",
41
"baseTokenPerShare": "0.999463386510494271",
42
"lendingApr": "0.0000004209960912",
43
"stakingApr": "0.0"
44
}
45
]
46
}
Copied!
通过 Alpaca 的 API 提取的价格会通过价格预言机提供基于智能合约。通过智能合约的调用来提供价格将容易受到来自客户端的注入攻击。我们强烈建议不要这样做。在这里可以查看一个简单价格预言机的例子。通过使用可信的价格预言机,您可以确保 ibToken 价格数据的完整性和可靠性。
我们强烈建议同时透过智能合约的计算和 Alpaca API 来提取 ibToken 价格。这两个来源的价格数据应该被比较以防止任何可能的数据异常。如果两个来源之间的比较差异很大,则价格数据应该被拒绝。
总之,计算 ibTokens 最安全的流程应当如下:
  1. 1.
    在您自己的合约中计算 ibTokens 的价格
  2. 2.
    利用链下预言机获取 ibTokens 的价格,或通过 Alpaca API 拉取价格
  3. 3.
    比较 1 和 2 的结果,如果相差超过 n% 则拒绝 (revert) 交易
Alpaca 的 API 目前只提供给白名单的协议和机构,想要进入白名单,请电邮联系我们 [email protected]

质押

Alpaca Finance 为用户提供质押机会。计息代币和特定的 LP 代币在我们的质押池中质押以赚取ALPACA 代币形式的额外收益。如果您已存入资金并收到 ibToken,我们建议您将这些代币放入这些池中以获得最大的奖励。
要将代币质押到 Alpaca Finance 的质押池中,首先需要获取质押池及其对应质押代币列表。请参阅 这里 有关所有质押池的合约地址。在我们的代码库中,质押池的合约通常被称为 Fairlaunch
执行质押可通过调用 deposit 方法。参数如下:
  • _for 为存款人地址。
  • _pid 为质押池的 ID。
  • _amount 是要存入的代币数量,以 uint256 表示(例如 ibBNB 使用18个位小数位,1 ibBNB = 100000000000000000001*1e18
1
// Solidity
2
address fairlaunchContractAddress = '0xA625AB01B08ce023B2a342Dbb12a16f2C8489A8F'; // ibBNB pool
3
IFairLaunch fairlaunch = IFairLaunch(fairlaunchContractAddress);
4
fairlaunch.deposit(msg.sender, poolId, amount);
Copied!
质押份额的信息将被存储在智能合约状态中。质押不会发行代币。通过调用 Fairlaunch 合约中 userInfo 方法可提取用户的份额。
来自质押的奖励不会自动被计算,而必须手动收取。但是,在已质押的池上进行存款或取款将自动收割待提取奖励到调用者。要从池中收割奖励,调用者必须调用 Fairlaunch 合约中的 harvest 方法并提供质押池 ID。
1
// Solidity
2
address fairlaunchContractAddress = '0xA625AB01B08ce023B2a342Dbb12a16f2C8489A8F'; // ibBNB pool
3
IFairLaunch fairlaunch = IFairLaunch(fairlaunchContractAddress);
4
fairlaunch.harvest(poolId);
Copied!
要从池中提取质押代币,必须在 Fairlaunch 合约中的 withdraw 方法中提供用户份额的数量。
1
// Solidity
2
address fairlaunchContractAddress = '0xA625AB01B08ce023B2a342Dbb12a16f2C8489A8F'; // ibBNB pool
3
IFairLaunch fairlaunch = IFairLaunch(fairlaunchContractAddress);
4
fairlaunch.withdraw(msg.sender, poolId, amount);
Copied!
质押代币将返还给调用者,任何待提取的奖励也将自动被收取。

测试网环境

在上传和部署开发到主网之前,Alpaca Finance 的合约会首先被部署到币安智能链上的测试网。这些测试网的合约原本是设计成仅供Alpaca Finance 开发的内部测试用途。 然而,我们开放给有兴趣测试他们对 Alpaca 的合约集成的第三方。给测试网使用的代币是我们内部创造出来的,如果您想要这些代币以供测试使用,请来信至 [email protected]。测试网的地址清单请见此处