使用智能合约实现自动分账
哈哈笑417
post on 2023-1-4 14:36:20
21
0
0
文中代码已在 GitHub 上开源。https://github.com/fengluo/fibos-subaccount
设计思路
在 FIBOS 转账是通过 token 合约的extransfer方法来实现的。extransfer方法在执行的时候会给转账方账户和入账方账户发送通知。所以用户给平台方账户转账的时候,平台账户就会收到通知。所以整体业务逻辑如下:
quantity: 10 FO
memo: 内容提供者账户 quantity: 8 FO
用户账户 -------------------> 平台账户 ----------------> 内容提供者账户
extransfer 2/8 分成 extransfer
1.用户给平台方账户转账,memo 中填写内容提供者的账户名。
2.平台方的账户合约监听 extransfer 方法的通知,然后做出分账计算,给对应内容提供者的账户转账对应金额。
整体逻辑很简单,整个合约代码逻辑差不多用20行就可以写完。
编写合约
FIBOS 的智能合约分为 ABI 文件和 JS 合约两部分。ABI 相当于合约接口,JS 合约则是功能实现。本案例目前没有接口设计需求,不过 ABI 文件还是合约不可缺少的部分。所以我们简单创建一下就好。
我们先创建一个 contracts 文件夹,合约文件都会放在这里。然后在此文件夹下,创建 subaccount.abi 文件,内容为:
{
"version": "eosio::abi/1.0"
}
JS 合约部分也没有太复杂。在 contracts 文件夹下创建 subaccount.js 文件,代码为:
exports.on_extransfer = (from, to, quantity, memo) => {
// 需要在开头做一些判断
if (to === action.receiver && action.is_account(memo)) {
const num = parseInt(quantity.quantity.split(' ')[0])
// 假设我们约定平台方跟内容提供者是2/8分成。
const subnum = (num * 0.8).toFixed(4);
trans.send_inline('eosio.token', 'extransfer', {
from: to,
to: memo,
quantity: {
quantity: `${subnum} ${quantity.quantity.split(' ')[1]}`,
contract: quantity.contract
},
memo: 'sub account'
},
[
{
// 需要提供合约账户的 active 权限
actor: action.receiver,
permission: 'active'
}
]);
}
}
合约代码开头我们需要做一些验证。
1.收款方的账户为合约账户,否则因为下面代码执行给内容提供者转账时,因为转帐方也是合约账号会再次收到通知,造成无限递归,超出最大 send_inline 层数而报错。
2.我们用 memo 参数来放内容提供者的账户,所以我们需要对此参数校验一下该账户是否存在防止打错。
合约代码中我们使用 send_inline 调用 eosio.token 合约来执行转帐操作。转帐操作需要对应账户的 active 权限才能执行。为了解决权限滥用问题,FIBOS 定义了一个特殊权限 eosio.code。我们需要在平台合约账户中配置权限,在 active 权限下添加该合约账户的 eosio.code 授权。具体的配置操作会在下面说明。
在 FIBOS TestNet 上注册账号
为方便测试,我们在测试网 http://testnet.fibos.fo 上注册三个账户。
用户账号 helloworld11
内容提供者账号 helloworld22
平台合约账号 helloworld33
我们需要记录这三个账号的账户名以及公私钥。以便下面的开发使用。创建一个统一的配置文件来记录这些数据:
const config = {
// 平台合约账户的客户端配置
client: {
chainId: '68cee14f598d88d340b50940b6ddfba28c444b46cd5f33201ace82c78896793a',
httpEndpoint: 'http://testnet.fibos.fo',
keyProvider: 'PRIVATE_KEY_OF_helloworld33'
},
// 用户账户的客户端配置
callClient:{
chainId: '68cee14f598d88d340b50940b6ddfba28c444b46cd5f33201ace82c78896793a',
httpEndpoint: 'http://testnet.fibos.fo',
keyProvider: 'PRIVATE_KEY_OF_helloworld11'
},
// 平台合约账户信息
contractAccount: {
name: 'helloworld33',
publicKey: 'PUBLIC_KEY_OF_helloworld33',
privateKey: 'PRIVATE_KEY_OF_helloworld33'
},
// 用户账户信息
account1: {
name: 'helloworld11',
publicKey: 'PUBLIC_KEY_OF_helloworld11',
privateKey: 'PRIVATE_KEY_OF_helloworld11'
},
// 内容提供者账户信息
account2: {
name: 'helloworld22',
publicKey: 'PUBLIC_KEY_OF_helloworld22',
privateKey: 'PRIVATE_KEY_OF_helloworld22'
}
}
module.exports = config
配置权限
在合约代码中,我们调用了 trans.send_inline 函数调用合约 eosio.token 来实现转帐操作,但是转帐操作是需要账户的 active 权限。所以我们需要更新一下合约账户的权限,需要添加调用者的 eosio.code 授权到它的 active 权限。这个调用者自然也是这个合约账户。
const FIBOS = require('fibos.js');
const config = require('./config');
const fibosClient = FIBOS(config.client);
let ctx = fibosClient.contractSync('eosio');
var r = ctx.updateauthSync({
account: config.contractAccount.name,
permission: 'active',
parent: 'owner',
auth: {
threshold: 1,
keys: [{
key: config.contractAccount.publicKey,
weight: 1
}],
accounts: [{
permission: {
// 将调用者账号的 eosio.code 授权添加到它的 active 权限下。
actor: config.contractAccount.name,
permission: 'eosio.code'
},
weight: 1
}]
}
},{
authorization: `${config.contractAccount.name}@owner` //更改账户权限需要使用 owner 权限
});
console.log(r);
部署合约
const FIBOS = require('fibos.js');
const config = require('./config');
const fibosClient = FIBOS(config.client);
const fs = require('fs');
// setcode
const jsCode = fs.readTextFile(`${__dirname}/contracts/subaccount.js`);
fibosClient.setcodeSync(config.contractAccount.name, 0, 0, fibosClient.compileCode(jsCode));
// getcode
const code = fibosClient.getCodeSync(config.contractAccount.name, true);
console.log('code:', code);
// setabi
const abi = JSON.parse(fs.readTextFile(`${__dirname}/contracts/subaccount.abi`));
fibosClient.setabiSync(config.contractAccount.name, abi);
转账测试
我们先来写一个脚本 account.js 来查看三个账户的余额。
const FIBOS = require('fibos.js');
const config = require('./config');
const fibosClient = FIBOS(config.callClient);
const account1 = fibosClient.getTableRowsSync(true, 'eosio.token', config.account1.name, 'accounts');
console.log(config.account1.name);
console.log(account1);
const account2 = fibosClient.getTableRowsSync(true, 'eosio.token', config.account2.name, 'accounts');
console.log(config.account2.name);
console.log(account2);
const contractAccount = fibosClient.getTableRowsSync(true, 'eosio.token', config.contractAccount.name, 'accounts');
console.log(config.contractAccount.name);
console.log(contractAccount);
执行 fibos account.js 来查看三个账户信息。 目前我们的账户还没有 FO,所以大致情况是这样的:
用户账户:helloworld11 金额:0.0000 FO内容提供者账户:helloworld22 金额:0.0000 FO平台合约账户:helloworld33 金额:0.0000 FO
测试网会自动给每个账户发放10 EOS 的通证用以测试使用。账户中还并没有 FO 通证。所以我们再来写一个兑换脚本,用1 EOS 换一点 FO 通证。
const FIBOS = require('fibos.js');
const config = require('./config');
const fibosClient = FIBOS(config.callClient);
let ctx = fibosClient.contractSync('eosio.token');
const r = ctx.exchangeSync(
config.account1.name,
'1.0000 EOS@eosio',
'0.0000 FO@eosio',
'exchange FO to EOS',
{
authorization: config.account1.name
}
);
console.log(r)
再次执行 fibos account.js 来查看账户信息。目前我们的账户金额大致是这样的:
用户账户:helloworld11 金额:146.4245 FO内容提供者账户:helloworld22 金额:0.0000 FO平台合约账户:helloworld33 金额:0.0000 FO
下面写个脚本 transfer.js 来执行转帐操作。
const FIBOS = require('fibos.js');
const config = require('./config');
const fibosClient = FIBOS(config.callClient);
let ctx = fibosClient.contractSync('eosio.token');
const r = ctx.extransferSync(
config.account1.name, // 用户账户
config.contractAccount.name, // 平台合约账户
'10.0000 FO@eosio', // 转帐金额
config.account2.name, // 附言填写内容提供者的账户名,平台合约会给它分账
{
authorization: config.account1.name //提供用户账户的授权
}
)
console.log(r)
我们要从用户账户 account1 给平台合约账户 account3 转帐 10 FO。memo 参数为要分成的内容提供者账户 account2。根据合约中定的2/8分成,平台合约账户 account3 将会分得2 FO,而内容提供者账户 account2 将会获得8 FO。
使用命令 fibos transfer.js 执行该脚本完成转帐操作。
下面我们再来看一下目前三个账户情况。执行命令 fibos account.js。三个账户金额大致如下。
用户账户:helloworld11 金额:136.4245 FO内容提供者账户:helloworld22 金额:8.0000 FO平台合约账户:helloworld33 金额:2.0000 FO
结果显示,分账账户和平台合约账户如预期那样获得8 FO 和2 FO。
综上,我们成功使用了智能合约实现了自动分账。平台方还可以继续根据自己业务需要定制自己的合约。
文中的代码请参考:https://github.com/fengluo/fibos-subaccount
BitMere.com is Information release platform,just provides information storage space services.
The opinions expressed are solely those of the author,Does not constitute advice, please treat with caution.
The opinions expressed are solely those of the author,Does not constitute advice, please treat with caution.
Write the first review