ComBoox - 白皮书
  • 👋欢迎访问ComBoox!
  • 🚀系统综述
    • 🎆系统综述
      • ⛔公司治理难题
      • 💡区块链解决方案
      • 💰通证化与公司估值
      • ✨特点与优势
    • ⚙️设计理念和基本架构
      • 🖥️计算控制模型
      • 🏗️系统架构
      • 🚷身份识别与权限控制
      • 📐合约模版及版本控制
      • 💰CBP代币与系统经济模型
      • 💸财务记录
      • ☝️几个关键性法律问题
    • 🥇许可协议
  • 🕹️操作指南
    • 🛣️新手上路
    • ✒️起草《股东协议》
    • 💺提名董事并取得席位
    • 🗞️股权投资与股份交易
  • 📚技术手册
    • 🌻核心对象
      • 🗞️股份及股份库
      • 👨‍👨‍👧‍👧股东及股东库
      • 💺职位及官员库
      • 🗳️动议及动议库
        • ✍️委托代理映射表
        • 🗳️表决票及表决票箱
      • 🛍️交易及交易库
        • 🔄互换合约及互换合约库
      • 📈卖单及卖单库
      • 📑质权及质权库
      • ⚖️期权及期权库
      • 📏规则及其解析库
      • 🍵反稀释条款
      • 🔐锁定期条款
      • 🚜随售拖售条款
      • 🛸期权条款
    • 🛠️数据结构及组件
      • ⏱️历史状态序列库
      • 🏁T型链表库
      • 🥇黄金链表库
      • 🔤可枚举集合库
      • 🔄条件及条件库
      • 🔐哈希锁及保险箱
      • 🖋️签名及签字页
      • 📂文件及文件库
      • 🗄️文档及文档库
    • 👨‍🚀身份及身份识别
      • 😜角色及角色库
      • 🚷访问控制合约
      • 🦸用户及用户库
    • 🏄‍♀️法律行为及逻辑流程
      • 🤝股权交易
Powered by GitBook
On this page
  1. 系统综述
  2. 设计理念和基本架构

财务记录

系统允许使用ETH和USDC作为价值载体,支付新股认购款或股转对价;同时,也允许系统中簿记的公司对外支付ETH/USDC,或者在调用外部智能合约时,携带ETH以支付特定法律行为的费用或对价。

为方便用户自动簿记这些价值收支活动的财务记录,系统在总管理人合约、相关的分项管理人合约以及收银台合约中设置了事件日志,以便可以实时、自动检索、汇总这些价值支付活动的财务记录。

(1)兑换比价

1. ETH/记账法币兑换费率

在系统中创设公司簿记时,可自由设定公司的记账货币币种。目前系统允许设定的币种包括:人民币、美元、日元、欧元、英镑等主流国家的法定货币币种。在股权交易时,系统将自动调用Chain Link Price Feed 服务,获取交易当时该服务提供的记账法币与ETH的汇率比价,按成交的法定货币金额自动计算并交割ETH,券款对付。

2. ETH/CBP兑换费率

系统通过燃料库合约对外发售CBP代币。ETH/CBP的兑换费率由平台所有者决定。目前平台的兑换费率为1:1。平台用户可实时检索该兑换费率。

3. USDC

USDC锚定美元,每个USDC的价格为1美元。

(2)CBP收支记录

作为ERC-20标准化代币,CBP的收支记录由注册中心合约统一簿记,自动记录每一笔转账记录的支付方、收款方和支付金额。用户可根据CBP的支付方、收款方角色进一步区分CBP支付的具体场景、支付理由。例如,当支付方为“零地址”时,代表平台向收款方铸币;当支付方为燃料库合约地址时,为充值购入CBP。

// CBP支付行为的事件日志接口
event Transfer(address indexed from, address indexed to, uint256 indexed value);
(3)ETH收支记录

