如何使用加密货币创建“公共物品”而不给投资者带来风险



在本文中,我将讨论什么是保证合同,也被称为提供公共利益和团体利益的机制,我们将共同在Obyte平台上编写基于自主代理的众筹实施方案。

保证合同是一种用于创建新公共物品的有组织的筹款机制。 使用此类合同的一个典型示例可能是以下情况:夏季合作社的参与者决定修建一条道路,以方便前往夏季小屋。 为此,收集金额N并将其转移给承包商以修建道路。 出现了许多问题:在哪里找到一个每个人都会信任并收费的人;如何使道路的所有潜在用户投资于道路建设;如果收集到的钱不足,会发生什么?

保证合同的含义与众筹非常相似,只有投资者没有风险,就像投资风险企业的投资者一样。 这样的合同以及众筹也可以有两个结果-成功和不成功,这取决于所收集金额目标的实现。 成功收款的结果将是投资者(但有时不仅是投资者)收到一种新的公共物品。 万一发生故障,钱只会退还给储户。

因此,对于初学者,我们重复一下基本条件。 众筹的本质是以给定的最终金额(不一定是固定的,可以是动态的)和结束日期(也并非总是,但是通常)为预定目标“在人群中”筹集资金。 当达到此金额时,就认为该轮融资成功并且停止了筹款,所有资金都被分配用于实现目标。 万一失败,也就是说,在截止日期前且筹集的资金不足,所有资金将退还给捐助者。

加密货币众筹解决了哪些问题? 首先,它使投资者不必信任和验证汇款人。 自主募集代理的代码是公开的,每个投资者都可以确保自己可以随时提取捐款,直到达到最终金额,而且所有资金都将被发送到预先选定的地址以创建商品。 其次,对所有筹集资金的透明核算有助于按目标实现所分配的贡献来分配实现目标的未来收益。

保证合同可以解决的另一个问题是协调问题。 今天,我们将补充有关游戏“ Attack 51%”的上一篇文章,我们将解决此问题。 如果不使用AA,游戏中的参与者将由于缺乏协调而处于“缺乏”所收集金额的风险中。 然后,那些已经成功进行投资的人只会因为其他参与者没有表现出兴趣,或者只是没有时间去做而失去自己的钱(请记住,对立的团队只有24小时可以挑战现任领导人)。 通过保证合同收取款项,玩家将可以随时提取款项,直到收集到必要的金额为止。

在我们的案例中不适用,但是此类合同的另一个有用功能是减少“搭便车效应”或“搭便车问题”的影响。 由于公共利益,即不可剥夺或难以控制的获取,因此,搭便车问题是公共物品组织中的主要问题。 人们不希望投资于他人可以免费使用的东西,也不想投资于投资者本人,他们坚持绝对合理的经济行为,并选择了“非投资”策略(如果成功收集),很可能能够使用所创造的商品。

我还将讨论优化担保合同的选择,它增加了成功筹集资金的机会,因为 参与者的理性行为已经是投资策略的选择,而不是无视。

我们集体玩游戏


对于我们的示例,我们将使用上一篇文章中已知的游戏“ Attack 51%”。
在当前的实施方式中,游戏参与者将钱转至游戏的AA地址。 但是可以改进算法,并且可以减少参与者在失去团队的情况下赔钱的机会。
为此,任何团队成员都可以组织动态目标至少等于游戏总池数51%的众筹。 随着资金池的增长,最终的众筹目标也将发生变化。 而且只有成功了,这笔钱才会被发送到游戏的AA地址,团队将立即成为当前的领导者。 如果从未发生过这样的事件,那么参与者将不会损失他们的钱,白白浪费游戏池,而只是从筹集AA的资金中拿走钱。

两种独立代理的原件始终可以在在线Oscript代码编辑器中以模板的形式获得,只需从下拉菜单中选择“ 51% Attack game”和“ Fundraising proxy”即可。

在您开始用Oscript编写AA之前,强烈建议您阅读我们文档中的入门指南 (eng),以快速熟悉编写AA的基本原理。

编写代码


首先,我们编写算法:施主将字节发送到AA地址,以1:1的比例返回众筹令牌。在任何时候,他都可以将这些令牌交换回字节。 收到字节后,机管局会检查我们是否已达到筹集资金的目标,如果是,则将所有字节发送到游戏机管局的地址并作为回报接收游戏令牌(团队令牌)。 捐献者现在可以将其众筹代币交换为游戏代币,如果团队获胜,将来可以通过AA游戏将其交换为字节,从原始游戏中最多接收2字节。

因此,让我们开始吧。

新筹款期间的启动处理单元。 收到传入数据消息中到达AA地址的“开始”字段后,我们将发行众筹令牌并将其写入状态,还将其作为响应返回给调用方。

