Comment écrire et publier un contrat intelligent dans TON
De quoi parle cet article ?
Dans cet article, je vais raconter comment j'ai participé au premier (sur deux) concours Telegram sur la blockchain, je n'ai pas remporté de prix et j'ai décidé de documenter mon expérience dans un article, afin qu'elle ne soit pas perdue et, peut-être, aide quelqu'un.
Comme je ne voulais pas écrire du code abstrait mais faire quelque chose de concret, pour l'article j'ai écrit un contrat intelligent de loterie instantanée et un site qui affiche les données du contrat intelligent directement depuis TON sans utiliser de réserves intermédiaires.
L'article sera utile à ceux qui veulent créer leur premier contrat intelligent dans TON, mais ne savent pas par où commencer.
À travers l'exemple de la loterie, je vais partir de l'installation de l'environnement jusqu'à la publication du contrat intelligent, son interaction et je vais écrire un site pour récupérer et publier des données.
Concernant la participation au concours
En octobre de l'année dernière, Telegram a annoncé un concours sur la blockchain avec de nouveaux langages Fift et FunC. Il fallait choisir d'écrire l'un des cinq contrats intelligents proposés. J'ai pensé qu'il serait intéressant de m'occuper de quelque chose d'inhabituel, d'étudier le langage et de créer quelque chose, même si je n'aurais pas à écrire quoi que ce soit d'autre à l'avenir. De plus, le sujet est toujours d'actualité.
Il convient de dire que je n'avais pas d'expérience en développement de contrats intelligents.
J'avais prévu de participer jusqu'à la fin tant que je pouvais et ensuite d'écrire un article de revue, mais j'ai échoué dès le premier. J'ai avec une signature multiple sur FunC et il fonctionnait en général. J'ai pris comme base .
À ce moment-là, j'ai pensé que c'était largement suffisant pour obtenir au moins une place de prix. En fin de compte, environ 40 des 60 participants ont gagné des prix et je n'étais pas parmi eux. En général, il n'y a rien de terrible, mais une chose m'a inquiété. Au moment de l'annonce des résultats, il n'y avait pas eu de révision avec un test de mon contrat, j'ai demandé aux participants dans le chat s'il y avait quelqu'un d'autre qui ne l'avait pas, mais il n'y en avait pas.
Apparemment, en portant attention à mes messages, deux jours plus tard, les juges ont publié un commentaire et je n'ai toujours pas compris s'ils avaient accidentellement omis mon contrat intelligent pendant le jugement ou s'ils ont simplement pensé qu'il était si mauvais qu'il ne nécessitait pas de commentaire. J'ai posé la question sur la page, mais je n'ai pas reçu de réponse. Bien que ceux qui ont jugé ne soient pas un secret, j'ai considéré qu'il était superflu d'envoyer des messages personnels.
Un temps considérable a été consacré à comprendre le sujet, c'est pourquoi il a été décidé d'écrire cet article. Étant donné qu'il n'y a pas encore beaucoup d'informations, cet article aidera à économiser du temps à tous ceux qui sont intéressés.
Le concept de fonctionnement des contrats intelligents dans TON
Avant d’écrire quoi que ce soit, il est nécessaire de déterminer par quel angle aborder ce sujet. Je vais donc expliquer les différentes parties de ce système. Plus précisément, quelles parties doivent être connues pour rédiger au moins un contrat fonctionnel.
Nous allons nous concentrer sur la rédaction d'un contrat intelligent et le travail avec la Machine Virtuelle TON (TVM), Fift et FunC, c'est pourquoi cet article ressemble davantage à une description du développement d'un programme ordinaire. Nous n'allons pas nous attarder sur le fonctionnement de la plateforme elle-même.
En général, des informations sur le fonctionnement de TVM et le langage Fift sont disponibles dans une bonne documentation officielle. Pendant ma participation au concours et même maintenant, en rédigeant le contrat actuel, je m'y suis souvent référé.
Le principal langage utilisé pour écrire des contrats intelligents est FunC. Actuellement, il n'existe pas de documentation à son sujet, donc pour écrire quelque chose, il faut étudier des exemples de contrats intelligents de notre dépôt officiel ainsi que l'implémentation du langage, de plus, il est possible de consulter des exemples de contrats intelligents des deux concours précédents. Les liens se trouvent à la fin de l'article.
Supposons que nous ayons déjà rédigé un contrat intelligent en FunC, après cela, nous compilons le code en assembleur Fift.
Le contrat intelligent compilé reste à être publié. Pour cela, il est nécessaire d'écrire une fonction en Fift, qui prendra en entrée le code du contrat intelligent ainsi que quelques autres paramètres, et le fichier en sortie aura l'extension .boc (qui signifie "bag of cells"), et, en fonction de ce que nous avons écrit, une clé privée et une adresse générée à partir du code du contrat intelligent. Des grammes peuvent déjà être envoyés à l'adresse du contrat intelligent qui n'a pas encore été publié.
Pour publier un contrat intelligent dans TON, le fichier obtenu doit être envoyé dans la blockchain via un client léger (comme expliqué ci-dessous). Cependant, avant de publier, il faut transférer des grammes à l'adresse générée, sinon le contrat intelligent ne sera pas publié. Après publication, il sera possible d'interagir avec le contrat intelligent, en lui envoyant des messages de l'extérieur (par exemple, à l'aide d'un client léger) ou de l'intérieur (par exemple, un contrat intelligent envoie un message à un autre à l'intérieur de TON). .boc Le fichier devra être envoyé sur la blockchain à l'aide d'un léger client (comme indiqué ci-dessous). Mais avant de publier, vous devez transférer des grammes vers l'adresse générée, sinon le contrat intelligent ne sera pas publié. Après la publication, il sera possible d'interagir avec le contrat intelligent en lui envoyant des messages de l'extérieur (par exemple, en utilisant un léger client) ou de l'intérieur (par exemple, un contrat intelligent envoie un message à un autre à l'intérieur de TON).
Une fois que nous avons compris comment le code est publié, il devient plus facile. Nous savons à peu près ce que nous voulons écrire et comment notre programme va fonctionner. Pendant l'écriture, nous recherchons comment cela a déjà été réalisé dans les contrats intelligents existants ou nous consultons le code de mise en œuvre. Fift et FunC dans le dépôt officiel, ou nous consultons la documentation officielle.
J'ai très souvent cherché des mots-clés dans le chat Telegram où tous les participants au concours étaient rassemblés, y compris des employés de Telegram. Pendant le concours, tout le monde s'est réuni là et a commencé à discuter de Fift et FunC. Le lien est à la fin de l'article.
Il est temps de passer de la théorie à la pratique.
Préparation de l'environnement pour travailler avec TON
Tout ce qui sera décrit dans l'article a été réalisé sur MacOS et vérifié sur une installation propre d'Ubuntu 18.04 LTS dans Docker.
La première chose à faire est de télécharger et d'installer lite-client avec lequel on peut envoyer des requêtes à TON.
Le guide sur le site officiel décrit assez en détail et clairement le processus d'installation et omet certains détails. Ici, nous suivons le guide tout en installant les dépendances manquantes. Je ne me suis pas donné la peine de compiler chaque projet moi-même et j'ai installé à partir du dépôt officiel d'Ubuntu (sur MacOS, j'ai utilisé brew).
apt -y install git
apt -y install wget
apt -y install cmake
apt -y install g++
apt -y install zlib1g-dev
apt -y install libssl-dev Une fois toutes les dépendances installées, nous pouvons installer lite-client, Fift, FunC.
Tout d'abord, nous clonons le dépôt TON avec les dépendances. Pour plus de commodité, nous allons tout faire dans le dossier ~\/TON.
cd ~\/TON
git clone https:\/\/github.com\/ton-blockchain\/ton.git
cd .\/ton
git submodule update --init --recursiveLe dépôt contient également des réalisations. Fift et FunC.
Nous sommes maintenant prêts à compiler le projet. Le code du dépôt a été cloné dans le répertoire ~\/TON\/ton. Il y a ~\/TON nous créons un dossier build et compilons le projet dedans.
mkdir ~\/TON\/build
cd ~\/TON\/build
cmake ..\/tonComme nous allons écrire un contrat intelligent, nous avons besoin non seulement de lite-client, mais aussi Fift avec FunC, donc nous compilons tout. Ce n'est pas un processus rapide, alors nous attendons.
cmake --build . --target lite-client
cmake --build . --target fift
cmake --build . --target funcEnsuite, nous téléchargeons le fichier de configuration qui contient les données sur le nœud auquel lite-client nous allons nous connecter.
wget https://test.ton.org/ton-lite-client-test1.config.jsonNous faisons nos premières requêtes à TON
Maintenant, lançons lite-client.
cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.jsonSi la compilation s'est déroulée avec succès, après le lancement, vous verrez le journal de connexion du client léger au nœud.
[ 1][t 2][1582054822.963129282][lite-client.h:201][!testnode] conn ready
[ 2][t 2][1582054823.085654020][lite-client.cpp:277][!testnode] version du serveur 1.1, capacités 7
[ 3][t 2][1582054823.085725069][lite-client.cpp:286][!testnode] heure du serveur 1582054823 (delta 0)
...Vous pouvez exécuter la commande help et voir quelles commandes sont disponibles.
helpÉnumérons les commandes que nous allons utiliser dans cet article.
liste des commandes disponibles :
laste Obtenez les informations sur le dernier bloc et l'état du serveur
sendfile Charge un message sérialisé depuis et l’envoie au serveur
getaccount [] Charge l'état le plus récent du compte spécifié ; est au format [:]
runmethod [] ... Exécute la méthode GET du compte avec les paramètres spécifiéslast obtient le dernier bloc créé depuis le serveur.
sendfile envoie un fichier contenant un message au TON; c'est grâce à cette commande que le contrat intelligent est publié et les demandes lui sont adressées.
getaccount charge l'état actuel du contrat intelligent à l'adresse spécifiée.
runmethod [] exécute les méthodes GET du contrat intelligent. Nous sommes maintenant prêts à écrire le contrat lui-même.
Mise en œuvre
Idée
Comme mentionné précédemment, le contrat intelligent que nous écrivons est une loterie.
De plus, ce n'est pas une loterie où vous devez acheter un ticket et attendre une heure, un jour ou un mois, mais instantanée où l'utilisateur transfère des grammes à l'adresse du contrat N et reçoit immédiatement 2 * N grammes ou perd. La probabilité de gagner sera d'environ 40 %. Si le montant des grammes pour le paiement n'est pas suffisant, nous considérerons la transaction comme un dépôt.
Il est également important que les mises soient visibles en temps réel et de manière pratique, afin que l'utilisateur puisse immédiatement comprendre s'il a gagné ou perdu. Par conséquent, nous devons créer un site Web qui affichera les mises et les résultats directement depuis le TON.
Écriture d’un contrat intelligent
Pour plus de commodité, j'ai créé une mise en surbrillance pour le code FunC; le plugin peut être trouvé et installé dans la recherche de Visual Studio Code. Si jamais vous souhaitez ajouter quelque chose, j'ai mis le plugin à disposition publique. Un plugin pour travailler avec le Fift a également été fait par quelqu'un auparavant; celui-ci peut également être trouvé et installé dans VSC.
Créons d'ores et déjà un dépôt où nous allons committer les résultats intermédiaires.
Pour nous faciliter la tâche, nous allons écrire le contrat intelligent et le tester localement jusqu'à ce qu'il soit prêt. Ce n'est qu'après cela que nous le publierons dans le TON.
Le contrat intelligent a deux méthodes externes auxquelles on peut faire appel. La première, recv_external() cette fonction est exécutée lorsqu'une demande de contrat provient du monde extérieur, c'est-à-dire pas de TON, par exemple lorsque nous formons nous-même un message et l'envoyons via le lite-client. La seconde, recv_internal() c'est lorsque dans le TON lui-même, un contrat appelle notre contrat. Dans les deux cas, des paramètres peuvent être passés à la fonction.
Commençons par un exemple simple qui fonctionnera si nous le publions, mais il n'a pas de charge fonctionnelle.
() recv_internal(slice in_msg) impure {
;; TODO: implémentation
}
() recv_external(slice in_msg) impure {
;; TODO: implémentation
}Ici, il faut expliquer ce qu'est slice. Toutes les données stockées dans la Blockchain TON sont une collection TVM cell ou simplement cell, dans cette cellule, il est possible de stocker jusqu'à 1023 bits de données et jusqu'à 4 liens vers d'autres cellules.
slice de cellule TVM ou slice est une partie existante qui cell est utilisée pour son analyse, cela sera compris par la suite. L'essentiel pour nous est que dans le contrat intelligent, nous pouvons passer slice et en fonction du type de message, traiter les données dans recv_external() ou recv_internal().
impure est un mot-clé qui indique que la fonction modifie les données du contrat intelligent.
Nous allons enregistrer le code du contrat dans lottery-code.fc et le compiler.
~\/TON\/build\/crypto\/func -APSR -o lottery-compiled.fif ~\/TON\/ton\/crypto\/smartcont\/stdlib.fc .\/lottery-code.fc Les valeurs des drapeaux peuvent être consultées avec la commande
~\/TON\/build\/crypto\/func -helpNous avons obtenu un code assembleur Fift compilé dans lottery-compiled.fif:
// lottery-compiled.fif
"Asm.fif" include
// automatically generated from `/Users/rajymbekkapisev/TON/ton/crypto/smartcont/stdlib.fc` `./lottery-code.fc`
PROGRAM{
DECLPROC recv_internal
DECLPROC recv_external
recv_internal PROC:<{
// in_msg
DROP //
}>
recv_external PROC:<{
// in_msg
DROP //
}>
}END>cIl peut être exécuté localement, pour cela nous préparerons l'environnement.
Notons qu'à la première ligne, on inclut Asm.fif, c'est du code écrit en Fift pour l'assembleur Fift.
Comme nous voulons exécuter et tester le contrat intelligent localement, créons un fichier lottery-test-suite.fif et copions le code compilé en remplaçant la dernière ligne, qui enregistre le code du contrat intelligent dans une constante code, pour ensuite le passer à la machine virtuelle :
"TonUtil.fif" include
"Asm.fif" include
PROGRAM{
DECLPROC recv_internal
DECLPROC recv_external
recv_internal PROC:<{
\/\/ in_msg
DROP \/\/
}>
recv_external PROC:<{
\/\/ in_msg
DROP \/\/
}>
}END>s constant code
Pour l’instant, c’est clair, maintenant ajoutons dans le même fichier le code que nous utiliserons pour exécuter le TVM.
0 tuple 0x076ef1ea , \/\/ magic
0 , 0 , \/\/ actions msg_sents
1570998536 , \/\/ unix_time
1 , 1 , 3 , \/\/ block_lt, trans_lt, rand_seed
0 tuple 100000000000000 , dictnew , , \/\/ remaining balance
0 , dictnew , \/\/ contract_address, global_config
1 tuple \/\/ wrap to another tuple
constant c7
0 constant recv_internal \/\/ to run recv_internal()
-1 constant recv_external \/\/ to invoke recv_external()Dans c7 nous enregistrons le contexte, c'est-à-dire les données avec lesquelles le TVM sera exécuté (ou l'état du réseau). Pendant le concours, un des développeurs a montré comment créer c7 et je l'ai copié. Dans cet article, nous devrons peut-être changer rand_seed Comme cela dépend de la génération d'un nombre aléatoire et qu'il ne faut pas le modifier, il renverra toujours le même nombre.
recv_internal et recv_external Les constantes avec les valeurs 0 et -1 seront responsables de l'appel des fonctions correspondantes dans le contrat intelligent.
Nous sommes maintenant prêts à créer notre premier test pour notre contrat intelligent vide. Pour plus de clarté, nous allons ajouter tous les tests dans ce même fichier. lottery-test-suite.fif.
Créons une variable storage et écrivons-y un vide cell, ce sera le stockage du contrat intelligent.
message C'est le message que nous allons transmettre au contrat intelligent de l'extérieur. Nous le ferons aussi vide pour l'instant.
stockage variable
<b b> stockage !
message variable
<b b> message ! Après avoir préparé les constantes et les variables, nous lançons le TVM avec la commande runvmctx et nous passons les paramètres créés en entrée.
message @
recv_external
code
storage @
c7
runvmctx Au final, nous obtiendrons Nous pouvons maintenant exécuter le code obtenu. Fift.
export FIFTPATH=~\/TON\/ton\/crypto\/fift\/lib \/\/ exécutez une fois pour la commodité ~\/TON\/build\/crypto\/fift -s lottery-test-suite.fif
Le programme doit s'exécuter sans erreurs et dans la sortie, nous verrons le journal d'exécution : execute SETCP 0 execute DICTPUSHCONST 19 (xC_,1) execute DICTIGETJMPZ execute DROP execute implicit RET [ 3][t 0][1582281699.325381279][vm.cpp:479] steps: 5 gas: used=304, max=9223372036854775807, limit=9223372036854775807, credit=0
Super, nous avons écrit la première version fonctionnelle du contrat intelligent.Nous devons maintenant ajouter des fonctionnalités. D'abord, nous allons nous occuper des messages qui viennent du monde extérieur dans
Le développeur choisit lui-même le format des messages que le contrat peut accepter. recv_external()
Mais généralement,
d'une part, nous voulons protéger notre contrat du monde extérieur et faire en sorte que seul le propriétaire du contrat puisse lui envoyer des messages externes.
- D'autre part, lorsque nous envoyons un message valide à TON, nous voulons qu'il se produise exactement une fois et que lors de l'envoi répétitif du même message, le contrat intelligent le rejette.
- C'est pourquoi presque tous les contrats résolvent ces deux problèmes, car notre contrat accepte les messages externes, nous devons également veiller à cela.
Nous allons procéder dans l'ordre inverse. D'abord, nous allons résoudre le problème des répétitions : si le contrat a déjà reçu un tel message et l'a traité, il ne l'exécutera pas une deuxième fois. Ensuite, nous traiterons le problème pour que seules certaines personnes puissent envoyer des messages au contrat intelligent.
Nous allons commencer par cela.
Il existe plusieurs façons de résoudre le problème des messages répétés. Voici comment nous procéderons. Dans le contrat intelligent, nous initialiserons un compteur de messages reçus à une valeur initiale de 0. Dans chaque message, nous ajouterons la valeur actuelle du compteur au contrat intelligent. Si la valeur du compteur dans le message ne correspond pas à celle du contrat intelligent, nous ne le traiterons pas ; si elle correspond, nous le traiterons et augmenterons le compteur dans le contrat intelligent de 1.
Nous revenons à lottery-test-suite.fif et ajoutons un deuxième test. Nous allons envoyer un numéro incorrect ; le code devra lever une exception. Par exemple, supposons que les données du contrat stockent 166, mais que nous envoyons 165.
<b 166 32 u, b> stockage !
<b 165 32 u, b> message !
message @
recv_external
code
storage @
c7
runvmctx
drop
exit_code !
."Code de sortie " exit_code @ . cr
exit_code @ 33 - abort"Test #2 non réussi"Lançons.
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fif Et nous verrons que le test échoue.
[ 1][t 0][1582283084.210902214][words.cpp:3046] lottery-test-suite.fif:67: abort": Test #2 non passé
[ 1][t 0][1582283084.210941076][fift-main.cpp:196] Erreur d'interprétation du fichier `lottery-test-suite.fif`: erreur d'interprétation du fichier inclus `lottery-test-suite.fif` : lottery-test-suite.fif:67: abort": Test #2 non passéÀ ce stade lottery-test-suite.fif doit se présenter sous la forme .
Maintenant, ajoutons la logique du compteur dans le contrat intelligent dans lottery-code.fc.
() recv_internal(slice in_msg) impure {
;; TODO: implémentation
}
() recv_external(slice in_msg) impure {
if (slice_empty?(in_msg)) {
return ();
}
int msg_seqno = in_msg~load_uint(32);
var ds = begin_parse(get_data());
int stored_seqno = ds~load_uint(32);
throw_unless(33, msg_seqno == stored_seqno);
}Dans slice in_msg contient le message que nous envoyons.
La première chose que nous faisons est de vérifier si le message contient des données ; si ce n'est pas le cas, nous sortons simplement.
Ensuite, nous analysons le message. in_msg~load_uint(32) charge le nombre 165, 32 bits unsigned int du message reçu.
Ensuite, nous chargeons 32 bits depuis le stockage du contrat intelligent. Nous vérifions que le nombre chargé correspond à celui transmis ; sinon, nous levons une exception. Dans notre cas, comme nous transmettons un nombre non correspondant, une exception doit être levée.
Maintenant, compilons.
~\/TON\/build\/crypto\/func -APSR -o lottery-compiled.fif ~\/TON\/ton\/crypto\/smartcont\/stdlib.fc .\/lottery-code.fc Copions le code obtenu dans lottery-test-suite.fif, sans oublier de remplacer la dernière ligne.
Vérifions que le test passe :
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fifnous pouvons consulter le commit correspondant avec les résultats actuels.
Remarquons qu'il n'est pas pratique de copier constamment le code compilé du contrat intelligent dans le fichier des tests, donc nous allons écrire un script qui enregistrera le code dans une constante pour nous, et nous intégrerons simplement le code compilé dans nos tests via "include".
Dans le dossier du projet, créons le fichier build.sh avec le contenu suivant.
#!/bin/bash
~/TON/build/crypto/func -SPA -R -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fcRendez-le exécutable.
chmod +x .\/build.shMaintenant, il suffit d'exécuter notre script pour compiler le contrat. Mais en plus de cela, nous devons l'enregistrer dans une constante. code. C'est pourquoi nous allons créer un nouveau fichier. lotter-compiled-for-test.fif, que nous inclurons dans le fichier. lottery-test-suite.fif.
Ajoutons au script sh le code qui va simplement dupliquer le fichier compilé dans lotter-compiled-for-test.fif et changer la dernière ligne.
# copy and change for test
cp lottery-compiled.fif lottery-compiled-for-test.fif
sed '$d' lottery-compiled-for-test.fif > test.fif
rm lottery-compiled-for-test.fif
mv test.fif lottery-compiled-for-test.fif
echo -n "}END>s constant code" >> lottery-compiled-for-test.fifMaintenant, pour vérifier, exécutons le script généré et nous obtiendrons le fichier lottery-compiled-for-test.fif, que nous inclurons dans notre lottery-test-suite.fif
Dans lottery-test-suite.fif supprimons le code du contrat et ajoutons la ligne "lottery-compiled-for-test.fif" include.
Exécutons les tests pour vérifier qu'ils passent.
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fifSuper, maintenant, pour automatiser l'exécution des tests, créons un fichier test.sh, qui effectuera d'abord build.sh, puis lancera les tests.
touch test.sh
chmod +x test.shÉcrivons à l'intérieur
.\/build.sh
echo "nCompilation terminée n"
export FIFTPATH=~\/TON\/ton\/crypto\/fift\/lib
~\/TON\/build\/crypto\/fift -s lottery-test-suite.fifFaisons-le test.sh et exécutons-le pour nous assurer que les tests fonctionnent.
chmod +x .\/test.sh
.\/test.shVérifions que le contrat se compile et que les tests s'exécutent.
Parfait, maintenant lors de l'exécution test.sh la compilation et l'exécution des tests se feront automatiquement. Voici le lien vers .
D'accord, avant de continuer, faisons une dernière chose pour plus de commodité.
Créons un dossier build où nous allons stocker le contrat compilé et son clone enregistré dans une constante. lottery-compiled.fif, lottery-compiled-for-test.fif. Créons également un dossier test où seront stockés le fichier de tests lottery-test-suite.fif et potentiellement d'autres fichiers auxiliaires. .
Continuons le développement du smart contract.
Ensuite, il doit y avoir un test qui vérifie que le message est reçu et que le compteur est mis à jour dans le stockage lorsque nous envoyons un nombre correct. Mais nous ferons cela plus tard.
Pour l'instant, réfléchissons à quelle structure de données et quelles données doivent être sauvegardées dans le smart contract.
Je vais décrire tout ce que nous stockons.
`seqno` un entier positif de 32 bits compteur.
`pubkey` un entier positif de 256 bits clé publique, qui nous permettra de vérifier la signature du message envoyé de l'extérieur, comme indiqué ci-dessous.
`order_seqno` un entier positif de 32 bits qui conserve le compteur du nombre d'enchères.
`number_of_wins` un entier positif de 32 bits qui conserve le nombre de victoires.
`incoming_amount` type de données Gram (les 4 premiers bits correspondent à la longueur), conserve le nombre total de grammes envoyés au contrat.
`outgoing_amount` le nombre total de grammes qui ont été envoyés aux gagnants.
`owner_wc` numéro du workchain, un entier de 32 bits (dans certains endroits, il est écrit comme 8 bits). Il existe actuellement seulement deux : -1 et 0.
`owner_account_id` un entier positif de 256 bits, adresse du contrat dans le workchain actuel.
`orders` une variable de type dictionnaire, conserve les vingt dernières enchères. Ensuite, il faut écrire deux fonctions. Appelons la première pack_state(), qui va empaqueter les données pour les sauvegarder ultérieurement dans le stockage du smart contract. La seconde, que nous appellerons unpack_state() lira et retournera les données du stockage.
_ pack_state(int seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) inline_ref {
return begin_cell()
.store_uint(seqno, 32)
.store_uint(pubkey, 256)
.store_uint(order_seqno, 32)
.store_uint(number_of_wins, 32)
.store_grams(incoming_amount)
.store_grams(outgoing_amount)
.store_int(owner_wc, 32)
.store_uint(owner_account_id, 256)
.store_dict(orders)
.end_cell();
}
_ unpack_state() inline_ref {
var ds = begin_parse(get_data());
var unpacked = (ds~load_uint(32), ds~load_uint(256), ds~load_uint(32), ds~load_uint(32), ds~load_grams(), ds~load_grams(), ds~load_int(32), ds~load_uint(256), ds~load_dict());
ds.end_parse();
return unpacked;
}Ajoutons ces deux fonctions en tête du smart contract. Cela donnera un résultat intermédiaire.
Pour sauvegarder les données, il sera nécessaire d'appeler la fonction intégrée set_data() et elle enregistrera les données dans pack_state() le stockage du smart contract.
cell packed_state = pack_state(arg_1, .., arg_n);
set_data(packed_state);Maintenant que nous avons des fonctions pratiques pour écrire et lire des données, nous pouvons avancer.
Il nous faut vérifier que le message entrant est signé par le propriétaire du contrat (ou par un autre utilisateur ayant accès à la clé privée).
Lorsque nous publions un contrat intelligent, nous pouvons l'initialiser avec les données nécessaires dans le stockage, qui seront conservées pour une utilisation future. Nous y enregistrerons la clé publique pour pouvoir vérifier que la signature du message entrant a été effectuée avec la clé privée correspondante.
Avant de continuer, créons une clé privée et écrivons-la dans test/keys/owner.pk. Pour cela, lançons Fift en mode interactif et exécutons quatre commandes.
`newkeypair` génère une clé publique et une clé privée et les écrit dans la pile.
`drop` supprime le dessus de la pile (dans ce cas, la clé publique)
`.s` affiche le contenu actuel de la pile
`"owner.pk" B>file` écrit la clé privée dans un fichier nommé `owner.pk`.
`bye` termine la session Fift. Créons un dossier clés dans le dossier test et nous y écrirons la clé privée.
mkdir test/keys
cd test/keys
~ /TON/build/crypto/fift -i
newkeypair
ok
.s
BYTES:128DB222CEB6CF5722021C3F21D4DF391CE6D5F70C874097E28D06FCE9FD6917 BYTES:DD0A81AAF5C07AAAA0C7772BB274E494E93BB0123AA1B29ECE7D42AE45184128
drop
ok
"owner.pk" B>file
ok
byeNous voyons dans le dossier actuel le fichier owner.pk.
Nous retirons la clé publique de la pile, et lorsque cela sera nécessaire, nous pourrons l'obtenir à partir de la clé privée.
Maintenant, nous devons écrire une vérification de la signature. Commençons par un test. D'abord, nous lisons la clé privée à partir du fichier en utilisant la fonction file>B et nous l'enregistrons dans la variable owner_private_key, ensuite, avec la fonction priv>pub nous convertissons la clé privée en clé publique et enregistrons le résultat dans owner_public_key.
variable owner_private_key
variable owner_public_key
"./keys/owner.pk" file>B owner_private_key !
owner_private_key @ priv>pub owner_public_key !Nous aurons besoin des deux clés.
Nous initialisons le stockage du contrat intelligent avec des données arbitraires dans le même ordre que dans la fonction pack_state()et nous l'enregistrons dans la variable storage.
variable owner_private_key
variable owner_public_key
variable orders
variable owner_wc
variable owner_account_id
"./keys/owner.pk" file>B owner_private_key !
owner_private_key @ priv>pub owner_public_key !
dictnew orders !
0 owner_wc !
0 owner_account_id !
<b 0 32 u, owner_public_key @ b, gram, owner_wc i, owner_account_id 256 orders dict, b> stockage !Ensuite, nous composerons un message signé, qui contiendra uniquement la signature et la valeur du compteur.
D'abord, nous créons les données que nous souhaitons transmettre, puis nous les signons avec la clé privée et enfin nous formons le message signé.
message_variable à signer
message_variable à envoyer
signature_variable
<b 0 32 u, b> message_variable à signer !
message_variable à signer @ clé_privée_hash @ signature_ed25519_sign_uint !
<b signature @ b, 0 32 u, b> <s ! En fin de compte, le message que nous enverrons au contrat intelligent est enregistré dans la variable message_to_send, concernant les fonctions hashu, ed25519_sign_uint vous pouvez lire davantage .
Et pour relancer le test, nous appelons de nouveau.
message_to_send @
recv_external
code
storage @
c7
runvmctxle fichier avec les tests devrait ressembler à ce stade.
Lançons le test et il échouera, donc nous allons modifier le contrat intelligent pour qu'il puisse recevoir des messages dans ce format et vérifier la signature.
Nous commençons par lire 512 bits de la signature dans le message et les stocker dans une variable, puis nous lisons 32 bits de la variable compteur.
Comme nous avons une fonction pour lire les données du stockage du smart contract, nous allons l'utiliser.
Ensuite, nous vérifions le compteur transmis avec le stockage et la signature. Si quelque chose ne correspond pas, nous levons une exception avec le code approprié.
var signature = in_msg~load_bits(512);
var message = in_msg;
int msg_seqno = message~load_uint(32);
(int stored_seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) = unpack_state();
throw_unless(33, msg_seqno == stored_seqno);
throw_unless(34, check_signature(slice_hash(in_msg), signature, pubkey));Le commit correspondant .
Nous allons lancer les tests et voir que le deuxième test échoue. Pour deux raisons, le manque de bits dans le message et le manque de bits dans le stockage, donc le code échoue lors de l'analyse. Il faut ajouter la signature du message que nous envoyons et copier le stockage du dernier test.
Dans le deuxième test, nous ajouterons la signature du message et modifierons le stockage du smart contract. voici à quoi ressemble le fichier de tests en ce moment.
Écrivons le quatrième test, où nous enverrons un message signé avec la clé privée d'un tiers. Créons une autre clé privée et sauvegardons-la dans un fichier not-owner.pk. Nous signerons le message avec cette clé privée. Lançons les tests et assurons-nous que tous les tests passent. à l'heure actuelle.
Nous pouvons enfin passer à l'implémentation de la logique du smart contract.
Dans recv_external() Nous allons recevoir deux types de messages.
Comme notre contrat accumulera les pertes des joueurs, cet argent devra être transféré au créateur de la loterie. L'adresse du portefeuille du créateur de la loterie est enregistrée dans le stockage lors de la création du contrat.
Au cas où, nous avons besoin de la possibilité de changer l'adresse à laquelle envoyer les grammes des perdants. Nous devons également avoir la possibilité d'envoyer des grammes de la loterie à l'adresse du propriétaire.
Commençons par le premier. Écrivons d'abord un test qui vérifiera qu'après l'envoi du message, le smart contract a enregistré la nouvelle adresse dans le stockage. Notons que dans le message, en plus du compteur et de la nouvelle adresse, nous transmettons également action un nombre entier non négatif sur 7 bits, en fonction de celui-ci, nous choisirons comment traiter le message dans le smart contract.
<b 0 32 u, 1 @ 7 new_owner_wc i, new_owner_account_id 256 b> message à signer !Dans le test, vous pouvez voir comment se déroule la désérialisation du stockage du smart contract. storage Dans Fift. La désérialisation des variables est décrite dans la documentation de Fift.
avec l'ajout du test.
Nous exécutons le test et vérifions qu'il échoue. Ajoutons maintenant la logique pour modifier l'adresse du propriétaire de la loterie.
Dans le contrat intelligent, nous continuons à parser message, en lisant dans action. Rappelons que nous aurons deux action: la modification de l'adresse et l'envoi de grammes.
Ensuite, nous lisons la nouvelle adresse du propriétaire du contrat et l'enregistrons dans le stockage.
Nous exécutons les tests et voyons que le troisième test échoue. Il échoue parce que le contrat parse maintenant 7 bits supplémentaires du message, qui manquent dans le test. Ajoutons au message un action. Exécutons les tests et voyons que tous passent. commit sur les modifications. Parfait.
Nous allons maintenant écrire la logique pour envoyer le nombre spécifié de grammes à l'adresse précédemment enregistrée.
D'abord, écrivons un test. Nous écrirons deux tests : un lorsque le solde est insuffisant, et l'autre lorsque tout doit réussir. Les tests peuvent être consultés .
Ajoutons maintenant le code. Écrivons d'abord deux méthodes auxiliaires. La première est une méthode get pour connaître le solde actuel du contrat intelligent.
int balance() inline_ref method_id {
return get_balance().pair_first();
}Et la deuxième pour envoyer des grammes à un autre contrat intelligent. Cette méthode a été complètement copiée d'un autre contrat intelligent.
() send_grams(int wc, int addr, int grams) impure {
;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
cell msg = begin_cell()
;; .store_uint(0, 1) ;; 0 <= format indicator int_msg_info$0
;; .store_uint(1, 1) ;; 1 <= ihr disabled
;; .store_uint(1, 1) ;; 1 <= bounce = true
;; .store_uint(0, 1) ;; 0 <= bounced = false
;; .store_uint(4, 5) ;; 00100 <= address flags, anycast = false, 8-bit workchain
.store_uint (196, 9)
.store_int(wc, 8)
.store_uint(addr, 256)
.store_grams(grams)
.store_uint(0, 107) ;; 106 zéros + 0 en tant qu'indicateur qu'il n'y a pas de cellule avec les données.
.end_cell();
send_raw_message(msg, 3); ;; mode, 2 pour ignorer les erreurs, 1 pour que l'expéditeur paie les frais, 64 pour renvoyer la valeur du message entrant
}Ajoutons ces deux méthodes au contrat intelligent et écrivons la logique. Tout d'abord, nous analysons le nombre de grammes du message. Ensuite, nous vérifions le solde, s'il est insuffisant, nous levons une exception. Si tout va bien, nous envoyons les grammes à l'adresse sauvegardée et mettons à jour le compteur.
int amount_to_send = message~load_grams();
throw_if(36, amount_to_send + 500000000 > balance());
accept_message();
send_grams(owner_wc, owner_account_id, amount_to_send);
set_data(pack_state(stored_seqno + 1, pubkey, order_seqno, number_of_wins, incoming_amount, outgoing_amount, owner_wc, owner_account_id, orders));le contrat intelligent actuel. Exécutons les tests et vérifions qu'ils passent.
Notez qu'à chaque message traité, une commission est prélevée sur le contrat intelligent. Pour que le contrat intelligent exécute la demande, il faut d'abord effectuer des vérifications de base. accept_message().
Passons maintenant aux messages internes. En fait, nous allons simplement recevoir des grammes et renvoyer le double de la somme au joueur en cas de gain et un tiers au propriétaire en cas de perte.
Commençons par écrire un simple test. Pour cela, nous aurons besoin de l'adresse de test du contrat intelligent à partir de laquelle nous envoyons des grammes au contrat intelligent.
L'adresse du contrat intelligent se compose de deux nombres : un entier 32 bits pour le workchain et un numéro de compte unique non négatif de 256 bits dans ce workchain. Par exemple, -1 et 12345, nous allons conserver cette adresse dans un fichier.
J'ai copié la fonction pour enregistrer l'adresse depuis .
// ( wc addr fname -- ) Save address to file in 36-byte format
{ -rot 256 u>B swap 32 i>B B+ swap B>file } : save-addressExaminons comment fonctionne la fonction, cela nous aidera à comprendre comment fonctionne Fift. Lançons Fift en mode interactif.
~\/TON\/build\/crypto\/fift -i Tout d'abord, nous plaçons dans la pile -1, 12345 et le nom du futur fichier "sender.addr" :
-1 12345 "sender.addr" Ensuite, la fonction suivante est exécutée -rot, qui déplace la pile de sorte que le numéro unique du contrat intelligent se retrouve au sommet :
"sender.addr" -1 12345256 u>B convertit l'entier non négatif de 256 bits en octets.
"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039swap inverse les deux premiers éléments de la pile.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -132 i>B convertit un entier de 32 bits en octets.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFFB+ concatène deux séquences d'octets.
"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFFEncore swap.
BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" Et enfin, l'écriture des octets dans le fichier est effectuée B>file. Après cela, notre pile est vide. Arrêtons Fift. Un fichier a été créé dans le dossier actuel sender.addr. Déplaçons le fichier dans le dossier créé test\/addresses\/.
Écrivons un simple test qui enverra des grammes au contrat intelligent. .
Passons maintenant à la logique de la loterie.
La première chose que nous faisons est de vérifier si le message bounced ou non, si bounced, nous l'ignorons. bounced ce qui signifie que le contrat renverra les grammes en cas d'erreur. Nous ne renverrons pas les grammes s'il y a une erreur.
Vérifions le solde, s'il est inférieur à un demi-gramme, acceptons simplement le message et l'ignorons.
Nous analysons l'adresse du contrat intelligent à partir de laquelle le message a été envoyé.
Nous lisons les données de stockage et ensuite supprimons les anciennes mises de l'historique si elles dépassent vingt. Pour plus de commodité, j'ai écrit trois fonctions supplémentaires. pack_order(), unpack_order(), remove_old_orders().
Ensuite, nous vérifions si le solde est insuffisant pour le paiement, donc nous considérons que ce n'est pas une mise, mais un rechargement et nous sauvegardons le rechargement dans orders.
Ensuite, enfin, la nature du contrat intelligent.
D'abord, si le joueur perd, nous l'enregistrons dans l'historique des mises et si le montant est supérieur à 3 grammes, nous envoyons 1/3 au propriétaire du contrat intelligent.
Si le joueur gagne, nous envoyons le montant doublé à l'adresse du joueur et ensuite nous sauvegardons l'information sur la mise dans l'historique.
() recv_internal(int order_amount, cell in_msg_cell, slice in_msg) impur {
var cs = in_msg_cell.begin_parse();
int flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
if (flags & 1) { ;; ignorer le rebond
return ();
}
if (order_amount < 500000000) { ;; juste recevoir des grammes sans changer l'état
return ();
}
slice src_addr_slice = cs~load_msg_addr();
(int src_wc, int src_addr) = parse_std_addr(src_addr_slice);
(int stored_seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) = unpack_state();
orders = remove_old_orders(orders, order_seqno);
if (balance() = 4) {
builder order = pack_order(order_seqno, 3, now(), order_amount, src_wc, src_addr);
orders~udict_set_builder(32, order_seqno, order);
set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins, incoming_amount + order_amount, outgoing_amount, owner_wc, owner_account_id, orders));
if (order_amount > 3000000000) {
send_grams(owner_wc, owner_account_id, order_amount / 3);
}
return ();
}
send_grams(src_wc, src_addr, 2 * order_amount);
builder order = pack_order(order_seqno, 2, now(), order_amount, src_wc, src_addr);
orders~udict_set_builder(32, order_seqno, order);
set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins + 1, incoming_amount, outgoing_amount + 2 * order_amount, owner_wc, owner_account_id, orders));
}Voilà, c'est tout. .
Il ne reste plus qu'une simple tâche, nous allons créer des méthodes GET afin que le monde extérieur puisse obtenir des informations sur l'état du contrat (en fait, lire les données de son stockage du contrat intelligent).
. Nous expliquerons comment obtenir des informations sur le contrat intelligent ci-dessous.
J'ai aussi oublié d'ajouter le code qui traitera la toute première requête qui se produit lors de la publication du contrat intelligent. . Et encore le bug d'envoi de 1/3 du montant au compte du propriétaire.
Ensuite, il reste à publier le contrat intelligent. Créons un dossier requests.
J'ai pris comme base le code de publication qui dans le dépôt officiel.
Il y a quelques points à noter. Nous formons le stockage du contrat intelligent et le message d'entrée. Ensuite, l'adresse du contrat intelligent est générée, c'est-à-dire que l'adresse est connue avant la publication dans TON. Ensuite, il faut envoyer quelques grammes à cette adresse, et seulement après cela, il faut envoyer le fichier contenant le contrat intelligent, car la réseau prélève des frais pour le stockage du contrat intelligent et les opérations qu'il contient (les validateurs qui stockent et exécutent les contrats intelligents). .
Ensuite, nous exécutons le code de publication et obtenons lottery-query.boc le fichier et l'adresse du contrat intelligent.
~\/TON\/build\/crypto\/fift -s requests\/new-lottery.fif 0N'oublions pas de sauvegarder les fichiers générés : lottery-query.boc, lottery.addr, lottery.pk.
Parmi d'autres choses, dans les journaux d'exécution, nous verrons l'adresse du contrat intelligent.
new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a
(Sauvegarde de l'adresse dans le fichier lottery.addr)
Adresse non rebondissable (pour l'initialisation) : 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Adresse rebondissable (pour un accès ultérieur) : kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFYPar curiosité, faisons une requête dans TON
$ .\/lite-client\/lite-client -C ton-lite-client-test1.config.json
getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydEt nous verrons que le compte avec cette adresse est vide.
l'état du compte est videNous envoyons à l'adresse 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 Gram et après quelques secondes, nous exécutons à nouveau la même commande. Pour envoyer des grammes, j'utilise , et des grammes de test peuvent être demandés à quelqu'un dans le chat que je mentionnerai à la fin de l'article.
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydIl regarde, ce qui dans le réseau est apparu un contrat intelligent non initialisé (state:account_uninit) avec cette adresse et un solde de 1 000 000 000 nanogrammes.
l'état du compte est (compte
addr:(addr_std
anycast:rien workchain_id:0 address:x044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A)
storage_stat:(storage_info
used:(storage_used
cells:(var_uint len:1 value:1)
bits:(var_uint len:1 value:103)
public_cells:(var_uint len:0 value:0)) last_paid:1583257959
due_payment:rien)
storage:(account_storage last_trans_lt:3825478000002
balance:(currencies
grams:(nanograms
amount:(var_uint len:4 value:2000000000))
other:(extra_currencies
dict:hme_empty))
state:account_uninit))
x{C00044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A20259C2F2F4CB3800000DEAC10776091DCD650004_}
la dernière transaction lt = 3825478000001 hash = B043616AE016682699477FFF01E6E903878CDFD6846042BA1BFC64775E7AC6C4
le solde du compte est 2000000000ngNous allons maintenant publier le contrat intelligent. Lançons le lite-client et exécutons-le.
>> sendfile lottery-query.boc
[ 1][t 2][1583008371.631410122][lite-client.cpp:966][!testnode] envoi de la requête depuis le fichier lottery-query.boc
[ 3][t 1][1583008371.828550100][lite-client.cpp:976][!query] l'état du message externe est 1 Vérifions que le contrat a été publié.
>> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KsydParmi d'autres, nous allons obtenir.
storage:(account_storage last_trans_lt:3825499000002
balance:(currencies
grams:(nanograms
amount:(var_uint len:4 value:1987150999))
other:(extra_currencies
dict:hme_empty))
state:(account_activeNous voyons que account_active.
Le commit correspondant avec les modifications .
Nous allons maintenant créer des requêtes pour interagir avec le contrat intelligent.
Plus précisément, nous laisserons la première pour changer d'adresse comme un travail autonome, et nous créerons la deuxième pour envoyer des grammes à l'adresse du propriétaire. En réalité, nous devrons faire exactement la même chose que dans le test d'envoi de grammes.
Voici le message que nous allons envoyer au contrat intelligent, où msg_seqno 165, action 2 et 9.5 grammes à envoyer.
<b 165 32 u, 2 7 9500000000 gram, b>N'oublions pas de signer le message avec la clé privée lottery.pk, qui a été générée précédemment lors de la création du contrat intelligent. .
Nous obtenons des informations à partir du contrat intelligent à l'aide des méthodes get
Maintenant, examinons comment exécuter les méthodes get du contrat intelligent.
Lançons lite-client et nous exécutons les méthodes get que nous avons écrites.
$ .\/lite-client\/lite-client -C ton-lite-client-test1.config.json
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd balance
arguments: [ 104128 ]
result: [ 64633878952 ]
...Dans result la valeur contenue, qui est renvoyée par la fonction balance() de notre contrat intelligent.
Nous effectuerons aussi cela pour plusieurs autres méthodes.
>> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
arguments: [ 77871 ]
result: [ 1 ] Demandons l'historique des enchères.
>> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_orders
...
arguments: [ 67442 ]
result: [ ([0 1 1583258284 10000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [1 3 1583258347 4000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [2 1 1583259901 50000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308]) ] Nous allons utiliser lite-client et les méthodes GET pour afficher les informations sur le smart contract sur le site.
Affichage des données du smart contract sur le site
J'ai écrit un site web simple en Python pour afficher les données du smart contract de manière accessible. Je ne vais pas m'attarder sur cela et publierai le site. .
Les requêtes à TON sont effectuées depuis Python à l'aide de lite-client. Pour plus de commodité, le site est empaqueté dans Docker et hébergé sur Google Cloud. .
Essayons
Maintenant, essayons d'envoyer des grammes pour recharger depuis . Nous allons envoyer 40 grammes et faire quelques paris pour plus de clarté. Nous voyons que le site affiche l'historique des paris, le pourcentage actuel de gains et d'autres informations utiles.
, que nous avons gagné le premier, perdu le deuxième.
Postface
L'article est devenu beaucoup plus long que je ne le pensais, peut-être aurait-il pu être plus court, mais peut-être juste assez pour une personne qui ne sait rien sur TON et veut écrire et publier un smart contract pas si simple avec la possibilité d'interagir avec lui. Peut-être que certaines choses auraient pu être expliquées plus simplement.
Il est possible que certains aspects de l'implémentation auraient pu être faits de manière plus efficace et élégante, mais cela aurait pris encore plus de temps pour préparer l'article. Il est également possible que j'aie fait des erreurs ou que je n'aie pas compris certaines choses, donc si vous faites quelque chose de sérieux, il faut se référer à la documentation officielle ou au dépôt officiel du code TON.
Il convient de noter qu'étant donné que TON est encore en active développement, des modifications peuvent survenir, ce qui pourrait casser l'une des étapes de cet article (ce qui s'est déjà produit pendant que j'écrivais, j'ai déjà corrigé), mais l'approche générale est peu susceptible de changer.
Je ne vais pas spéculer sur l'avenir de TON. Il est possible que la plateforme devienne quelque chose de plus grand et qu'il vaille la peine de consacrer du temps à son étude et d'occuper une niche avec nos produits dès maintenant.
Il y a aussi Libra de Facebook, qui a un public potentiel d'utilisateurs plus nombreux que celui de TON. Je ne sais presque rien de Libra, mais d'après le forum, l'activité y est nettement plus importante que dans la communauté TON. Bien que les développeurs et la communauté TON ressemblent plus à un underground, ce qui est plutôt cool.
Liens
- Documentation officielle sur TON :
- Dépôt officiel de TON :
- Portefeuille officiel pour différentes plateformes :
- Dépôt du smart contract de cet article :
- Lien vers le site du smart contract :
- Dépôt de l'extension pour Visual Studio Code pour FunC :
- Un chat sur TON dans Telegram qui a vraiment aidé à s'y retrouver au début. Je pense qu'il ne sera pas erroné de dire qu'on y trouve toutes les personnes qui ont écrit quelque chose pour TON. On peut aussi demander des grammes de test là-bas.
- Un autre chat sur TON où j'ai trouvé des informations utiles :
- Première étape du concours :
- Deuxième étape du concours :
Source : habr.com