所有以ETH作为结算方式的股权交易行为的调用指令,只能由总管理人合约统一接收。因此,随交易行为一并支付的ETH也直接由总管理人合约统一收取并存储。之后,总管理人合约将会把相关股权交易指令分别路由至特定的分项管理人合约,由分项管理人合约逐一计算ETH款项的收款用户编号和具体收款金额,并将相关信息反馈给总管理人合约。最后,总管理人合约再根据分项管理人合约反馈信息,将ETH款项划归特定用户的暂存款账户或保证金账户。

例如,当买方通过ETH支付协议股转交易的对价时,总管理人合约会接收并存储随指令支付的ETH,然后将调用指令路由至投资协议管理人合约,投资协议管理人会计算股转交易的成交总金额,调用Chain Link Price Feed服务查询当时的ETH兑换汇率,然后向总管理人合约反馈ETH记账指令,将成交总价对应的ETH记入卖方暂存款账户、将超出成交总价的ETH余额记入买方暂存款账户。

1. 公司的ETH收入

对于股东实缴出资款、股权认购款这种支付给公司的ETH,分项管理人合约只会通过事件日志记录下来款项支付理由,总管理人合约也不会将这些ETH划归暂存款账户或保证金账户。

公司ETH收款事件日志表

交易场景
事件名称
记录参数

支付增资交易款

PayOffCIDeal

支付人用户编号、ETH金额

支付实缴出资

PayInCapital

股权证书编号、出资金额、ETH金额

摘牌新股发行订单

CloseBidAgainstInitOffer

买方、ETH金额

2. 公司的ETH支付

公司的对外支付的ETH,均需要按照股东协议合约规定的公司治理流程,经过股东会决议或董事会决议的批准才能对外支付,实质上是股东会决议或董事会决议的执行过程。

公司对外支付事件日志表

交易场景
事件名称
记录参数

股东会批准的支付

TransferFund

收款用户编号、币种(CBP/ETH)、支付金额、动议编号、执行用户编号

股东会批准的行为

ExecAction

目标合约地址、ETH金额、调用指令内容、动议编号、执行用户编号

利润分配

DistributeProfits

分配ETH总额、动议编号、执行用户编号

董事会批准的支付

TransferFund

收款用户编号、币种(CBP/ETH)、支付金额、动议编号、执行用户编号

董事会批准的行为

ExecAction

目标合约地址、ETH金额、调用指令内容、动议编号、执行用户编号

3. ETH暂存款

(1) 存入保管箱函数

总管理人合约通过存入保管箱函数统一管理ETH款项的划拨、记账活动。该函数仅记录收款用户编号、具体金额和款项用途。其中,款项用途通过Bytes32定长数组以ASCII编码格式简单记录相关用途的摘要信息。

// 存入保管箱函数

function saveToCoffer(uint acct, uint value, bytes32 reason) external{
    require(msg.sender == _keepers[4] ||
        msg.sender == _keepers[5] ||
        msg.sender == _keepers[6] ||
        msg.sender == _keepers[7] ||
        msg.sender == _keepers[10],
        "GK.saveToCoffer: not correct Keeper");
    require(address(this).balance >= _coffers[0] + value,
        "GK.saveToCoffer: insufficient Eth");
    _coffers[acct] += value;
    _coffers[0] += value;
    emit SaveToCoffer(acct, value, reason);
}

存入用户暂存款账户的ETH,仅能由特定用户通过总管理人合约的取出存款函数一次性取出,任何其他账户均无法挪用或取出。

(2) 取出暂存款函数

// 取出暂存款函数
function pickupDeposit() external isNormal{
    uint caller = _msgSender(msg.sender, 18000);
    uint value = _coffers[caller];
    if (value > 0) {
        _coffers[caller] = 0;
        _coffers[0] -= value;
        Address.sendValue(payable(msg.sender), value);
        emit PickupDeposit(msg.sender, caller, value);
    } else revert("GK.pickupDeposit: no balance");
}

(3) 暂存款用途编码表

