-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
for_use_ethereumbook_appdx-dev-toolstxt_fr_CA.html
1450 lines (1401 loc) · 87.7 KB
/
for_use_ethereumbook_appdx-dev-toolstxt_fr_CA.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.17">
<title>Outils, cadres, et bibliothèques de développement</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment the following line when using as a custom stylesheet */
/* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
html{font-family:sans-serif;-webkit-text-size-adjust:100%}
a{background:none}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
b,strong{font-weight:bold}
abbr{font-size:.9em}
abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
dfn{font-style:italic}
hr{height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
audio,video{display:inline-block}
audio:not([controls]){display:none;height:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type=checkbox],input[type=radio]{padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,::before,::after{box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:0}
p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
:not(pre).nobreak{word-wrap:normal}
:not(pre).nowrap{white-space:nowrap}
:not(pre).pre-wrap{white-space:pre-wrap}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre>code{display:block}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
details{margin-left:1.25rem}
details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
details>summary::-webkit-details-marker{display:none}
details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.prettyprint{background:#f7f7f8}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
pre.pygments span.linenos{display:inline-block;margin-right:.75em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>*>tr>*{border-width:1px}
table.grid-cols>*>tr>*{border-width:0 1px}
table.grid-rows>*>tr>*{border-width:1px 0}
table.frame-all{border-width:1px}
table.frame-ends{border-width:1px 0}
table.frame-sides{border-width:0 1px}
table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
li>p:empty:only-child::before{content:"";display:inline-block}
ul.checklist>li>p:first-child{margin-left:-1em}
ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
td.hdlist2{word-wrap:anywhere}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background:#00fafa}
.black{color:#000}
.black-background{background:#000}
.blue{color:#0000bf}
.blue-background{background:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background:#fa00fa}
.gray{color:#606060}
.gray-background{background:#7d7d7d}
.green{color:#006000}
.green-background{background:#007d00}
.lime{color:#00bf00}
.lime-background{background:#00fa00}
.maroon{color:#600000}
.maroon-background{background:#7d0000}
.navy{color:#000060}
.navy-background{background:#00007d}
.olive{color:#606000}
.olive-background{background:#7d7d00}
.purple{color:#600060}
.purple-background{background:#7d007d}
.red{color:#bf0000}
.red-background{background:#fa0000}
.silver{color:#909090}
.silver-background{background:#bcbcbc}
.teal{color:#006060}
.teal-background{background:#007d7d}
.white{color:#bfbfbf}
.white-background{background:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt,summary{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]{border-bottom:1px dotted}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#header,#content,#footnotes,#footer{max-width:none}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
</head>
<body class="article">
<div id="header">
</div>
<div id="content">
<div class="sect1">
<h2 id="dev_tools_frameworks">Appendix A: Outils, cadres, <span class="keep-together">et bibliothèques</span> de développement</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_cadres_de_développement_frameworks">Cadres de développement (Frameworks)</h3>
<div class="paragraph">
<p>Les cadres de développement peuvent être utilisés pour faciliter le développement de contrats intelligents Ethereum. En faisant tout vous-même, vous comprenez mieux comment tout s’emboîte, mais c’est beaucoup de travail fastidieux et répétitif. Les cadres de développement décrits dans cette section permettent d’automatiser certaines tâches et de faciliter la programmation.</p>
</div>
<div class="sect3">
<h4 id="truffle">Truffle</h4>
<div class="paragraph">
<p> GitHub : <a href="https://github.com/trufflesuite/truffle" class="bare">https://github.com/trufflesuite/truffle</a></p>
</div>
<div class="paragraph">
<p>Site Web : <a href="https://truffleframework.com" class="bare">https://truffleframework.com</a></p>
</div>
<div class="paragraph">
<p>Documentation : <a href="https://truffleframework.com/docs" class="bare">https://truffleframework.com/docs</a></p>
</div>
<div class="paragraph">
<p>Boîtes Truffle : <a href="http://truffleframework.com/boxes/" class="bare">http://truffleframework.com/boxes/</a></p>
</div>
<div class="paragraph">
<p>Référentiel de packages npm : <a href="https://www.npmjs.com/package/truffle" class="bare">https://www.npmjs.com/package/truffle</a></p>
</div>
<div class="sect4">
<h5 id="installing_truffle">Installation du cadre de développement Truffle</h5>
<div class="paragraph">
<p>Le cadre de développement Truffle comprend plusieurs packages Node.js. Avant d’installer <code>truffle</code>, vous devez avoir une installation à jour et fonctionnelle de Node.js et du Node Package Manager (npm).</p>
</div>
<div class="paragraph">
<p>La méthode recommandée pour installer Node.js et npm consiste à utiliser le gestionnaire de version de nœud (nvm). Une fois que vous avez installé <code>nvm</code>, il gérera toutes les dépendances et mises à jour pour vous. Suivez les instructions trouvées sur <a href="http://nvm.sh" class="bare">http://nvm.sh</a>.</p>
</div>
<div class="paragraph">
<p>Une fois que nvm est installé sur votre système d’exploitation, l’installation de Node.js est simple. Utilisez le drapeau --lts pour dire à nvm que vous voulez la version la plus récente de "support à long terme" (LTS) de Node.js :</p>
</div>
<pre data-type="programlisting">
$ <strong>nvm install --lts</strong>
</pre>
<div class="paragraph">
<p>Vérifiez que node et npm sont installés :</p>
</div>
<pre data-type="programlisting">
$ <strong>node -v</strong>
v8.9.4
$ <strong>npm -v</strong>
5.6.0
</pre>
<div class="paragraph">
<p>Ensuite, créez un fichier caché, <em>.nvmrc</em>, qui contient la version Node.js prise en charge par votre DApp afin que les développeurs n’aient qu’à exécuter "nvm install" à la racine du répertoire du projet et il s’installera automatiquement et passera à l’utilisation de cette version. :</p>
</div>
<pre data-type="programlisting">
$ <strong>node -v > .nvmrc</strong>
$ <strong>nvm install</strong>
</pre>
<div class="paragraph">
<p>Ça parait bien. Maintenant, installons truffle :</p>
</div>
<pre data-type="programlisting">
$ <strong>npm -g install truffle</strong>
installed 1 package in 37.508s
</pre>
</div>
<div class="sect4">
<h5 id="truffle_box">Intégration d’un projet Truffle préconstruit (Truffle Box)</h5>
<div class="paragraph">
<p>Si vous souhaitez utiliser ou créer une DApp qui s’appuie sur un passe-partout prédéfini, accédez au site Web de Truffle Boxes, choisissez un projet Truffle existant, puis exécutez la commande suivante pour le télécharger et l’extraire :</p>
</div>
<pre data-type="programlisting">
$ <strong>truffle unbox <em>BOX_NAME</em></strong>
</pre>
</div>
<div class="sect4">
<h5 id="truffle_project_directory">Création d’un répertoire de projet truffle</h5>
<div class="paragraph">
<p>Pour chaque projet où vous utiliserez <code>truffle</code>, créez un répertoire de projet et initialisez truffle dans ce répertoire. truffle créera la structure de répertoire nécessaire dans le répertoire de votre projet. Il est d’usage de donner au répertoire du projet un nom qui décrit le projet. Pour cet exemple, nous utiliserons truffle pour déployer notre contrat Faucet depuis <a href="#simple_contract_example">[simple_contract_example]</a>, et donc nous nommerons le dossier du projet <em>Faucet</em> :</p>
</div>
<pre data-type="programlisting">
$ <strong>mkdir Faucet</strong>
$ <strong>cd Faucet</strong>
Faucet $
</pre>
<div class="paragraph">
<p>Une fois dans le répertoire <em>Faucet</em>, nous initialisons truffle :</p>
</div>
<pre data-type="programlisting">
Faucet $ <strong>truffle init</strong>
</pre>
<div class="paragraph">
<p>truffle crée une structure de répertoires et des fichiers par défaut :</p>
</div>
<div class="listingblock">
<div class="content">
<pre>Faucet
+---- contracts
| `---- Migrations.sol
+---- migrations
| `---- 1_initial_migration.js
+---- test
+---- truffle-config.js
`---- truffle.js</pre>
</div>
</div>
<div class="paragraph">
<p>Nous utiliserons également un certain nombre de packages de support JavaScript (Node.js), en plus de truffle lui-même. Nous pouvons les installer avec <code>npm</code>. Nous initialisons la structure de répertoires npm et acceptons les valeurs par défaut suggérées par npm :</p>
</div>
<pre data-type="programlisting">
$ <strong>npm init</strong>
package name: (faucet)
version: (1.0.0)
description:
entry point: (truffle-config.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to Faucet/package.json:
{
"name": "faucet",
"version": "1.0.0",
"description": "",
"main": "truffle-config.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this ok? (yes)
</pre>
<div class="paragraph">
<p>Maintenant, nous pouvons installer les dépendances que nous utiliserons pour faciliter le travail avec truffle :</p>
</div>
<pre data-type="programlisting">
$ <strong>npm install dotenv truffle-wallet-provider ethereumjs-wallet</strong>
</pre>
<div class="paragraph">
<p>Nous avons maintenant un répertoire <em>node_modules</em> avec plusieurs milliers de fichiers dans notre répertoire <em>Faucet</em>.</p>
</div>
<div class="paragraph">
<p>Avant de déployer un DApp dans un environnement de production cloud ou d’intégration continue, il est important de spécifier le champ engines afin que votre DApp soit construit avec la bonne version de Node.js et que ses dépendances associées soient installées. Pour plus de détails sur la configuration de ce champ, consultez la <a href="http://bit.ly/2zp2GPF">documentation</a>.</p>
</div>
</div>
<div class="sect4">
<h5 id="_configuration_de_truffle">Configuration de truffle</h5>
<div class="paragraph">
<p>truffle crée des fichiers de configuration vides, <em>truffle.js</em> et <em>truffle-config.js</em>. Sur les systèmes Windows, le nom <em>truffle.js</em> peut provoquer un conflit lorsque vous essayez d’exécuter la commande truffle et que Windows tente d’exécuter <em>truffle.js</em> à la place. Pour éviter cela, nous allons supprimer <em>truffle.js</em> et utiliser <em>truffle-config.js</em> (en soutien aux utilisateurs de Windows, qui, honnêtement, souffrent déjà assez) :</p>
</div>
<pre data-type="programlisting">
$ <strong>rm truffle.js</strong>
</pre>
<div class="paragraph">
<p>Maintenant, nous éditons <em>truffle-config.js</em> et remplaçons le contenu par l’exemple de configuration montré ici :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">module.exports = {
networks: {
localnode: { // Quel que soit le réseau auquel notre nœud local se connecte
network_id: "*", // Correspond à n'importe quel ID de réseau
host: "localhost",
port: 8545,
}
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Cette configuration est un bon point de départ. Il configure un réseau Ethereum par défaut (nommé localnode), qui suppose que nous exécutons un client Ethereum tel que Parity, soit en tant que nœud complet, soit en tant que client léger. Cette configuration demandera à truffle de communiquer avec le nœud local via RPC, sur le port 8545. truffle utilisera le réseau Ethereum auquel le nœud local est connecté, comme le réseau principal Ethereum ou un réseau de test comme Ropsten. Le nœud local fournira également la fonctionnalité de portefeuille.</p>
</div>
<div class="paragraph">
<p>Dans les sections suivantes, nous configurerons des réseaux supplémentaires pour truffle à utiliser, tels que la chaîne de blocs de test locale ganache et Infura, un fournisseur de réseau hébergé. Au fur et à mesure que nous ajouterons des réseaux, le fichier de configuration deviendra plus complexe, mais il nous donnera également plus d’options pour notre flux de travail de test et de développement.</p>
</div>
</div>
<div class="sect4">
<h5 id="_utiliser_truffle_pour_déployer_un_contrat">Utiliser truffle pour déployer un contrat</h5>
<div class="paragraph">
<p>Nous avons maintenant un répertoire de travail de base pour notre projet <em>Faucet</em>, et nous avons truffle et ses dépendances configurées. Les contrats vont dans le sous-répertoire <em>contracts</em> de notre projet. Le répertoire contient déjà un contrat "d’aide", <em>Migrations.sol</em>, qui gère pour nous les mises à jour des contrats. Nous examinerons l’utilisation de <em>Migrations.sol</em> dans la section suivante.</p>
</div>
<div class="paragraph">
<p>Copions le contrat <em>Faucet.sol</em> (depuis <a href="#solidity_faucet_example">[solidity_faucet_example]</a>) dans le sous-répertoire <em>contracts</em>, de sorte que le répertoire du projet ressemble à ceci :</p>
</div>
<div class="listingblock">
<div class="content">
<pre>Faucet
+---- contracts
| +---- Faucet.sol
| `---- Migrations.sol
...</pre>
</div>
</div>
<div class="paragraph">
<p>Nous pouvons maintenant demander à truffle de compiler le contrat pour nous :</p>
</div>
<pre data-type="programlisting">
$ <strong>truffle compile</strong>
Compiling ./contracts/Faucet.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts
</pre>
</div>
<div class="sect4">
<h5 id="truffle_migrations_understanding_deployment_scripts">Migrations Truffle—comprendre les scripts de déploiement</h5>
<div class="paragraph">
<p>Truffle propose un système de déploiement appelé <em>migration</em>. Si vous avez travaillé dans d’autres cadres de développement, vous avez peut-être vu quelque chose de similaire : Ruby on Rails, Python Django et de nombreux autres langages et cadres de développement ont une commande migrate.</p>
</div>
<div class="paragraph">
<p>Dans tous ces cadres de développement, le but d’une migration est de gérer les modifications du schéma de données entre différentes versions du logiciel. Le but des migrations dans Ethereum est légèrement différent. Parce que les contrats Ethereum sont immuables et coûtent du gaz à déployer, Truffle propose un mécanisme de migration pour garder une trace des contrats (et des versions) qui ont déjà été déployés. Dans un projet complexe avec des dizaines de contrats et des dépendances complexes, vous ne voudriez pas avoir à payer pour redéployer des contrats qui n’ont pas changé. Vous ne voudriez pas non plus suivre manuellement quelles versions de quels contrats ont déjà été déployées. Le mécanisme de migration Truffle fait tout cela en déployant le contrat intelligent <em>Migrations.sol</em>, qui suit ensuite tous les autres déploiements de contrat.</p>
</div>
<div class="paragraph">
<p>Nous n’avons qu’un seul contrat, <em>Faucet.sol</em>, ce qui signifie que le système de migration est pour le moins exagéré. Malheureusement, nous devons l’utiliser. Mais, en apprenant à l’utiliser pour un contrat, nous pouvons commencer à mettre en pratique de bonnes habitudes pour notre flux de travail de développement. L’effort sera payant au fur et à mesure que les choses se compliqueront.</p>
</div>
<div class="paragraph">
<p>Le répertoire <em>migrations</em> de Truffle est l’endroit où se trouvent les scripts de migration. À l’heure actuelle, il n’y a qu’un seul script, <em>1_initial_migration.js</em>, qui déploie le contrat <em>Migrations.sol</em> lui-même :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">var Migrations = artifacts.require("./Migrations.sol");
module.exports = function(deployer) {
deployer.deploy(Migrations);
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Nous avons besoin d’un deuxième script de migration, pour déployer <em>Faucet.sol</em>. Appelons-le <em>2_deploy_contracts.js</em>. C’est très simple, tout comme <em>1_initial_migration.js</em>, avec seulement quelques petites modifications. En fait, vous pouvez copier le contenu de <em>1_initial_migration.j</em> et simplement remplacer toutes les instances de Migrations par Faucet :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">var Faucet = artifacts.require("./Faucet.sol");
module.exports = function(deployer) {
deployer.deploy(Faucet);
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Le script initialise une variable <code>Faucet</code>, identifiant le code source Solidity <em>Faucet.sol</em> comme l’artefact qui définit <code>Faucet</code>. Ensuite, il appelle la fonction "deploy" pour déployer ce contrat.</p>
</div>
<div class="paragraph">
<p>Nous sommes prêts. Utilisons truffle migrate pour le déployer. Nous devons spécifier sur quel réseau déployer le contrat, en utilisant l’argument --network . Nous n’avons qu’un seul réseau spécifié dans le fichier de configuration, que nous avons nommé <code>localnode</code>. Assurez-vous que votre client Ethereum local est en cours d’exécution, puis tapez :</p>
</div>
<pre data-type="programlisting">
Faucet $ <strong>truffle migrate --network localnode</strong>
</pre>
<div class="paragraph">
<p>Comme nous utilisons un nœud local pour nous connecter au réseau Ethereum et gérer notre portefeuille, nous devons autoriser la transaction créée par <code>truffle</code>. Nous exécutons parity connecté à la chaîne de blocs de test de Ropsten, donc pendant la migration, nous verrons une fenêtre contextuelle comme celle de <a href="#parity_deployment_confirmation">Parity demandant confirmation pour déployer Faucet</a> sur la console web de Parity.</p>
</div>
<div id="parity_deployment_confirmation" class="imageblock">
<div class="content">
<img src="images/parity_deployment_confirmation.png" alt="Parité demandant confirmation pour déployer Faucet">
</div>
<div class="title">Figure 1. Parity demandant confirmation pour déployer Faucet</div>
</div>
<div class="paragraph">
<p>Il y a quatre transactions au total : une pour déployer <code>Migrations</code>, une pour mettre à jour le compteur de déploiements à <code>1</code>, une pour déployer Faucet et une pour mettre à jour le compteur de déploiements à <code>2</code>.</p>
</div>
<div class="paragraph">
<p>Truffle affichera les migrations terminées, affichera chacune des transactions et affichera les adresses de contrat :</p>
</div>
<pre data-type="programlisting">
$ <strong>truffle migrate --network localnode</strong>
Using network 'localnode'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0xfa090db179d023d2abae543b4a21a1479e70ca7d35a469a5d1a98bfc6bd80fe8
Migrations: 0x8861c27715550bed8362c0345add158489df6db0
Saving successful migration to network...
... 0x985c4a32716826ddbe4eae284104bef8bc69e959899f62246a1b27c9dfcd6c03
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying Faucet...
... 0xecdbeef77f0558edc689440e34b7bba0a3ba7a45e4b680b071b47c30a930e9d6
Faucet: 0xd01cd8e7bd29e4bff8c1693f59eee46137a9f300
Saving successful migration to network...
... 0x11f376bd7307edddfd40dc4a14c3f7cb84b6c921ac2465602060b67d08f9fd8a
Saving artifacts...
</pre>
</div>
<div class="sect4">
<h5 id="_utilisation_de_la_console_truffle">Utilisation de la console Truffle</h5>
<div class="paragraph">
<p>Truffle propose une console JavaScript que nous pouvons utiliser pour interagir avec le réseau Ethereum (via le noeud local), interagir avec les contrats déployés et interagir avec le fournisseur de portefeuille. Dans notre configuration actuelle (localnode), le fournisseur de nœud et de portefeuille est notre client Parity local.</p>
</div>
<div class="paragraph">
<p>Démarrons la console Truffle et essayons quelques commandes :</p>
</div>
<pre data-type="programlisting">
$ <strong>truffle console --network localnode</strong>
truffle(localnode)>
</pre>
<div class="paragraph">
<p>Truffle présente une invite indiquant la configuration réseau sélectionnée (localnode).</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>Il est important de se rappeler et de savoir quel réseau vous utilisez. Vous ne voudriez pas déployer accidentellement un contrat de test ou effectuer une transaction sur le réseau principal Ethereum. Cela pourrait être une erreur coûteuse!</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>La console Truffle offre une fonction de saisie semi-automatique qui nous permet d’explorer facilement l’environnement. Si nous appuyons sur Tab après une commande partiellement terminée, Truffle terminera la commande pour nous. Appuyer deux fois sur Tab affichera toutes les complétions possibles si plus d’une commande correspond à notre entrée. En fait, si nous appuyons deux fois sur Tab sur une invite vide, Truffle liste toutes les commandes disponibles :</p>
</div>
<pre data-type="programlisting" class="codewrap">
truffle(localnode)>
Array Boolean Date Error EvalError Function Infinity JSON Math NaN Number Object RangeError ReferenceError RegExp String SyntaxError TypeError URIError decodeURI decodeURIComponent encodeURI encodeURIComponent eval isFinite isNaN parseFloat parseInt undefined
ArrayBuffer Buffer DataView Faucet Float32Array Float64Array GLOBAL Int16Array Int32Array Int8Array Intl Map Migrations Promise Proxy Reflect Set StateManager Symbol Uint16Array Uint32Array Uint8Array Uint8ClampedArray WeakMap WeakSet WebAssembly XMLHttpRequest _ assert async_hooks buffer child_process clearImmediate clearInterval clearTimeout cluster console crypto dgram dns domain escape events fs global http http2 https module net os path perf_hooks process punycode querystring readline repl require root setImmediate setInterval setTimeout stream string_decoder tls tty unescape url util v8 vm web3 zlib
__defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__ __proto__ constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf
</pre>
<div class="paragraph">
<p>La grande majorité des fonctions liées au portefeuille et aux nœuds sont fournies par l’objet <code>web3</code>, qui est une instance de la bibliothèque web3.js. L’objet web3 résume l’interface RPC à notre nœud Parity. Vous remarquerez également deux objets aux noms familiers : Migrations et <code>Faucet</code>. Ceux-ci représentent les contrats que nous venons de déployer. Nous utiliserons la console Truffle pour interagir avec un contrat. Tout d’abord, vérifions notre wallet via l’objet web3 :</p>
</div>
<pre data-type="programlisting">
truffle(localnode)> <strong>web3.eth.accounts</strong>
[ '0x9e713963a92c02317a681b9bb3065a8249de124f',
'0xdb5dc1a13e3a55cf3b4587cd8d1e5fdeb6738145' ]
</pre>
<div class="paragraph">
<p>Notre client Parity a deux portefeuilles, avec un peu d’ether de test sur Ropsten. L’attribut web3.eth.accounts contient une liste de tous les comptes. Nous pouvons vérifier le solde du premier compte en utilisant la fonction getBalance :</p>
</div>
<pre data-type="programlisting">
truffle(localnode)> <strong>web3.eth.getBalance(web3.eth.accounts[0]).toNumber()</strong>
191198572800000000
truffle(localnode)>
</pre>
<div class="paragraph">
<p>web3.js est une grande bibliothèque JavaScript qui offre une interface complète au système Ethereum, via un fournisseur tel qu’un client local. Nous examinerons web3.js plus en détail dans <a href="#web3js_tutorial">[web3js_tutorial]</a>. Essayons maintenant d’interagir avec nos contrats :</p>
</div>
<pre data-type="programlisting">
truffle(localnode)> <strong>Faucet.address</strong>
'0xd01cd8e7bd29e4bff8c1693f59eee46137a9f300'
truffle(localnode)> <strong>web3.eth.getBalance(Faucet.address).toNumber()</strong>
0
truffle(localnode)>
</pre>
<div class="paragraph">
<p>Ensuite, nous utiliserons sendTransaction pour envoyer de l’ether de test afin de financer le contrat <code>Faucet</code>. Notez l’utilisation de web3.utils.toWei pour convertir les unités ether pour nous. Taper 18 zéros sans se tromper est à la fois difficile et dangereux, il est donc toujours préférable d’utiliser un convertisseur d’unités pour les valeurs. Voici comment nous envoyons la transaction :</p>
</div>
<pre data-type="programlisting">
truffle(localnode)> <strong>web3.eth.sendTransaction({from:web3.eth.accounts[0],
to:Faucet.address, value:web3.utils.toWei(0.5, 'ether')});</strong>
'0xf134c75b985dc0e0c27c2f0412251e0860eb530a5055e660f21e7483ab336808'
</pre>
<div class="paragraph">
<p>Si nous passons à l’interface Web de Parity, nous verrons une fenêtre contextuelle nous demandant de confirmer cette transaction. Une fois la transaction extraite, nous pourrons voir le solde de notre contrat Faucet :</p>
</div>
<pre data-type="programlisting">
truffle(localnode)> <strong>web3.eth.getBalance(Faucet.address).toNumber()</strong>
500000000000000000
</pre>
<div class="paragraph">
<p>Appelons maintenant la fonction <code>withdraw</code>, pour retirer de l’ether de test du contrat :</p>
</div>
<pre data-type="programlisting">
truffle(localnode)> <strong>Faucet.deployed().then(instance =>
{instance.withdraw(web3.utils.toWei(0.1,
'ether'))}).then(console.log)</strong>
</pre>
<div class="paragraph">
<p>Encore une fois, nous devrons approuver la transaction dans l’interface Web de Parity. Si nous vérifions à nouveau, nous verrons que le solde du contrat Faucet a diminué et que notre portefeuille de test a reçu 0,1 ether:</p>
</div>
<pre data-type="programlisting">
truffle(localnode)> <strong>web3.eth.getBalance(Faucet.address).toNumber()</strong>
400000000000000000
truffle(localnode)> <strong>Faucet.deployed().then(instance =>
{instance.withdraw(web3.utils.toWei(1, 'ether'))})</strong>
StatusError: Transaction: 0xe147ae9e3610334...8612b92d3f9c
exited with an error (status 0).
</pre>
</div>
</div>
<div class="sect3">
<h4 id="_embark">Embark</h4>
<div class="paragraph">
<p>GitHub : <a href="https://github.com/embark-framework/embark/" class="bare">https://github.com/embark-framework/embark/</a></p>
</div>
<div class="paragraph">
<p>Documents : <a href="https://embark.status.im/docs/" class="bare">https://embark.status.im/docs/</a></p>
</div>
<div class="paragraph">
<p>Référentiel de packages npm : <a href="https://www.npmjs.com/package/embark" class="bare">https://www.npmjs.com/package/embark</a></p>
</div>
<div class="paragraph">
<p>Embark est un framework conçu pour permettre aux développeurs de développer et de déployer facilement des applications décentralisées.
Embark s’intègre à Ethereum, IPFS, Whisper et Swarm pour offrir les fonctionnalités suivantes :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Déployer automatiquement les contrats et les rendre disponibles en code JS.</p>
</li>
<li>
<p>Surveiller les changements et mettez à jour les contrats pour les redéployer si nécessaire.</p>
</li>
<li>
<p>Gérer et interagir avec différentes chaînes (par exemple, testnet, local, mainnet).</p>
</li>
<li>
<p>Gérer des systèmes complexes de contrats interdépendants.</p>
</li>
<li>
<p>Stocker et récupérer des données, y compris le téléchargement et la récupération de fichiers hébergés dans IPFS.</p>
</li>
<li>
<p>Faciliter le processus de déploiement de l’application complète sur IPFS ou Swarm.</p>
</li>
<li>
<p>Envoyer et recevoir des messages via Whisper.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Vous pouvez l’installer avec npm :</p>
</div>
<pre data-type="programlisting">
$ <strong>npm -g install embark</strong>
</pre>
</div>
<div class="sect3 pagebreak-before">
<h4 id="_openzeppelin">OpenZeppelin</h4>
<div class="paragraph">
<p>GitHub : <a href="https://github.com/OpenZeppelin/openzeppelin-solidity" class="bare">https://github.com/OpenZeppelin/openzeppelin-solidity</a></p>
</div>
<div class="paragraph">
<p>Site Web : <a href="https://openzeppelin.org/" class="bare">https://openzeppelin.org/</a></p>
</div>
<div class="paragraph">
<p>Documentation : <a href="https://openzeppelin.org/api/docs/open-zeppelin.html" class="bare">https://openzeppelin.org/api/docs/open-zeppelin.html</a></p>
</div>
<div class="paragraph">
<p><a href="https://openzeppelin.org/">OpenZeppelin</a> est un cadre ouvert de contrats intelligents réutilisables et sécurisés dans le langage Solidity.</p>
</div>
<div class="paragraph">
<p>Il est piloté par la communauté, dirigé par l’équipe <a href="https://zeppelin.solutions/">Zeppelin</a>, avec plus d’une centaine de contributeurs externes. L’objectif principal du cadre est la sécurité, obtenue en appliquant des modèles de sécurité de contrat standard et les meilleures pratiques, en s’appuyant sur toute l’expérience que les développeurs Zeppelin ont acquise en <a href="https://blog.zeppelin.solutions/tagged/security">auditant</a> un grand nombre de contrats, et grâce à des tests et des audits constants de la part de la communauté qui utilise le cadre de développement comme base pour leurs applications dans le monde réel.</p>
</div>
<div class="paragraph">
<p>Le cadre de développement OpenZeppelin est la solution la plus largement utilisée pour les contrats intelligents Ethereum. Le cadre de développement dispose actuellement d’une vaste bibliothèque de contrats, y compris des implémentations de jetons ERC20 et ERC721, de nombreuses variantes de modèles de vente publique et des comportements simples que l’on trouve couramment dans des contrats tels que "Ownable", "Pausable" ou "LimitBalance". Les contrats de ce référentiel fonctionnent dans certains cas comme des implémentations standard <em>de facto</em>.</p>
</div>
<div class="paragraph">
<p>Le cadre est sous licence MIT, et tous les contrats ont été conçus avec une approche modulaire pour garantir la facilité de réutilisation et d’extension. Ce sont des blocs de construction propres et basiques, prêts à être utilisés dans votre prochain projet Ethereum. Configurons le cadre et construisons une simple vente publique à l’aide des contrats OpenZeppelin, pour démontrer à quel point il est facile à utiliser. Cet exemple souligne également l’importance de réutiliser des composants sécurisés au lieu de les écrire par vous-même.</p>
</div>
<div class="paragraph">
<p>Tout d’abord, nous devrons installer la bibliothèque openzeppelin-solidity dans notre espace de travail. La dernière version au moment d’écrire ces lignes est la v1.9.0, nous allons donc l’utiliser :</p>
</div>
<pre data-type="programlisting">
$ <strong>mkdir sample-crowdsale</strong>
$ <strong>cd sample-crowdsale</strong>
$ <strong>npm install [email protected]</strong>
$ <strong>mkdir contracts</strong>
</pre>
<div class="paragraph">
<p>Au moment de la rédaction, OpenZeppelin comprend plusieurs contrats de jetons de base qui suivent les normes ERC20, ERC721 et ERC827, avec différentes caractéristiques d’émission, de limites, d’acquisition, de cycle de vie, etc.</p>
</div>
<div class="paragraph">
<p>Créons un jeton ERC20 monnayable, ce qui signifie que l’approvisionnement initial commence à 0 et que de nouveaux jetons peuvent être créés par le propriétaire du jeton (dans notre cas, le <span class="keep-together">contrat</span> de vente publique) et vendus aux acheteurs. Pour ce faire, nous allons créer un fichier <em>contracts/SampleToken.sol</em> avec le contenu suivant :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">pragma solidity 0.4.23;
import 'openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol';
contract SampleToken is MintableToken {
string public name = "SAMPLE TOKEN";
string public symbol = "SAM";
uint8 public decimals = 18;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>OpenZeppelin fournit déjà un contrat MintableToken que nous pouvons utiliser comme base pour notre jeton, nous ne définissons donc que les détails spécifiques à notre cas. Ensuite, faisons le contrat de vente publique. Tout comme avec les jetons, OpenZeppelin propose déjà une grande variété de saveurs de vente publique. Actuellement, vous trouverez des contrats pour divers scénarios impliquant la distribution, l’émission, le prix et la validation. Donc, disons que vous voulez fixer un objectif pour votre vente publique et s’il n’est pas atteint au moment où la vente se termine, vous voulez rembourser tous vos investisseurs. Pour cela, vous pouvez utiliser le contrat <a href="http://bit.ly/2yHoh65">RefundableCrowdsale</a>. Ou peut-être souhaitez-vous définir une vente publique avec un prix croissant pour inciter les premiers acheteurs ; il y a un contrat <a href="http://bit.ly/2PtWOys"><code>IncreasingPriceCrowdsale</code></a>juste pour ça. Vous pouvez également mettre fin à la vente publique lorsqu’une quantité spécifiée d’ether a été reçue par le contrat (<a href="http://bit.ly/2OVsCN8">CappedCrowdsale</a>), ou définir une heure de fin avec le contrat <a href="http://bit.ly/2zp2Nuz">TimedCrowdsale</a>, ou créez une liste blanche d’acheteurs avec le contrat <a href="http://bit.ly/2CN8Hc9">WhitelistedCrowdsale</a>.</p>
</div>
<div class="paragraph">
<p>Comme nous l’avons dit précédemment, les contrats OpenZeppelin sont des éléments de base. Ces contrats de crowdsale ont été conçus pour être combinés ; il suffit de lire le code source du contrat de base <a href="http://bit.ly/2ABIQSI"><code>Crowdsale</code></a>pour savoir comment l’étendre. Pour la vente publique de notre jeton, nous devons créer des jetons lorsque l’ether est reçu par le contrat de vente publique, utilisons donc <a href="http://bit.ly/2Sx3HOc"><code>MintedCrowdsale</code></a>comme base. Et pour le rendre plus intéressant, faisons-en également une <a href="http://bit.ly/2Qef0Jm"><code>PostDeliveryCrowdsale</code></a>afin que les jetons ne puissent être retirés qu’après la fin de la vente publique. Pour ce faire, nous allons écrire ce qui suit dans <em>contracts/SampleCrowdsale.sol</em> :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">pragma solidity 0.4.23;
import './SampleToken.sol';
import 'openzeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol';
import 'openzeppelin-solidity/contracts/crowdsale/ \
distribution/PostDeliveryCrowdsale.sol';
contract SampleCrowdsale is PostDeliveryCrowdsale, MintedCrowdsale {
constructor(
uint256 _openingTime,
uint256 _closingTime
uint256 _rate,
address _wallet,
MintableToken _token
)
public
Crowdsale(_rate, _wallet, _token)
PostDeliveryCrowdsale(_openingTime, _closingTime)
{
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Encore une fois, nous avons à peine eu à écrire du code ; nous venons de réutiliser le code testé au combat que la communauté OpenZeppelin a mis à disposition. Cependant, il est important de noter que ce cas est différent de celui de notre contrat <code>SampleToken</code>. Si vous allez sur les <a href="http://bit.ly/2Q8lQ3o">Tests automatisés Crowdsale</a>, vous verrez qu’ils sont testés de manière isolée. Lorsque vous intégrez différentes unités de code dans un composant plus gros, il ne suffit pas de tester toutes les unités séparément, car les interactions entre elles peuvent provoquer des comportements auxquels vous ne vous attendiez pas. En particulier, vous verrez qu’ici nous avons introduit l’héritage multiple, ce qui peut surprendre le développeur s’il ne comprend pas les détails de Solidity. Notre <span class="keep-together"><code>SampleCrowdsale</code></span> est simple et fonctionnera exactement comme prévu, car le cadre a été conçu pour simplifier des cas comme ceux-ci ; mais ne relâchez pas votre vigilance à cause de la simplicité qu’introduit ce cadre de développement. Chaque fois que vous intégrez des parties du cadre de développement OpenZeppelin pour créer une solution plus complexe, vous devez tester entièrement chaque aspect de votre solution pour vous assurer que toutes les interactions des unités fonctionnent comme vous le souhaitez.</p>
</div>
<div class="paragraph">
<p>Enfin, lorsque nous sommes satisfaits de notre solution et que nous l’avons testée de manière approfondie, nous devons la déployer. OpenZeppelin s’intègre bien à Truffle, nous pouvons donc simplement écrire un fichier de migration comme celui-ci (<em>migrations/2_deploy_contracts.js</em>), comme expliqué dans <a href="#truffle_migrations_understanding_deployment_scripts">Migrations Truffle—comprendre les scripts de déploiement</a> :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-js" data-lang="js">const SampleCrowdsale = artifacts.require('./SampleCrowdsale.sol');
const SampleToken = artifacts.require('./SampleToken.sol');
module.exports = function(deployer, network, accounts) {