硬件钱包或APP如何集成质押接口?
首先钱包APP需要帮助用户判断、或者让用户选择下边两种质押方式。如果钱包APP决定让用户选择质押方式,就需要提供两个质押入口(大额、小额),并告知用户区别。
如果钱包APP希望自动帮助用户选择质押方式,也可以在用户质押时候判断质押数量是否大于32,如果大于32则走大额质押流程,反之则走小额质押流程。
- 大额质押:用户自己管理提款凭证,最低支持32ETH,最大支持3200ETH,质押量须是32的整数倍。
- 小额质押:可乐平台多签管理提款凭证,最低支持0.01ETH,最大支持100000000000ETH。
Mainnet主网合约:0xACBA4cFE7F30E64dA787c6Dc7Dc34f623570e758
Goerli测试网合约:0xdCAe38cC28606e61B1e54D8b4b134588e4ca7Ab7
大额质押
第一步:ETH1地址转ETH2提款凭证
钱包APP需要使用官方提供的ETH1_ADDRESS_WITHDRAWAL_PREFIX方式,将用户ETH1存款地址转换成ETH2的提款凭证,注意转换后的提款凭证都是小写字母,具体转换方式如下:
- ETH2提款凭证 =
0x01 + 11个00 + 去掉0x的ETH1地址
转换例子:
ETH1存款地址:0x5dD3BD08cBc8498C8640Abc26D19480219bB0606
ETH2提款凭证:0x0100000000000000000000005dd3bd08cbc8498c8640abc26d19480219bb0606
第二步:请求可乐矿池API
(1)用户地址注册
/user/v2/anonymouslogin
此接口只需在用户第一次质押的时候调用,当然你也可以在用户每次质押时调用,注意此接口必须在用户质押前调用。
POST https://test-api.kelepool.com/user/v2/anonymouslogin
{
// 用户质押钱包地址
"payee_addr":"0xA49F98416aa4B158c2e752FD8031Fb295D330B22",
// 质押代币(eth)
"token":"eth",
// 数据来源便于商务合作统计(例如:钱包APP)
"source":"钱包APP"
}
(2)生成合约大额质押需要的参数
/eth2/v2/validator/keypair
此接口用于合约大额质押的参数生成,需要传入上面的转换好的ETH提款凭证。由于大额质押是用户自己控制提款密钥,但验证节点需要可乐矿池运营,因此需要调用此接口生成运营节点需要的一些参数,用户质押时需将验证节点参数一起提交至ETH2.0官方存款合约。
这里请求的参数里有个count
,是通过用户质押量计算出来的,下边有计算例子。这里传入了2
因此返回了两条验证节点信息,你可能会发现他们的提款凭证
都是一样的,未来用户可以通过一个提款凭证对所有节点质押数量和收益提款。由于用户可能在质押时传入了35、100、89这种并非32的倍数数量,因此钱包APP需要计算一下有效质押数量,只允许用户质押32的倍数数量。
- 验证节点数量 =
(用户质押ETH数量 - (用户质押ETH数量 % 32))/ 32
- 有效质押数量 =
(用户质押ETH数量 - (用户质押ETH数量 % 32))
- 大额质押手续费 =
0.05 * 验证节点数量
假设用户质押了68ETH:
- 验证节点数量 = (68 - 68 % 32)/ 32 = 2
- 有效质押数量 = (68 - 68 % 32) = 64
- 大额质押手续费 = 0.05 * 2 = 0.1ETH
POST https://test-api.kelepool.com/eth2/v2/validator/keypair
请求参数:
{
// 上面转换好的ETH2提款凭证(去掉0x)
"deposit_credentials":"0100000000000000000000005dd3bd08cbc8498c8640abc26d19480219bb0606",
// 验证节点数量,计算方式 =(用户质押ETH数量 - (用户质押ETH数量 % 32))/ 32
"count":2,
// 是否重新生成新的keystore。(0=否,1=是)
"recreate":0
}
返回值:
{
// 整型数字,等于0表示成功,大于0表示失败
"code":0,
// 失败后返回的消息
"message":"success",
"data":[
{
// 验证者公钥
"pubkey":"86ee4eecf1c83725020cf8667c555b286b54445691da44aa7a671b6d18abf118452e60876216f9adec5e64ff09c3e231",
// 提款凭证
"withdrawal_credentials":"0100000000000000000000005dd3bd08cbc8498c8640abc26d19480219bb0606",
// 验证者签名
"signature":"a61e5ed96b5b22ec9da92cf3f09c24cf9230ec1db99918e9dedfc9440de473f64b7520b5fb40558d0bc9f009dd20731917c3dbf6b3cfd98b48377a190d9e2959df3d2fa2dcec9c09e8be420accc9daa25301d4a2ce1636a5413ac066e7a4628f",
// 默克尔树根
"deposit_data_root":"ebb84a75e241501cc64c4e42dd3cdb7a2f72e6af60ab828b2fb246905eb629e5",
// ETH网络
"network_name":"Goerli"
},
{
"pubkey":"83909737754d15dd3ad1281a3f0e62baa64d3c0abb3ed218c3baf7ff250058a24fe1143a5243c3b015e3f93ed6af1e18",
"withdrawal_credentials":"0100000000000000000000005dd3bd08cbc8498c8640abc26d19480219bb0606",
"signature":"b95af475d67e8438e49cfaad12dacd789c705938fd6a8fee93a1a170ef6322c2cf37c643d1d010b23734c04e9028b58d034435dd6c9f19610090bfdefb7522c69e99b0a7830f6d967f1d07e3ff30128c8b516d40232e5595ac91d746420da993",
"deposit_data_root":"f08ca526395300d60ccc6db28d931ba129944f44d4bb92c773424e120dde222b",
"network_name":"Goerli"
}
]
}
第三步:调用合约质押
得到上面返回的的验证者公钥数据后,我们就可以调用合约进行大额质押了。上面按质押量计算出验证节点数量为2
,因此API接口返回了两条验证节点数据,我们调用合约时需要将这两条数据组合一下,再传入合约。具体请参考下边的js代码。
- 用户质押64ETH,得出
64 / 32 = 2
,那么用户需要额外准备0.05 * 2 = 0.1ETH
的手续费 - 因此用户转入合约的数量变成了
64.1ETH
,低于或高于这个数量合约都会拒收 - 可乐矿池每个验证节点收取一次fee,运营fee的有效期为ETH2.0上线,之后可乐矿池将视情况收费
// 导入库
import { ethers } from "ethers";
// 连接Metamask钱包
const provider = new ethers.providers.Web3Provider(window.ethereum)
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
let userAddress = await signer.getAddress();
// 初始化合约参数
const kelepool = {
address: "0xdCAe38cC28606e61B1e54D8b4b134588e4ca7Ab7",// 可乐矿池【代理合约】,这里必须是代理合约!!!
abi: [{"anonymous":false.... }] // 将上面的合约ABI数组放到这里,
};
const contract = new ethers.Contract(kelepool.address, kelepool.abi, signer);
// 组装大额质押数据
let data = [] // /eth2/v2/validator/keypair API返回的data对象
let stakingPublicKey = ''
let stakingSignature = ''
let stakingCredentials = '0100000000000000000000005dd3bd08cbc8498c8640abc26d19480219bb0606' // 用户提款凭证
let stakingRoot = []
for (let i = 0; i < data.length; i++) {
let validator = data[i]
stakingPublicKey += validator.pubkey // 拼接公钥字符串
stakingSignature += validator.signature // 拼接签名字符串
stakingRoot.push('0x' + validator.deposit_data_root) // 拼接默克尔树字符串
}
// 生成大额质押合约参数
let prefix = '0x'
let pubkey = ethers.utils.arrayify(prefix + stakingPublicKey)
let withdrawal_credentials = ethers.utils.arrayify(prefix + stakingCredentials)
let signature = ethers.utils.arrayify(prefix + stakingSignature)
let deposit_data_root = stakingRoot
// 执行合约大额质押方法,最低质押32ETH,这里我们质押64ETH,由于每个节点需要0.05ETH手续费,因此2个节点需要质押64.1ETH
let amount = ethers.utils.parseUnits('64.1', 'ether')
// 以下是V1版本(已经弃用),无法传递source渠道参数。
// source渠道参数是可乐矿池分配给第三方渠道的标识,用于分红统计时区分是哪个渠道过来的质押金额。
// 使用V1版本必须在用户质押前先请求:用户地址注册接口(/user/v2/anonymouslogin)建立用户地址与source渠道的关联,我们才能区分渠道质押金额。
const tx = await contract.createValidator(1, pubkey, withdrawal_credentials, signature, deposit_data_root, {
from: userAddress, // 调用者账号
value: amount,// 质押金额
gasLimit: 10000000 // 最大Gas限制
})
// 以下是V2版本(推荐使用),可以传递source渠道参数。
// source渠道参数是可乐矿池分配给第三方渠道的标识,用于分红统计时区分是哪个渠道过来的质押金额。
// 如果你之前接入了V1版本也没关系,更新成V2版本后,用户质押完成会优先写入从合约传递过来的source。
let source = ethers.utils.arrayify(ethers.utils.formatBytes32String("ThirdParty"))
const tx = await contract.createValidatorV2(1, source, pubkey, withdrawal_credentials, signature, deposit_data_root, {
from: userAddress, // 调用者账号
value: amount,// 质押金额
gasLimit: 10000000 // 最大Gas限制
})
console.log(`大额质押交易哈希: ${tx.hash}`);
小额质押
第一步:用户地址注册
/user/v2/anonymouslogin
此接口只需在用户第一次质押的时候调用,当然你也可以在用户每次质押时调用,注意此接口必须在用户质押前调用。
POST https://test-api.kelepool.com/user/v2/anonymouslogin
{
// 用户质押钱包地址
"payee_addr":"0xA49F98416aa4B158c2e752FD8031Fb295D330B22",
// 质押代币(eth)
"token":"eth",
// 数据来源便于商务合作统计(例如:钱包APP)
"source":"钱包APP"
}
第二步:调用合约质押
小额质押非常简单,只需要将代币存入可乐矿池智能合约。用户最低可以质押0.01ETH,最大可以质押无限数量的ETH,待合约中小额总质押数量累计超过32ETH后,可乐矿池会使用以太坊官方CLI工具在冷钱包中生成提款凭证,同时自动创建验证节点。用户的资金由可乐矿池管理及保障安全,等待未来ETH2.0正式上线后,可乐矿池会为用户开放提现接口。
- 假设我们打算质押
125.0172ETH
,质押后可乐矿池会立即创建3个验证节点
(每个32ETH) - 合约中将剩余
29.0172ETH
等待质押,待其他用户质押凑够32ETH
后会再创建验证节点
// 导入库
import { ethers } from "ethers";
// 连接Metamask钱包
const provider = new ethers.providers.Web3Provider(window.ethereum)
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
let userAddress = await signer.getAddress();
// 初始化合约参数
const kelepool = {
address: "0xdCAe38cC28606e61B1e54D8b4b134588e4ca7Ab7",// 可乐矿池【代理合约】,这里必须是代理合约!!!
abi: [{"anonymous":false.... }] // 将上面的合约ABI数组放到这里,
};
const contract = new ethers.Contract(kelepool.address, kelepool.abi, signer);
// 执行合约小额质押方法,最低质押0.01 ETH,这里我们质押125.0172ETH
let amount = ethers.utils.parseUnits("125.0172", 'ether')
// 以下是V1版本(已经弃用),无法传递source渠道参数。
// source渠道参数是可乐矿池分配给第三方渠道的标识,用于分红统计时区分是哪个渠道过来的质押金额。
// 使用V1版本必须在用户质押前先请求:用户地址注册接口(/user/v2/anonymouslogin)建立用户地址与source渠道的关联,我们才能区分渠道质押金额。
const tx = await contract.deposit({
from: userAddress, // 调用者账号
value: amount,// 质押金额
gasLimit: 10000000 // 最大Gas限制
});
// 以下是V2版本(推荐使用),可以传递source渠道参数。
// source渠道参数是可乐矿池分配给第三方渠道的标识,用于分红统计时区分是哪个渠道过来的质押金额。
// 如果你之前接入了V1版本也没关系,更新成V2版本后,用户质押完成会优先写入从合约传递过来的source。
let source = ethers.utils.arrayify(ethers.utils.formatBytes32String("ThirdParty"))
const tx = await contract.depositV2(source,{
from: userAddress, // 调用者账号
value: amount,// 质押金额
gasLimit: 10000000 // 最大Gas限制
});
console.log(`小额质押交易哈希: ${tx.hash}`);
大额质押设置合作商手续费及收款地址
1.合作商可以联系可乐矿池设置大额质押手续、渠道标记、收款地址、费用类型等,质押完成后合约自动将手续费转入合作商设置的收款地址,可乐矿池目前按每个验证节点收取0.05ETH手续费。
若用户质押时的source与合作商设置的partner渠道标记匹配,合约将要求用户支付合作商手续费
合作商可通过合约的getPartnerInfo查询自己的手续费信息
合作商未设置手续费或手续费设置为0,默认每个节点收取0.05手续费
2.收取手续费有两种方式(以用户一次质押10个验证节点,合作商设置0.1ETH手续费为例)
按节点数量收取:合约将收取1.5ETH手续费,其中0.5ETH给可乐矿池,1ETH自动转给合作商
按每次质押收取:合约将收取0.6ETH手续费,其中0.5ETH给可乐矿池,0.1ETH自动转给合作商