{ // start a new fundraising period if: `{trigger.data.start AND !$asset}`, messages: [ { app: 'asset', payload: { is_private: false, is_transferrable: true, auto_destroy: false, fixed_denominations: false, issued_by_definer_only: true, cosigned_by_definer: false, spender_attested: false } }, { app: 'state', state: `{ var[response_unit || '_status'] = 'open'; var['asset'] = response_unit; response['asset'] = response_unit; }` } ] }, 

处理捐助者的存款。 首先,我们过滤掉非常少量的垃圾交易,即使是佣金也不够。 接下来,检查游戏未完成且可以收集的基本条件。 完整的清单清单:

 { // contribute if: `{trigger.output[[asset=base]] >= 1e5 AND $asset}`, init: `{ if (var[$destination_aa]['finished']) bounce('game over'); $amount = trigger.output[[asset=base]] - 2000; // to account for fees we need to respond now and to refund bytes or pay shares later $total_raised = var['total_raised'] + $amount; $missing_amount = ceil((balance[$destination_aa][base] + $total_raised)*0.51) - var[$destination_aa]['team_' || $team || '_amount']; $bDone = ($total_raised > $missing_amount); }`, messages: [ { app: 'payment', payload: { asset: "{$asset}", outputs: [{address: "{trigger.address}", amount: "{$amount}"}] } }, { if: `{$bDone}`, app: 'payment', payload: { asset: "base", outputs: [{address: "{$destination_aa}", amount: "{$total_raised}"}] } }, { if: `{$bDone}`, app: 'data', payload: { team: "{$team}" } }, { app: 'state', state: `{ if ($bDone) var[$asset || '_status'] = 'raised'; else var['total_raised'] = $total_raised; }` } ] }, 

初步检查后,我们机管局的主要逻辑立即变为:

$total_raised = var['total_raised'] + $amount; -在这里,我们将刚收到的金额总结为代理商的资金总额。

$missing_amount = ceil((balance[$destination_aa][base] + $total_raised)*0.51) - var[$destination_aa]['team_' || $team || '_amount']; -检查新筹集的资金足以赢得比赛。 请注意对另一个AA变量的余额和状态的引用: balance[$destination_aa][base]var[$destination_aa]['team_' || $team || '_amount'] var[$destination_aa]['team_' || $team || '_amount'] var[$destination_aa]['team_' || $team || '_amount']

我们在init块中完成所有这些操作,该init块在每次处理事务消息之前都会被调用。 显然,对传入事务的答案是相对于接收到的字节( 消息数组的第一块)以一对一的比率发送AA令牌。 仅当局部变量$ bDone设置为true (在init块中设置)时,才会执行第二和第三块。 在其中,我们会将所有资金从该AA地址发送到AA游戏地址,以接收游戏代币。 在消息的最后一块中,我们仅更新状态,设置必要的状态和收集的数量。

处理来自AA游戏的已接收令牌,它们已经位于我们AA的余额上,我们只需要更改代理的状态即可:

 { // received team asset if: `{trigger.output[[asset=var[$destination_aa]['team_' || $team || '_asset']]] AND $asset}`, messages: [ { app: 'state', state: `{ var[$asset || '_status'] = 'done'; var['asset'] = false; var['total_raised'] = false; }` } ] }, 

玩家投资的拒绝。 我们允许您随时拒绝参加并收回您的字节数。 为此,玩家发送此AA的令牌,然后我们在返回交易中向他发送相同的字节:

 { // refund if: `{$asset AND trigger.output[[asset=$asset]] > 0}`, init: `{ $amount = trigger.output[[asset=$asset]]; }`, messages: [ { app: 'payment', payload: { asset: "base", outputs: [{address: "{trigger.address}", amount: "{$amount}"}] } }, { app: 'state', state: `{ var['total_raised'] -= $amount; }` } ] }, 

将我们的AA令牌交换为游戏令牌。 我们只发送与我们的AA余额(如果通过if块的情况下)相等的游戏代币,其数量等于收到的“我们的”代币的数量。

 { // pay the obtained team asset in exchange for the issued asset if: `{ $in_asset = trigger.output[[asset!=base]].asset; var[$in_asset || '_status'] == 'done' }`, messages: [ { app: 'payment', payload: { asset: "{var[$destination_aa]['team_' || $team || '_asset']}", outputs: [{address: "{trigger.address}", amount: "{trigger.output[[asset=$in_asset]]}"}] } }, ] } 

代理代码已准备就绪,下面是它的完整列表:

完整的代理商代码
 { /* This is a fundraising proxy AA. It allows to raise money up to a specific target. If the target is reached, the money is forwarded to another AA, otherwise the money is refunded. This specific example raises money for challenging the current candidate winner in 51% attack game. The target is a moving target as other teams may be adding contributions at the same time. Contributors get shares of the proxy in exchange for Bytes. They can exchange the shares back to the same amount of Bytes any time before the target is reached. As soon as the target is reached, the raised funds are forwarded to the game and the proxy receives the shares of the team in exchange. Then, the contributors can exchange the shares of the proxy for the shares of the team. */ init: `{ $asset = var['asset']; $destination_aa = 'WWHEN5NDHBI2UF4CLJ7LQ7VAW2QELMD7'; $team = 'VF5UVKDSOXPMITMDGYXEIGUJSQBRAMMN'; }`, messages: { cases: [ { // start a new fundraising period if: `{trigger.data.start AND !$asset}`, messages: [ { app: 'asset', payload: { is_private: false, is_transferrable: true, auto_destroy: false, fixed_denominations: false, issued_by_definer_only: true, cosigned_by_definer: false, spender_attested: false } }, { app: 'state', state: `{ var[response_unit || '_status'] = 'open'; var['asset'] = response_unit; response['asset'] = response_unit; }` } ] }, { // contribute if: `{trigger.output[[asset=base]] >= 1e5 AND $asset}`, init: `{ if (var[$destination_aa]['finished']) bounce('game over'); $amount = trigger.output[[asset=base]] - 2000; // to account for fees we need to respond now and to refund bytes or pay shares later $total_raised = var['total_raised'] + $amount; $missing_amount = ceil((balance[$destination_aa][base] + $total_raised)*0.51) - var[$destination_aa]['team_' || $team || '_amount']; $bDone = ($total_raised > $missing_amount); }`, messages: [ { app: 'payment', payload: { asset: "{$asset}", outputs: [{address: "{trigger.address}", amount: "{$amount}"}] } }, { if: `{$bDone}`, app: 'payment', payload: { asset: "base", outputs: [{address: "{$destination_aa}", amount: "{$total_raised}"}] } }, { if: `{$bDone}`, app: 'data', payload: { team: "{$team}" } }, { app: 'state', state: `{ if ($bDone) var[$asset || '_status'] = 'raised'; else var['total_raised'] = $total_raised; }` } ] }, { // received team asset if: `{trigger.output[[asset=var[$destination_aa]['team_' || $team || '_asset']]] AND $asset}`, messages: [ { app: 'state', state: `{ var[$asset || '_status'] = 'done'; var['asset'] = false; var['total_raised'] = false; }` } ] }, { // refund if: `{$asset AND trigger.output[[asset=$asset]] > 0}`, init: `{ $amount = trigger.output[[asset=$asset]]; }`, messages: [ { app: 'payment', payload: { asset: "base", outputs: [{address: "{trigger.address}", amount: "{$amount}"}] } }, { app: 'state', state: `{ var['total_raised'] -= $amount; }` } ] }, { // pay the obtained team asset in exchange for the issued asset if: `{ $in_asset = trigger.output[[asset!=base]].asset; var[$in_asset || '_status'] == 'done' }`, messages: [ { app: 'payment', payload: { asset: "{var[$destination_aa]['team_' || $team || '_asset']}", outputs: [{address: "{trigger.address}", amount: "{trigger.output[[asset=$in_asset]]}"}] } }, ] } ] } } 


我们没有实现最简单的算法,因为 我们的目标是动态的,这不是典型的保证合同所特有的。 在这些文件中,最常见的是目标数量以及最后期限是固定的。 这不需要对代码进行重大更改,因此让我们将其作为练习留给读者。

最好的策略是投资!


现在回到搭便车的问题。 就游戏而言,我们没有这样的问题,因为 只有众筹代币持有者才能赢。 但是,解决搭便车问题将对游戏有帮助。 我们可以“刺激”人们进行投资。 为此,筹款活动的组织者(也是AA的创建者)可以拨出少量补偿金,如果无法达到收集目的,他将自掏腰包支付。 在成功收集的情况下,组织者将占很小的比例。 就是说,我们介绍了一个第三方,为了获得利益,它将承担收款不成功的风险。

应用这种“优化的众筹”,以前“非投资”的理性行为(通常,任何公共物品搭便车都是最经济的获利策略)可能变得不如投资理性。 在创建涉及特定人员圈子的集体商品的情况下,这可能尤其相关。 这不能完全消除偷渡问题,但可以使参与成为一种理性行为。

实施“优化保证合同”的代码对于那些希望的人也将是一个有趣的练习。

Source: https://habr.com/ru/post/zh-CN475100/


All Articles