DeBox Shares 协议
DeBox Shares 简介
什么是 DeBox Shares?
DeBox Shares 协议是 DeBox 为开发者、KOL 和用户提供服务的赋能工具。它是一套由 DeBox 定义的 API,开发者可以利用这些 API 进行定制化服务,为用户和平台创造价值。
在 DeBox 平台上,群主、群成员以及开发者都可以通过 Shares 协议获利。该协议通过将 DeBox 平台的部分收入分配给用户的方式,激励更多的用户参与分享、推广和使用小程序。
开发者可以基于 DeBox SDK 开发小程序,并通过收入分成等方式,鼓励 DeBox 用户使用、推广和分享这些小程序。当用户通过成员的分享链接打开小程序时,用户在程序中的消费收入的一部分将按照一定比例分配给分享人、DAO 资产以及群主等,形成一个良性循环的收益模式。
Shares 支持哪些参与方式?
- 支持 vBOX 支付:直接调用 DeBox-Shares 的 vBOX 支付接口即可;
- 支持链上 Token 支付:调用 DeBox-Shares 合约,略微调整 DAPP 的付款处合约 代码即可;
- 支持多种网络:目前已支持 ETH, Arbitrum, Base, BSC, OP, Polygon 网络资产(不断更新中)。
如何接入 Shares?
1. vBOX 支付接入 Shares
- vBOX 支付过程包含两个主要步骤:连接钱包并获取授权、调用支付 API 完成支付。支付完毕后可以查看支付详细信息。以下是详细步骤和使用方法:
1.1 连接钱包并请求授权
-
DAPP 可以通过 DeBox Wallet SDK 连接用户钱包并获取所需用户信息。
DeBox Wallet SDK 是 DAPP 与 DeBox 钱包进行连接和交互的工具。当用户通过 DeBox 客户端打开网页时,DeBox 会自动在网页中注入
window.deboxWallet
对象(也可以通过别名window.ethereum
访问)。DAPP 可以通过此对象检测 DeBox 钱包是否已经安装,并调用相应的 API 方法进行操作。 -
以下方法可用于此过程:
eth_requestAccounts:该方法请求用户钱包授权连接。
- 常用的钱包方法,DeBox对此进行了扩展
- 在内部,该方法调用
debox_getUserInfo
方法请求用户信息权限 。 - 此方法会弹出一个窗口,要求用户授权连接 DAPP 并获取钱包地址。
请求:
await window.deboxWallet.request({
"method": "eth_requestAccounts",
"params": [],
});
参数:
- 无
响应:
- 成功时返回用户钱包地址。
[
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
]
wallet_requestPermissions:该方法用于请求用户批准 DAPP 某些访问权限
- 需要先请求用户授权的方法有:
debox_getUserInfo
(获取用户公开信息),debox_getVBoxBalance
(获取用户钱包 vBOX 余额)
-
权限请求信息参数为空。此时默认会请求用户批准
debox_getUserInfo
方法权限请求:
await window.deboxWallet.request({
"method": "wallet_requestPermissions",
"params": [{
eth_accounts: {}
}],
});参数:
eth_accounts
:其值为空对象{}
,表示请求默认权限(即debox_getUserInfo
)
响应:
- 成功时返回:
[
{
"parentCapability": "eth_accounts",
"invoker": "https://connect-nu-one.vercel.app/",
"caveats": [
{
"type": "restrictReturnedAccounts",
"value": [
"0xa56b4f0c7622bd076c2ba48b17d1e8d3fbf5303e"
]
},
{
"type": "debox_getUserInfo",
"value": {
"uid":"jkdi123",
"address":"0xa56b4f0c7622bd076c2ba48b17d1e8d3fbf5303e",
"name":"张三",
"avatar":"https://debox......png"
}
},
],
"date": 1728348403194
},
] -
权限请求信息带有参数。此时会请求用户批准开发者所指定方法的权限:
请求:
await window.deboxWallet.request({
"method": "wallet_requestPermissions",
"params": [{
eth_accounts: {
"debox_getUserInfo": {},
"debox_getVBoxBalance": {}
}
}],
});参数:
eth_accounts
属性,属性值为一个对象,里面指定了两个权限:"debox_getUserInfo"
: 请求获取用户信息(如头像、昵称等)的权限,值为空对象{}
。"debox_getVBoxBalance"
: 请求获取用户 vBOX 余额的权限,值为空对象{}
。
响应:
- 成功时返回:
[
{
"id": "QbOgSTaFmS3UK1qS6pese",
"parentCapability": "eth_accounts",
"invoker": "https://connect-nu-one.vercel.app/",
"caveats": [
{
"type": "restrictReturnedAccounts",
"value": [
"0xa56b4f0c7622bd076c2ba48b17d1e8d3fbf5303e"
]
},
{
"type": "debox_getUserInfo",
"value": {
"uid":"jkdi123",
"address":"0xa56b4f0c7622bd076c2ba48b17d1e8d3fbf5303e",
"name":"张三",
"avatar":"https://debox......png"
}
},
{
"type": "debox_getVBoxBalance",
"value": {
"usable_balance": 0.12
}
},
],
"date": 1728348403194
},
]
debox_getUserInfo:该方法获取用户的公开信息,如用户 ID、钱包地址、昵 称和头像。
- 前提条件: 已通过
wallet_requestPermissions
请求用户批准debox_getUserInfo
访问权限,否则拒绝服务 - 如果用户没有授权
debox_getUserInfo
访问,则弹出授权确认框,用户允许后再返回信息或者拒绝服务。
请求:
await window.deboxWallet.request({
"method": "debox_getUserInfo",
"params": [],
});
参数:
- 无
响应:
- 如果用户已授权访问,成功时返回用户的基本信息(ID、地址、昵称、头像)。
{
"address":"0xa56b4f0c7622bd076c2ba48b17d1e8d3fbf5303e",
"name":"张三",
"avatar":"https://debox......png",
"uid":"jkdi123"
}
debox_getVBoxBalance :该方法获取用户的 vBOX 余额
- 前提条件: 已通过
wallet_requestPermissions
请求用户批准debox_getVBoxBalance
访问权限,否则拒绝服务
请求:
await window.deboxWallet.request({
"method": "debox_getVBoxBalance",
"params": [],
});
- 返回用户的可用 vBOX 余额(需用户授权)。
参数:
- 无
响应:
- 成功时返回用户的可用 vBOX 余额,如果用户已授权访问。
{
"usable_balance": 0.12
}
错误代码
- 用户没有授权该方法调用时
{
"code": 4100,
"message": "The requested account and/or method has not been authorized by the user."
}
- 用户拒绝了请求时
{
"code": 4001,
"message": "User rejected the request."
}
1.2 调用 vBOX 支付 API
- 在用户授权后,Dapp 前端可以调用 debox_paymentVBox 方法进行支付。
- 以下方法可用于此过程:
debox_paymentVBox:该方法进行 vBOX 支付,可指定收款地址、支付金额、支付备注和分佣金额。
- 前提条件: 已通过
wallet_requestPermissions
请求用户批准debox_getUserInfo
访问权限,否则拒绝服务
请求:
await window.deboxWallet.request({
"method": "debox_paymentVBox",
"params": [{
"receiver_address": "0x4c7d41C915a12BCe634d619144941a51FA83DfF5",
"amount": 100,// 支付的 vBox 数量,最小值为 0.01
"nonce": 12893019283,
"note": "购买道具",
"donation_amount": 40
}],
});
- 用户可以输入收款地址、支付金额、备注以及分佣金额,API 会返回交易结果,如订单 ID 或支付状态。
参数:
receiver_address
:收款人钱包地址(如果地址不存在或无效,会导致支付失败)。amount
:支付的 vBOX 数量,最小值为 0.01。nonce
: Int64, 可选,如果为空则由DeBox客户端使用当前时间戳生成。这是一个防止同一笔支付多次消费的防重编码。note
:支付备注信息,最长不超过 100 个字符。donation_amount
:分配给 DeBox 平台进行分佣的金额,不能超过amount
值。
响应:
order_id
: 本次支付的订单ID
{
"order_id": "0xd85554eb6e2ab48dd36209eb8db65d1fa540621c3679c7388f469ff314a194a8"
}
错误代码
- 用户没有授权该方法调用时
{
"code": 4100,
"message": "The requested account and/or method has not been authorized by the user."
}
- 用户拒绝了请求时
{
"code": 4001,
"message": "User rejected the request."
}
- 收款地址
receiver_address
须要是DeBox用户的地址。否则支付失败,提示“不合法的参数” - 收款地址
receiver_address
不可与付款地址相同。否则支付失败,提示“系统繁忙,请稍后再试”
1.3 查询支付结果
- 在调用 debox_paymentVBox 支付后,Dapp 可以检 查回执的真实性:
- 以下方法可用于此过程:
GET https://open.debox.pro/openapi/payment/receipt
:该接口用于查看支付结果的详细信息
https://open.debox.pro/openapi/payment/receipt
:该接口用于查看支付结果的详细信息接口端点:https://open.debox.pro/openapi/payment/receipt
请求方法:GET
请求示例:
curl
https://open.debox.pro/openapi/payment/receipt?order_id=0x0aabbccxx
参数:
Header:
X-API-KEY
:String
- 开发者 key,在开放平台可以获取;
- 少量查询时可以不使用。大量发起请求时,添加该请求头以避免限流。
Query:
order_id
:String
- 支付的订单ID
响应:
- 成功时返回:
{
"code": 1,
"data": {
"order_id": "0x0aabbccxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"receiver_id": "okqwerty",
"payer_id": "0cqwerte",
"amount": "0.02",
"fee": "0.01",
"invoker_note": "buy a cup of coffee"
},
"message": "success",
"success": true
}
- 失败时返回:
{
"code":-4018,
"data":{
"amount":"0",
"fee":"0"
},
"message":"Record not found",
"success":false
}
1.4 部署、交互示例:
https://connect-nu-one.vercel.app/ (在DeBox中打开)