ETH暂存款收支的分项管理人合约、款项用途摘要及其ASCII编码,请见下表。

暂存款用途编码表

交易场景
分项管理人
用途摘要
ASCII编码(Bytes32 in Hex)

利润分配

GMMKeeper

DistributeProfits

0x4469737472696275746550726f66697473000000000000000000000000000000

存入卖单对价

LOOKeeper

CloseBidAgainstOffer

0x436c6f7365426964416761696e73744f66666572000000000000000000000000

存回买单余额

LOOKeeper

DepositBalanceOfBidOrder

0x4465706f73697442616c616e63654f664269644f726465720000000000000000

存入协议股转对价

ROAKeeper

DepositConsiderationOfSTDeal

0x4465706f736974436f6e73696465726174696f6e4f6653544465616c00000000

存回协议交易余额

ROAKeeper

DepositBalanceOfOTCDeal

0x4465706f73697442616c616e63654f664f54434465616c000000000000000000

存回实缴出资余额

ROMKeeper

DepositBalanceOfPayInCap

0x4465706f73697442616c616e63654f66506179496e4361700000000000000000

存入互换交易对价

ROOKeeper

DepositConsiderationOfSwap

0x4465706f736974436f6e73696465726174696f6e4f6653776170000000000000

存回互换交易余额

ROOKeeper

DepositBalanceOfSwap

0x4465706f73697442616c616e63654f6653776170000000000000000000000000

存入否决交易对价

ROOKeeper

DepositConsiderOfRejectedDeal

0x4465706f736974436f6e73696465724f6652656a65637465644465616c000000

存回否决交易余额

ROOKeeper

DepositBalanceOfRejectedDeal

0x4465706f73697442616c616e63654f6652656a65637465644465616c00000000

4. ETH保证金

(1) 存入ETH保证金

系统允许用户在挂牌交易(ETH)登记簿以定价买单、市价买单、定价卖单、市价卖单、定价发行订单五种订单挂牌交易标的公司的股份。挂牌定价买单时,系统需要将买方随单支付的ETH作为保证金存入买方用户的保证金账户。

存入保证金时,系统仍旧调用总管理人合约的存入保管箱函数,只是将买方用户编号复写两次并连接在一起作为账户持有人。这样,既可以甄别不同用户,又可以防止用户本人或任何其他用户取出保证金。

// 存入保证金算法举例
uint acct = bid.buyer;
acct = (acct << 40) + acct;
_gk.saveToCoffer(
    acct, bid.consideration,
    bytes32(0x437573746f647956616c75654f664269644f7264657200000000000000000000)
    ); // CustodyValueOfBidOrder

(2) 释放ETH保证金

挂牌卖单或发行订单时,系统会率先与已有买单进行交易撮合,成交后会将随买单锁定的保证金作为股转对价释放给卖方的暂存账户,或者作为增资对价释放给公司。

释放保证金时,会调用总管理人合约的释放保证金函数,通过事件日志自动记录付款方、收款方、金额和款项用途。与暂存款相似,也是通过Bytes32定长字符数组以ASCII编码保存款项用途的摘要说明。

// 释放保证金函数
function releaseCustody(uint from, uint to, uint amt, bytes32 reason) external isNormal {
    require (msg.sender == _keepers[10], "GK.releaseCustody: wrong Keeper");
    uint acct = (from << 40) + from;
    uint value = _coffers[acct];
    require (value >= amt, "GK.releaseCusotody: insufficient");
    _coffers[acct] -= amt;
    if (to > 0) { _coffers[to] += amt;
    } else { _coffers[0] -= amt;}
    emit ReleaseCustody(from, to, amt, reason);
}

(3) ETH保证金用途说明

存入或释放ETH保证金的分项管理人合约、用途摘要及其ASCII编码,请见下表。

保证金用途编码表

交易场景
分项管理人
用途摘要
ASCII编码(Bytes32 in Hex)

存入买单保证金

LOOKeeper

