Comment utiliser la crypto pour créer un «bien public» sans risque pour les investisseurs



Dans l'article, je parlerai de ce qu'est le contrat d'assurance, également connu sous le nom de mécanisme pour fournir des avantages publics et collectifs, et ensemble, nous écrirons notre propre implémentation de financement participatif basée sur les agents autonomes sur la plate-forme Obyte.

Le contrat d'assurance est un mécanisme organisé de collecte de fonds pour créer un nouveau bien public. Un exemple typique de l'utilisation de tels contrats peut être la situation suivante: les participants d'une coopérative d'été ont décidé de construire une route pour un accès pratique à leurs chalets d'été. Pour ce faire, collectez le montant N et transférez-le à l'entrepreneur pour la construction de la route. De nombreuses questions se posent: où trouver une personne à qui tout le monde ferait confiance et facturerait la collecte, comment faire en sorte que tous les utilisateurs potentiels de la route investissent dans sa construction, que se passerait-il s'il n'y avait pas assez d'argent collecté, etc.

Les contrats d'assurance sont très similaires au sens du financement participatif, seuls les investisseurs ne sont pas exposés au risque, comme c'est le cas pour les investisseurs qui investissent dans des entreprises à risque. De tels contrats, ainsi que le financement participatif, peuvent également avoir deux résultats - réussis et infructueux, selon l'atteinte de l'objectif pour le montant collecté. Le résultat d'une collecte réussie sera la réception par les investisseurs, mais parfois pas seulement par eux, d'un nouveau bien public. En cas d'échec, l'argent est simplement restitué aux déposants.

Donc, pour commencer, nous répétons les conditions de base. L'essence du financement participatif est de lever des fonds "dans une foule" pour un objectif prédéterminé, avec un montant final donné (pas nécessairement fixe, il peut être dynamique) et une date de fin (pas toujours, mais généralement). Lorsque ce montant est atteint, la ronde de financement est considérée comme réussie et la collecte s'arrête, tous les fonds sont alloués pour atteindre l'objectif. En cas d'échec, c'est-à-dire après avoir atteint le délai et avec des fonds insuffisants collectés, tous les fonds seront restitués aux donateurs.

Quels problèmes le crowdfunding de crypto-monnaie résout-il? Premièrement, cela évite aux investisseurs d'avoir à faire confiance et à vérifier à qui ils envoient leur argent. Le code de l'agent autonome pour la collecte de fonds est ouvert et chaque investisseur peut s'assurer qu'il peut retirer sa contribution à tout moment jusqu'à ce que le montant final soit atteint, et que tous les fonds soient envoyés à une adresse présélectionnée pour créer le bien. Deuxièmement, une comptabilité transparente de tous les fonds levés permet de répartir les bénéfices futurs de la réalisation de l'objectif au prorata de la contribution apportée.

Un autre problème qui peut être résolu avec le contrat d'assurance est le problème de coordination. Aujourd'hui, nous compléterons notre dernier article sur le jeu "Attack 51%" , et nous allons juste résoudre ce problème. Sans l'utilisation des AA, les participants au jeu risquent de "manquer" du montant collecté en raison d'un manque de coordination. Ensuite, ceux qui ont déjà réussi à faire un investissement perdront simplement leur argent à cause d'autres participants qui n'ont pas manifesté d'intérêt ou qui n'ont tout simplement pas eu le temps de le faire (rappelez-vous que les équipes adverses ont exactement 24 heures pour défier le leader actuel). En collectant de l'argent via un contrat d'assurance, les joueurs pourront retirer leur argent à tout moment jusqu'à ce que le montant nécessaire soit collecté.

Non applicable dans notre cas, mais une autre caractéristique utile de ces contrats est de réduire l'impact de «l'effet du free rider» ou du «problème du free rider». Le bien public, c'est-à-dire soit inaliénable, soit difficile à contrôler, est le problème du free rider qui est le principal dans l'organisation des biens publics. Les gens ne veulent pas investir dans quelque chose que d'autres peuvent utiliser gratuitement, ou l'investisseur lui-même, en adhérant à un comportement économique absolument rationnel et en choisissant une stratégie de «non-investissement», en cas de succès de la collecte, est susceptible de pouvoir utiliser le bien créé.

Je parlerai également de l'option du contrat d'assurance optimisé, qui augmente les chances de succès dans la collecte de fonds, comme le comportement rationnel des participants sera déjà le choix des stratégies d'investissement, plutôt que l'ignorance.

Nous jouons au jeu collectivement


Pour notre exemple, nous prendrons le jeu «Attack 51%» déjà connu dans le dernier article.
Dans son implémentation actuelle, les participants au jeu envoient de l'argent à l'adresse AA du jeu. Mais l'algorithme peut être amélioré et les chances de perdre de l'argent par les participants en cas de perte de leur équipe peuvent être réduites.
Pour cela, tout membre de l'équipe peut organiser le crowdfunding avec un objectif dynamique égal à au moins 51% du pool total du jeu. Au fur et à mesure que le pool grandit, l'objectif final de financement participatif changera également. Et seulement en cas de succès, l'argent sera envoyé à l'adresse AA du jeu et l'équipe deviendra immédiatement le leader actuel. Si un tel événement ne se produit jamais, les participants ne perdront pas leur argent, gaspillant le pool du jeu en vain, mais prenant simplement l'argent du crowdfunding AA.

Les originaux des deux agents autonomes sont toujours disponibles dans l' éditeur de code Oscript en ligne sous forme de modèles, il suffit de les sélectionner dans le menu déroulant: "51% attack game" et "Fundraising proxy".