点击各个按钮调用对应方法,在右下角 ”vConsole” 中即可观察到执行结果。
示例代码:
// test the availability of deboxWallet
if (typeof window.deboxWallet !== "undefined") {
window.ethersProvider = new ethers.providers.Web3Provider(
window.deboxWallet
);
console.log("deboxWallet is available");
} else {
console.error("deboxWallet is not installed!");
}
console.log(
"window.ethersProvider ethers provider:",
window.ethersProvider
);
// eth_requestAccounts
async function connectWallet() {
console.log("window.deboxWallet", window.deboxWallet);
if (typeof window.deboxWallet !== "undefined") {
// connectButton.addEventListener("click", async () => {
try {
// Request account access if needed
const accounts = await window.deboxWallet.request({
method: "eth_requestAccounts",
});
console.log("eth_requestAccounts: ", accounts, typeof accounts);
// Display the connected wallet address
walletAddress.innerText = `Connected Wallet: ${accounts[0].slice(
0,
6
)}...${accounts[0].slice(-4)}`;
errorMessage.innerText = "";
requestPermissions();
} catch (error) {
// Handle error (e.g., user denied account access)
errorMessage.innerText =
"Error connecting wallet: " + error.message;
}
} else {
// If no wallet is installed
errorMessage.innerText =
"No Ethereum wallet found. Please install DeBoxWallet.";
}
}
// wallet_requestPermissions
async function requestPermissions() {
console.log("testSDK run wallet_requestPermissions");
if (typeof window.deboxWallet !== "undefined") {
try {
window.deboxWallet
.request({
method: "wallet_requestPermissions",
params: [
{
eth_accounts: {},
},
],
})
.then((response) => {
console.log(
"wallet_requestPermissions: ",
response,
typeof response
);
});
} catch (error) {
console.error(error);
alert(error.message);
}
} else {
// If no wallet is installed
errorMessage.innerText =
"No Ethereum wallet found. Please install DeBoxWallet.";
}
}
// requestPermissionsParams
async function requestPermissionsParams() {
console.log("testSDK run wallet_requestPermissions");
if (typeof window.deboxWallet !== "undefined") {
try {
window.deboxWallet
.request({
method: "wallet_requestPermissions",
params: [
{
eth_accounts: {
debox_getUserInfo: {},
debox_getVBoxBalance: {},
},
},
],
})
.then((response) => {
console.log(
"wallet_requestPermissions_params: ",
response,
typeof response
);
const item = response[0]; // []
const deboxUserInfo = item.caveats.find(
(caveat) => caveat.type === "debox_user_public_info"
);
if (deboxUserInfo) {
const avatar = deboxUserInfo
? deboxUserInfo.value.avatar
: null;
const name = deboxUserInfo ? deboxUserInfo.value.name : null;
const address = deboxUserInfo
? deboxUserInfo.value.address
: null;
const uid = deboxUserInfo ? deboxUserInfo.value.uid : null;
console.log(
"wallet_requestPermissions_params data",
response?.[0]?.caveats?.[1]
);
const imgElement = document.getElementById("walletAvatar");
imgElement.src = avatar;
walletNickName.innerText = `NickName: ${name}`;
walletAddress.innerText = `Connected Wallet: ${address?.slice(
0,
6
)}...${address?.slice(-4)}`;
walletUid.innerText = `uid: ${uid}`;
errorMessage.innerText = "";
}
});
} catch (error) {
console.error(error);
alert(error.message);
}
} else {
// If no wallet is installed
errorMessage.innerText =
"No Ethereum wallet found. Please install DeBoxWallet.";
}
}
// debox_getUserInfo
async function getUserInfo() {
console.log("testSDK run debox_getUserInfo");
window.deboxWallet
.request({
method: "debox_getUserInfo",
params: [],
})
.then((response) => {
console.log("debox_getUserInfo", response, typeof response);
if (response) {
const imgElement = document.getElementById("walletAvatarUser");
imgElement.src = response?.avatar;
walletNickNameUser.innerText = `NickName: ${response?.name}`;
walletAddressUser.innerText = `Connected Wallet: ${response?.address?.slice(
0,
6
)}...${response?.address?.slice(-4)}`;
walletUidUser.innerText = `uid: ${response?.uid}`;
errorMessage.innerText = "";
}
})
.catch((error) => {
console.error(error);
alert(error.message);
});
}
// debox_getVBoxBalance
async function getVBoxBalance() {
console.log("testSDK run debox_getVBoxBalance");
window.deboxWallet
.request({
method: "debox_getVBoxBalance",
params: [],
})
.then((response) => {
console.log("debox_getVBoxBalance", response, typeof response);
walletAddressBalance.innerText = `vBOX: ${response?.usable_balance}`;
})
.catch((error) => {
console.error(error);
alert(error.message);
});
}
// debox_paymentVBox
async function paymentVBox() {
console.log("testSDK run debox_paymentVBox");
if (typeof window.deboxWallet !== "undefined") {
const walletUid = document.getElementById("walletUid");
const addressInput = document.getElementById("addressInput");
const amountInput = document.getElementById("amountInput");
const donationAmountInput = document.getElementById(
"donationAmountInput"
);
const noteInput = document.getElementById("noteInput");
let receiver_address = addressInput.value;
let amount = amountInput.value;
let donation_amount = donationAmountInput.value;
let note = noteInput.value;
console.log(walletUid.innerText, amount, donation_amount, note);
if (!receiver_address) {
alert("Please enter receiver");
return;
}
window.deboxWallet
.request({
method: "debox_paymentVBox",
params: [
{
receiver_address: receiver_address, // address of the receiver
amount: amount || 0.01, // amount of payment, minimum 0.01
// nonce: 0, // integer, optional
note: note || "buy a cup of coffee in the game",
donation_amount: donation_amount || 40,
},
],
})
.then((response) => {
console.log("debox_paymentVBox", response, typeof response);
orderIdShow.innerText = `${response?.order_id}`;
})
.catch((error) => {
console.error(error);
alert(error.message);
});
} else {
errorMessage.innerText =
"No Ethereum wallet found. Please install DeBoxWallet.";
}
}
2. 链上支付接入 Shares
链上 Shares 是一种实时的分佣方式。当用户使用 Token 进行支付时,部分支付金额会被自动捐赠给 DeBox Shares 协议进行分佣,完成收益分配。
开发者只需微调 Dapp 支付部分逻辑,即可快速实现高度定制化的链上支付分佣功能。
2.1 链上支付分佣的调用过程
链上支付的分佣有两类:链上原生代币(ETH)支付分佣;ERC20代币支付分佣:
2.1.1 链上原生代币(ETH)支付分佣
链上原生代币(ETH)支付分佣分两步:计算分佣金额;调用合约的捐赠函数以触发后续处理。
-
计算分佣金额
- Dapp 根据业务设计,计算通过 DeBox Shares 分配的分佣金额额。
-
调用
donationToShares
方法,同时附加分佣金额,触发后续分佣逻辑:- Dapp 在完成分佣金额计算后,调用 DeBox Shares 合约的
donationToShares
方法,将计算好的金额正式进行分佣。
// ...
uint256 donatedAmountETH = amountAcquiredETH / 10; // 计算分佣金额
doxShares.donationToShares{ value: donatedAmountETH }(); // 触发 后续分佣逻辑
// ... - Dapp 在完成分佣金额计算后,调用 DeBox Shares 合约的
-
示例合约逻辑
-
Dapp 合约集成 Shares 协议示例:
// SPDX-License-Identifier: Apache License 2.0
pragma solidity ^0.8.22;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IDeBoxShares } from "@debox/deboxdapp/interfaces/facets/IShares.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract PlayGameWithShares {
IDeBoxShares public doxShares;
event GamePlayed(address player, IERC20 token, uint256 amount);
constructor(IDeBoxShares _doxShares) {
doxShares = _doxShares;
}
// Dapp中,集成了Shares协议的ETH支付函数
function playGameWithETH() external payable {
uint256 amount = msg.value;
uint256 donatedAmount = amount / 10;
if (donatedAmount > 0) {
doxShares.donationToShares{ value: donatedAmount }();
}
emit GamePlayed(msg.sender, IERC20(address(0)), amount);
}
}
2.1.2 ERC20代币支付分佣
ERC20代币支付分佣分两步:计算分佣金额并授权 DeBox Shares 合约;调用合约的捐赠函数以触发后续处理。
-
计算分佣金额,将权限授予 DeBox-Shares 合约
- 首先,Dapp将用户支付的代币转入Dapp合约,并根据业务设计,计算通过 DeBox Shares 分配的分佣金额。
- 然后,合约调用
safeIncreaseAllowance
方法,将分佣金额的使用权限授予 DeBox Shares 合约地址。
// ...
SafeERC20.safeTransferFrom(token, msg.sender, address(this), amount); // 将用户支付的代币转入 Dapp 合约
uint256 donatedAmount = amountAcquired / 10; // 计算通过 DeBox Shares 分配的分佣金额
SafeERC20.safeIncreaseAllowance(token, address(doxShares), donatedAmount); // 将分佣金额的使用权限授予 DeBox Shares 合约
// ... -
调用
donationToShares
方法,触发后续分佣逻辑- 合约授予分佣金额使用权后,调用 DeBox Shares 合约的
donationToShares
方法,将计算好的金额正式进行分佣。 - 该方法会触发 DeBox Shares 协议的后续处理逻辑,将分佣金额转入 DAO 资产池或分配给受益方等。
// ...
// 上述的计算分佣金额、授予权限逻辑
// ...
doxShares.donationToShares(token, donatedAmount); // 触发后续分佣逻辑
// ... - 合约授予分佣金额使用权后,调用 DeBox Shares 合约的
-
示例合约逻辑
-
Dapp 合约集成 Shares 协议示例:
// SPDX-License-Identifier: Apache License 2.0
pragma solidity ^0.8.22;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IDeBoxShares } from "@debox/deboxdapp/interfaces/facets/IShares.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract PlayGameWithShares {
IDeBoxShares public doxShares;
event GamePlayed(address player, IERC20 token, uint256 amount);
constructor(IDeBoxShares _doxShares) {
doxShares = _doxShares;
}
// Dapp中的集成了Shares协议的ERC20代币支付函数
function playGame(IERC20 token, uint256 amount) external {
SafeERC20.safeTransferFrom(token, msg.sender, address(this), amount);
uint256 donatedAmount = amount / 10;
if (donatedAmount > 0) {
SafeERC20.safeIncreaseAllowance(token, address(doxShares), donatedAmount);
doxShares.donationToShares(address(token), donatedAmount);
}
emit GamePlayed(msg.sender, token, amount);
}
2.2 Shares 合约接口:
-
DeBox-shares 合约接口:
// SPDX-License-Identifier: Apache License 2.0
pragma solidity ^0.8.22;
interface IDeBoxShares {
event DonationToShares(address indexed contributor, address indexed token, uint256 amount);
event SharesConfigSet(address vault, address weth);
/**
* @notice Donate tokens to the shares protocol.
* @dev The donated tokens will be transferred to the vault.
* before the donation, the caller must approve me to spend the token.
* @param token The token to donate. must be a valid ERC20 token.
* @param amount The amount of `token` to donate. must be greater than 0.
*/
function donationToShares(address token, uint256 amount) external;
/**
* @notice Donate Native coin (ETH) to the shares protocol.
*/
function donationToShares() external payable;
function getSharesConfig() external view returns (address vault, address weth);
}