CustodyValueOfBidOrder

0x437573746f647956616c75654f664269644f7264657200000000000000000000

释放保证金给公司

LOOKeeper

CloseInitOfferAgainstBid

0x436c6f7365496e69744f66666572416761696e73744269640000000000000000

释放保证金给卖方

LOOKeeper

CloseOfferAgainstBid

0x436c6f73654f66666572416761696e7374426964000000000000000000000000

返还买单保证金

LOOKeeper

RefundValueOfBidOrder

0x526566756e6456616c75654f664269644f726465720000000000000000000000

(4)USDC收支记录

所有以USDC作为结算方式的股权交易行为的调用指令,只能由美元登记簿管理员合约接收。收银台合约持有、接收、转发、转让和分配并且随交易行为一并支付的USDC,并记录所有此类USDC支付活动。

1. 公司的USDC收入

对于股东实缴出资款、股权认购款这种支付给公司的USDC,收银台合约只会通过事件日志记录支付原因,不会将这些USDC分配到USDC暂存账户或保证金账户。

// USDC收入函数
function collectUsd(TransferAuth memory auth, bytes32 remark) external anyKeeper {
    _transferWithAuthorization(auth);
    emit ReceiveUsd(auth.from, auth.value, remark);
}

2. 公司的USDC支付

除前述的USDC分配场景外,公司的任何其他 USDC支付也应按照股东协议合约中规定的公司治理程流程,经过股东会决议或董事会决议的批准才能对外支付,实质上是股东会决议或董事会决议的执行过程。

被授权的执行者需要调用总管理人合约的董事会批准的行为函数或股东会批准的行为函数,进一步调用收银台合约的USDC支付函数来执行相关支付行为。

// 收银台合约的USDC支付函数
function transferUsd(address to, uint amt, bytes32 remark) external anyKeeper {
    require(balanceOfComp() >= amt, "Cashier.transferUsd: insufficient amt");
    emit TransferUsd(to, amt, remark);
    require(_usd().transfer(to, amt),"Cashier.transferUsd: transfer failed");
}
// 收银台合约的事件和数据结构
struct TransferAuth{
 address from;
 address to;
 uint256 value;
 uint256 validAfter;
 uint256 validBefore;
 bytes32 nonce;
 uint8 v;
 bytes32 r;
 bytes32 s;
}

event ReceiveUsd(address indexed from, uint indexed amt);
event ReceiveUsd(address indexed from, uint indexed amt, bytes32 indexed remark);
event ForwardUsd(address indexed from, address indexed to, uint indexed amt, bytes32 remark);
event CustodyUsd(address indexed from, uint indexed amt, bytes32 indexed remark);
event ReleaseUsd(address indexed from, address indexed to, uint indexed amt, bytes32 remark);
event TransferUsd(address indexed to, uint indexed amt, bytes32 indexed remark);
event DistributeUsd(uint indexed amt);
event PickupUsd(address indexed msgSender, uint indexed caller, uint indexed value);

3. USDC暂存款

(1) 美元利润分配函数

由于USDC的价格等于每单位1.00美元,因此以 USDC 进行的支付不会产生余额或零钱,任何对价或退款将直接结算到相关用户的账户中。

然而,如果公司向其成员分配任何 USDC,则相应金额将在名为“_lockers”的私有映射中按每个成员的用户编号进行分配。此后,成员可以根据自己的意愿随时提取分配的款项。

// Some收银台合约中的“_lockers”映射和美元利润分配函数
mapping(uint => uint) private _lockers;
function distributeUsd(uint amt) external {
    require(msg.sender == address(_gk), "Cashier.DistrUsd: not GK");
    require(balanceOfComp( ) >= amt, "Cashier.DistrUsd: insufficient amt");
    IRegisterOfMembers _rom = _gk.getROM( );
    uint[ ] memory members = _rom.membersList();
    uint len = members.length;
    uint totalPoints = _rom.ownersPoints( ).points;
    uint sum = 0;
    while (len > 1) {
        uint member = members[len - 1];
        uint pointsOfMember = _rom.pointsOfMember(member).points;
        uint value = pointsOfMember * amt / totalPoints;
        _lockers[member] += value;
        _lockers[0] += value;
        sum += value;
        len--;
    }
    _lockers[members[0]] += (amt - sum);
    _lockers[0] += (amt - sum);
    emit DistributeUsd(amt);
}