Avant de commencer à écrire AA dans Oscript, je vous recommande fortement de lire le Guide de démarrage (eng) dans notre documentation pour vous familiariser rapidement avec les principes de base de l'écriture AA.

Écrire un code


Tout d'abord, nous écrivons l'algorithme: le donateur envoie des octets à l'adresse AA, recevant en retour un jeton de crowdfunding dans le rapport de 1 à 1. À tout moment, il peut échanger ces jetons contre des octets. Après avoir reçu les octets, AA vérifie que nous avons atteint l'objectif de collecte de fonds, et si c'est le cas, envoie ensuite tous les octets à l'adresse des AA du jeu et reçoit en retour des jetons de jeu (jetons d'équipe). Le donateur peut désormais échanger ses jetons de financement participatif contre des jetons de jeu qui, à l'avenir, au cas où l'équipe gagnerait, pourraient déjà être échangés contre des octets via des jeux AA, recevant jusqu'à x2 octets des jeux originaux.

Commençons donc.

L'unité de traitement de démarrage de la nouvelle période de collecte de fonds. Dès réception du champ "start" dans le message de données entrant à l'adresse de notre AA, nous émettrons notre jeton de financement participatif et l'écrirons à l'état, nous le retournerons également en réponse à l'appelant.

{ // 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; }` } ] }, 

Traitement des dépôts des donateurs. Premièrement, nous filtrons les transactions indésirables avec de très petits montants, ce qui n'est pas suffisant même pour une commission. Ensuite, vérifiez les conditions de base selon lesquelles le jeu n'est pas terminé et la collecte est possible. Liste complète des blocs:

 { // 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; }` } ] }, 

Immédiatement après les vérifications initiales, la logique principale de notre AA va:

$total_raised = var['total_raised'] + $amount; - nous résumons ici le montant qui vient d'être reçu au montant total des fonds sur l'agent.

$missing_amount = ceil((balance[$destination_aa][base] + $total_raised)*0.51) - var[$destination_aa]['team_' || $team || '_amount']; - vérifiez que le nouveau montant des fonds récoltés est suffisant pour gagner la partie. Notez la référence au solde et à l'état des variables d'un autre AA: balance[$destination_aa][base] et var[$destination_aa]['team_' || $team || '_amount'] var[$destination_aa]['team_' || $team || '_amount'] var[$destination_aa]['team_' || $team || '_amount'] .

Nous faisons tout cela dans le bloc init , qui est appelé à chaque fois avant de traiter les messages de transaction. La réponse à la transaction entrante sera évidemment l'envoi de jetons AA dans un rapport un pour un par rapport aux octets reçus (le premier bloc du tableau de messages ). Les deuxième et troisième blocs ne seront exécutés que si la variable locale $ bDone est définie sur true (elle est définie dans le bloc init ). En eux, nous enverrons tous les fonds de l'adresse de cet AA à l'adresse du jeu AA, recevant en retour des jetons de jeu. Dans le dernier bloc de messages, nous mettons simplement à jour l'état, en définissant les statuts nécessaires et le montant collecté.

Traitement des jetons reçus du jeu AA, ils reposent déjà sur le solde de nos AA, il suffit de changer l'état de l'agent:

 { // 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; }` } ] }, 

Refand des investissements des joueurs. Nous vous permettons de refuser de participer à tout moment et de reprendre vos octets. Pour ce faire, le joueur envoie les jetons de cet AA, et nous lui envoyons les mêmes octets en retour de transaction:

 { // 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; }` } ] }, 

Échange de nos jetons AA contre des jetons de jeu. Nous envoyons simplement des jetons de jeu qui sont sur le solde de nos AA (dans le cas du passage du bloc if) d'un montant égal au nombre de «nos» jetons reçus.

 { // 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]]}"}] } }, ] } 

Le code de l'agent est prêt, voici une liste complète:

Code d'agent complet
 { /* 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]]}"}] } }, ] } ] } } 


Nous n'avons pas implémenté l'algorithme le plus trivial, car notre objectif est dynamique, ce qui n'est pas typique d'un contrat d'assurance typique. En eux, le plus souvent, le montant cible est fixe, ainsi que le délai. Cela ne nécessitera pas de changements majeurs dans le code, alors laissons cela comme un exercice pour le lecteur.

La meilleure stratégie est d'investir!


Et maintenant, revenons au problème du free rider. Dans le cas du jeu, nous n'avons pas un tel problème, car seuls les détenteurs de jetons de crowdfunding peuvent gagner. Mais résoudre le problème du free-rider sera utile dans le cas du jeu. Nous pouvons «stimuler» les gens à investir. Pour ce faire, l'organisateur de la collecte de fonds, qui est également le créateur de AA, peut fixer une petite compensation, qu'il versera de sa poche si le but de la collecte n'est pas atteint. Dans le cas d'une collecte réussie, l'organisateur prendra un petit pourcentage. C'est-à-dire que nous introduisons un tiers qui, afin d'obtenir des avantages, couvrira le risque d'une collecte infructueuse.

En appliquant un tel «financement participatif optimisé», le comportement auparavant rationnel du «non-investissement» (en général, pour que tout bien public soit du free-rider est toujours la stratégie la plus rentable économiquement) peut devenir moins rationnel que l'investissement. Cela peut être particulièrement pertinent dans les cas de création de biens de groupe dans lesquels un certain cercle de personnes est impliqué. Cela n'élimine pas complètement le problème des passagers clandestins, mais fait de la participation un comportement rationnel.

Le code qui implémente le «contrat d'assurance optimisé» restera également un exercice intéressant pour ceux qui le souhaitent.

Source: https://habr.com/ru/post/fr475100/


All Articles