(2) 取出美元函数

存入暂存款账户的USDC,仅能由特定用户通过调用收银台合约的取出美元函数来提取,任何其他账户均无法挪用或取出。

// 取出美元函数
function pickupUsd() external {
  uint caller = _msgSender(msg.sender, 18000);
   uint value = _lockers[caller];
 
  if (value > 0) {
   _lockers[caller] = 0;
   _lockers[0] -= value;
   emit PickupUsd(msg.sender, caller, value);
   require(_usd().transfer(msg.sender, value), "Cashier.PickupUsd: transfer failed");
 } else revert("Cashier.pickupDeposit: no balance");
}

4. USDC保证金

(1) 存入USDC保证金

系统允许经过验证的投资者在挂牌交易(USDC)登记簿的智能合约中以定价买单、市价买单、定价卖单、市价卖单、定价发行单和市价发行单六种订单挂牌交易标的公司的股份。挂牌定价买单时,系统需要将买方随单支付的USDC存入买方的保证金账户。

在存入保证金时,系统将调用收银台合约的美元托管函数,并将相关金额存入一个名为 “_coffers” 的私有映射中。这样,既可以甄别不同用户,又可以防止用户本人或任何其他用户取出保证金。

// 收银台合约的美元托管函数
mapping(address => uint) private _coffers;
function _transferWithAuthorization(TransferAuth memory auth) private {
    _usd().transferWithAuthorization(
    auth.from,
    address(this),
    auth.value,
    auth.validAfter,
    auth.validBefore,
    auth.nonce,
    auth.v,
    auth.r,
    auth.s
);
}
function custodyUsd(TransferAuth memory auth, bytes32 remark) external anyKeeper {
    _transferWithAuthorization(auth);
    _coffers[auth.from] += auth.value;
    _coffers[address(0)] += auth.value;
    emit CustodyUsd(auth.from, auth.value, remark);
}

(2) 释放USDC保证金

释放保证金时,会调用收银台合约的释放美元函数,通过事件日志自动记录付款人、收款人、金额和付款原因。与暂存款相似,也是通过Bytes32定长字符数组以ASCII编码保存款项用途的摘要说明。

// 释放美元函数
 
function releaseUsd(address from, address to, uint amt, bytes32 remark) external anyKeeper {
  require(_coffers[from] >= amt, "Cashier.ReleaseUsd: insufficient amt");
  _coffers[from] -= amt;
  _coffers[address(0)] -= amt;
  emit ReleaseUsd(from, to, amt, remark);
  require(_usd().transfer(to, amt), "Cashier.releaseUsd: transfer failed");
}

(3) USDC保证金用途说明

下表总结了存入或释放USDC保证金的原因及其ASCII编码,请见下表:

USDC保证金用途说明

情形
摘要
ASCII代码

存入买单保证金

CustodyValueOfBid

0x437573746f647956616c75654f66426964000000000000000000000000000000

释放保证金给公司

CloseInitOfferAgainstBid

0x436c6f7365496e69744f66666572416761696e73744269640000000000000000

释放保证金给卖方

CloseOfferAgainstBid

0x436c6f73654f66666572416761696e7374426964000000000000000000000000

返还买单保证金

RefundValueOfBidOrder

0x526566756e6456616c75654f664269644f726465720000000000000000000000

相关源代码

PreviousCBP代币与系统经济模型Next几个关键性法律问题

Last updated 1 month ago

| |

🚀
⚙️
💸
RegCenter
GeneralKeeper
Cashier