Академический Документы
Профессиональный Документы
Культура Документы
ing started
TheFrontieristhefirstlivereleaseoftheEthereumnetwork.Assuchyouareenteringuncharted
territoryandyouareinvitedtotestthegroundsandexplore.Thereisalotofdanger,theremaystill
beundiscoveredtraps,theremayberavagingbandsofpirateswaitingtoattackyou,buttherealso
isvastroomforopportunities.
InordertonavigatetheFrontier,youllneedtousethecommandline.Ifyouarenotcomfortable
usingit,westronglyadviseyoutostepback,watchfromadistanceforawhileandwaituntilmore
userfriendlytoolsaremadeavailable.Remember,therearenosafetynetsandforeverythingyou
dohere,youaremostlyonyourown.
TheFrontiertooliscalledGeth(theoldenglishthirdpersonsingularconjugationoftogo.Quite
appropriategivengethiswrittenin
Go
).Inordertogetit,openyourcommandlinetool(ifyouare
unsurehowtodothis,considerwaitingforamoreuserfriendlyrelease)andpastethecommand
below.
rubye"$(curlfsSL
https://raw.githubusercontent.com/cubedro/frontier.ethereum.org/master/bi
n/install.rb)"
Or,alternatively
rubye"$(curlfsSL
https://raw.githubusercontent.com/cubedro/frontier.ethereum.org/master/bi
n/install.rb)"
Pastetheaboveonelinerinyourterminalforanautomatedinstallscript.Thisscriptwilldetectyour
OSandwillattempttoinstalltheethereumCLI.Pleaseclickthebuttonbelowifyou'dliketoseea
stepbystepdescriptionoftheinstallerscript.
GethisamultipurposecommandlinetoolthatrunsafullEthereumnodeimplementedinGo.It
offersthreeinterfaces:thecommandlinesubcommandsandoptions[link],aJSONRPCserver
andaninteractiveconsole.Forthepurposesofthisguide,wewillfocusontheConsole,a
javascriptenvironmentthatcontainsallthemainfeaturesyouprobablywant.Typethecodebelow
onyourterminal
gethconsole2>>geth.log
Youarereadytostart.The2>>geth.logcreatesatextfilewiththeoutputofyourconsole.Ona
linuxmachineorMacOSyoucanrunoneterminalwiththegethconsoleandasecondonewith
theloggingoutputbyopeninganewterminalandtyping:tty
Theoutputwillbesomethinglike:
/dev/pts/13
(oronMac
/dev/tty002
).Theninyourmain
terminaltype:
gethconsole2>>/dev/pts/13
Thiswillallowyoutomonitoryournode
withoutclutteringyourconsole
.
Thegethconsolehashistorythatpersistsbetweensessions.Youcannavigateyourcommand
historybyusingtheupanddownarrowkeys.
Tip:
sometimesyoumightnotneedtoconnecttothelivepublicnetwork,youcaninsteadchoose
tocreateyourownprivatetestnet.Thisisveryusefulifyoudon'tneedtotestexternalcontracts
andwantjusttotestthetechnology,becauseyouwon'thavetocompetewithotherminersandwill
easilygeneratealotoftestethertoplayaround(replace12345withanynumber
gethnetworkid12345console
Ifyouuseaprivatetestnet,itmaybeagoodideatostartwitha'fresh'blockchain,andnotthereal
blockchain.Otherwise,inordertosuccessfullymineablock,you'llneedtomineagainstthe
difficultyofthelastblockpresentinyourlocalcopyoftheblockchainwhichmaytakeseveral
hours.Thisisdoneviathe`datadir`parameter:
gethnetworkid=123datadir=~/.ethereum_experimentconsole`
InordertodomostactionsinEthereumyouneedether,andtogetit,youwillneedtogeneratean
address(see
herefordetaileddocumentationonmanagingyouraccounts
).Type:
admin.newAccount()
Youllbeaskedforapassphrase.Chooseonewiselyandyouwillbepromptedtotypeittwice.Do
NOTforgetthispassphrase,otherwiseitwillnotbepossibletorecoveranyfundsyoumayhaveon
youraccount.Youvebeenwarned!
Tip:
Typingadminbyitselfwillbringupalistofsubcommandsusedtoadministeryourgeth
installation.
TheFollowingcommandgeneratesanaddressandassociatesitwithyourlocalmachine.Youcan
createmultipleaccountsbyexecutingthesamecommandagain.Goon,tryit:
admin.newAccount()
Byconventionwecallthefirstaccountyoucreateyourprimaryaccount.Youcanseeallyour
accountswiththecommand:
eth.accounts
NoticethatitoutputsaJavascriptarray.Itsbecauseallcommandsontheconsoleareactuallyin
javascript,soyoucancreatevariablesanddaisychainfunctions.Youcanalsowriteanyeth
functionasweb3.ethsinceitsactuallypartofthemainweb3object.
Trythisforexample:
varprimaryAccount=eth.accounts[0]
YounowhaveavariablecalledprimaryAccountthatyoucanuseinothercalls,likethis:
eth.getBalance(primaryAccount)
Alreadyfeelingcomfortable?Timetogetsomeether.Therearethreedifferentways:
Thatisbyfartheeasiestwaytogetether,butyouneedtoknowsomeonewhoiswillingtogiveyou
ahand.Ifyouhavesuchafriend,thentype:
eth.accounts[0]
Copytheaddressandsendittothemhopingtoreceivesomelovethroughtheether.Ifyoudon't
knowanyonewhocanprovideitforyou,youcanuseafaucet,whichhandouttestetherforfree.
Trythe
Zerogox
or
EtherParty
faucets.Ifthefaucetsarenotonlineforsomereason,youcanalso
tryaskingdirectlytothecommunityon
IRC
.
2. Mining ether
Sinceyouareoneofthefirstpioneers,itmightbepossibletoacquireetherbymining.Youcan
startyourminingoperationbytyping
admin.miner.start()
Beforeyoucanreallyfindblocksyourcomputerneedstogothroughaprocesscalledbuildinga
DAG.TheDAG(whichstandsforDirectedAcyclicGraph)isalargeblockofdatathatisrequired
formining,intendedtopreventASICappliances(whichstandsforApplicationSpecificIntegrated
Circuits)frombeingmassmanufacturedforminingethereum.Itisintendedtoprotectpioneers
likeyourselfsothatyouwillonlyeverneedyourhomecomputertomine..TheDAGshouldtake
about10minutestogenerateandassoonasitfinishesitwillstartminingautomatically.Ifatany
pointyouwanttoseewhatsgoingon,youcantype
admin.miner.hashrate()
Thisgivesyouanideaofhowmuchworkyourcomputerisdoingpersecond.Nowheadtothe
NetworkStatsPage
andtakealookattheDifficulty.
Dividethatnumberbyyourcurrent
hashrateandthatwillgiveyouanestimate,inseconds,ofhowlongyoucanexpecttowait
untilyoumineablockandgetsomeether.
Thisisanoverestimatebecauseitdoesnottakein
considerationthenumberandrewardsforuncleblocks
.
Youcanusethiscodesnippettodothis
automatically:
Math.floor(10*eth.getBlock("latest").difficulty/(60*
admin.miner.hashrate()))/10+"Minutes"
Ifyouhavesuccessfullyminedablockyouwillseeamessagelikethisinthelogfile:
Minedblock#12345
Yourcoinbaseistheaccountwhereyourminingrewardissent,bydefaultitistheprimaryaccount.
Inordertocheckyourearnings,youcandisplayyourcoinbasebalance:
web3.fromWei(eth.getBalance(eth.coinbase),"ether")
Note:theminingrewardsinthefrontiernetworkareonly10%ofwhattheyllbewhenthe
Homesteadphasebegins.Frontiershouldbealwaysconsideredatestnetworkforthe
network.
Thingstodo:
Ifyouareseriousaboutmining,thenyoucanalso:readmoreaboutminingwith
geth,
understandthecurrentproofofwork
andwhyitisASICresistant,readupaboutproofof
stake,orstartyourGPUminingoperation.
ReadtheMiningDocumentation
orcheckoutthe
ethereumminingguide
onourforums.
Beforeyoudecidetoimportyourpresaleetherwallet,pleaserememberthatFrontierisatest
network.Itsdangerous,potentiallyfullofbugsandispronetoinstability.Whileallaccount
balancesabove1etherwillbemovedovertohomesteadwhenitlaunches,themoneyincontracts
willnot.Therearemanypotentialmishaps,moneycanbelost,stolenorlockedintoabroken
contract.Westronglyadviseyoutoonlymovefundsthatyouarewillingtorisk.Ifyoustillwantto
goforward,
readthisotherarticle
.[LINKNEEDED]
Therearetwotypesofaccountsinethereum:
1. normalaccounts,whichholdonlyetherthatcanbemovedwithaprivatekeyand
2. contractaddresses,whichholdethercontrolledbyitsowninternalcode.Letsfocusonthe
formerfirst.
Andsimilarly,yourtransactionsarealsooftwotypes:transactionssenttonormalaccountsare
ethertransfers,whiletherestiscommunicationwithsmartcontracts,
Beforeyousendyourfirstethertransferyouneedafriendtosendyouretherto.Ifyoudonthave
any,youcanalsocreateasmanynewaccountsasyouwant,followingthestepsdiscussedabove
andsimplymoveyourfundsbetweenaccountsyouown.Afteryouvedonethat,runthis:
varsender=eth.accounts[0]
varreceiver=eth.accounts[1]
varamount=web3.toWei(0.01,"ether")
Thefirsttwolinessetlocalvariableswithaccountnumbersforeasieraccesslater..Changethe
senderandreceiveraddressasmuchasyoulike.Ifyouareaddinganaddressinstead,putitin
betweenquoteslike0xffd25e388bf07765e6d7a00d6ae83fa750460c7e'.Thethirdlineconvertsthe
tokenunitsasrequiredbythenetwork..
Althoughtherearemanynamesfor
etherdenominations
wewilluseonlytwo:etherandwei.
Theweiistheminimumatomicunitofether,andiswhatisusedonthesystemlevel.Mostdayto
daytransactionswillbedonewithether,whichisequivalenttoonequintillionwei,ora1followed
by18zeros.Sobeforesendinganytransactionsitsveryimportanttoconvertittowei,andforthat,
usethe
web3.toWei
function.(Ifyouaredealingwithsmallamountsofether,itmightbeusefulto
usefinney,whichisashorthandforathousandthofanether,butinmostcasesetherwillsuffice).
Afterhavingsetthevariablesabove,sendthetransactionwith:
eth.sendTransaction({from:sender,to:receiver,value:amount})
Afterwaitingafewseconds,thetransactionshouldbecomplete.Tocheckthebalanceofan
account,yousimplytype:
eth.getBalance(eth.accounts[0])
Tip:ifyouwanttocheckthebalanceofallyouraccountsatonce,usethisJavaScriptcode
snippet:
Thiscodewillrunineachofyouraccountsandprintitsbalanceinether.
functioncheckAllBalances(){
vari=0
eth.accounts.forEach(function(e){
console.log("eth.accounts["+i+"]:"+e+"\tbalance:"+
web3.fromWei(eth.getBalance(e),"ether")+"ether")
i++
})
}
Onceyouexecutedthelineabove,allyouneedtocheckyourwholebalanceis:
checkAllBalances()
Tryityourself:
tweakthisjavascriptfunctiontomakeitshowanotherunit,likefinney.
Learnmore:
Readthetransactionsdocumentation
Allaccountsarereferencedinthenetworkbytheirpublicaddress.Butaddressesarelong,difficult
towritedown,hardtomemorizeandimmutable.Thelastoneisspeciallyimportantifyouwantto
beabletogeneratefreshaccountsinyourname,orupgradethecodeofyourcontract.Inorderto
solvethis,thereisadefaultnameregistrarcontractwhichisusedtoassociatethelongaddresses
withshort,humanfriendlynames.
Nameshavetouseonlyalphanumericcharactersand,cannotcontainblankspaces.Infuture
releasesthenameregistrarwilllikelyimplementabiddingprocesstopreventnamesquattingbut
fornow,it'safirstcomefirstservedbased.Soaslongasnooneelseregisteredthename,youcan
claimit.
First,selectyourname:
varmyName="bob"
Then,checktheavailabilityofyourname:
registrar.addr(myName)
Ifthatfunctionreturns"0x00..",youcanclaimittoyourself:
registrar.reserve.sendTransaction(myName,{from:eth.accounts[0]})
Waitfortheprevioustransactiontobepickedup.Waituptothirtysecondsandthentry:
registrar.owner(myName)
Ifitreturnsyouraddress,itmeansyouownthatnameandareabletosetyourchosennameto
anyaddressyouwant:
registrar.setAddress.sendTransaction(myName,eth.accounts[1],true,{from:
eth.accounts[0]})
Youcansendatransactiontoanyonebynameinsteadofaccountsimplybytyping
eth.sendTransaction({from:eth.accounts[0],to:registrar.addr("bob"),
value:web3.toWei(1,"ether")})
Tip:
don'tmistakeregistrar.addrforregistrar.owner.Thefirstistowhichaddressthatnameis
pointedat:anyonecanpointanametoanywhereelse,justlikeanyonecanforwardalinkto
google.com,butonlytheownerofthenamecanchangeandupdatethelink.Youcansetbothto
bethesameaddress.
Nowthatyoumasteredthebasicsonhowtogetstartedandhowtosendether,it'stimetogetyour
handsdirtyinwhatreallymakesethereumstandoutofthecrowd:smartcontracts.Smartcontracts
arepiecesofcodethatliveontheblockchainandexecutecommandsexactlyhowtheyweretold
to.Theycanreadothercontracts,takedecisions,sendetherandexecuteothercontracts.
Contractswillexistandrunaslongasthewholenetworkexists,andwillonlystopiftheyrunoutof
gasoriftheywereprogrammedtoselfdestruct.
Whatcanyoudowithcontracts?Youcandoalmostanythingreally,butforthisguidelet'sdo
somethingsimple:youwillstartyournewcountry.
Yourcountrywon'tbeverypowerfulcomparedtomost:itwillholdnoland,havenomilitaryand
holdnoassetsotherthanthosethatexistontheblockchain.Allit'scitizenswillbevoluntaryandit
isunabletocoerceotherpeoplebyforce.
Butwhatit
can
doistogathersupportaroundaunitedcause.Youwillgetfundsthrougha
crowdfundingthat,ifsuccessful,willsupplyaradicallytransparentanddemocraticorganizationthat
willonlyobeyitsowncitizens,willneverswerveawayfromitsconstitutionandcannotbecensored
orshutdown.Andallthatinlessthan300linesofcode.
Solet'sstartnow.
Important:Frontierisconsideredatestnetwork.Allcontractsmightbewipedwhenthe
projecttransitionstothenextphase,andallethertheycontainwillbelost.Onlysendsmall
amountsoffundstocontracts,unlessareokaylosingthem.
fulldocumentation:https://github.com/ethereum/goethereum/wiki/ContractsandTransactions
NowthatyouvemasteredthebasicsofEthereum,letsmoveintoyourfirstseriouscontract.Itsa
bigopenterritoryandsometimesyoumightfeellonely,soourfirstorderofbusinesswillbeto
createalittleautomaticcompaniontogreetyouwheneveryoufeellonely.Wellcallhimthe
Greeter.
contractgreeter{
//Declarevariableadminwhichwillstoreanaddress
addresspublicadmin
//thisfunctionisexecutedatinitialization
//andsetstheownerofthecontract
functiongreeter(){
admin=msg.sender
}
//mainfunction
functiongreet(bytes32input)returns(bytes32){
if(input==""){return"Hello,World"}
returninput
}
//Functiontorecoverthefundsonthecontract
functionkill(){
if(msg.sender==admin){
suicide(admin)
}
}
}
Asyoucansee,theGreeterisanintelligentdigitalentitythatlivesontheblockchainandisableto
haveconversationswithanyonewhointeractswithit,basedonitsinput.Itmightnotbeatalker,
butitsagreatlistener.
Beforeyouareabletouploadittothenetwork,youneedtwothings:thecompiledcode,andthe
ApplicationBinaryInterface,whichisasortofuserguideonhowtointeractwiththecontract.
Thefirstyoucangetbyusingacompiler.Youshouldhaveasoliditycompilerbuiltinonyourgeth
console.Totestit,usethiscommand:
eth.getCompilers()
Ifyouhaveitinstalled,itshouldoutputsomethinglikethis:
['Solidity']
Ifinsteadthecommandreturnsanerror,thenreadthedocumentationon
howtoinstallacompiler
,
use
Alethzero
orusethe
onlinesoliditycompiler
.
IfyouhaveGethSolidityCompilerinstalled,youneednowreformatbyremovingspacessoitfits
intoastringvariable(thereare
someonlinetools
thatwilldothis):
vargreeterSource='contractgreeter{addressadminfunctiongreeter()
{admin=msg.sender}functiongreet(bytes32input)returns(bytes32){
if(input==""){return"Hello,World"}returninput}function
kill(){if(msg.sender==admin){suicide(admin)}}}'
Onceyousuccessfullyexecutedtheabove,compileitandpublishtothenetworkusingthe
followingcommands:
vargreeterCompiled=eth.compile.solidity(greeterSource)
vargreeterAddress=eth.sendTransaction({data:
greeterCompiled.greeter.code,from:eth.accounts[0],gas:1000000,
gasPrice:web3.toWei(0.001,"finney")})
Youwillprobablybeaskedforthepasswordyoupickedinthebeginning.Youarechoosingfrom
whichaccountwillpayforthetransaction.Dependingonthecurrentgasprice,expectthatthis
contracttocostapproximately
0.5ether
.
Waitaminuteforyourtransactiontobepickedupandthentype:
eth.getCode(greeterAddress)
Thisshouldreturnthecodeofyourcontract.Ifitreturns0x,itmeansthatyourtransactionhasnot
beenpickedupyet.Waitalittlebitmore.Ifitstillhasn't,checkifyouareconnectedtothenetwork
net.peerCount
Youcanalsotakealooktoseeifyourtransactionisonthelistofpendingtransactionswaitingto
bepickedup:
eth.pendingTransactions()
Ifyouhavemorethan0peersandittakesmorethanaminuteortwoforyourtransactiontobe
mined,yourgaspricemighthavebeentoolow.Gobacktothatcommandaboveandtryplaying
aroundwiththegaspriceorgasamount.Gotooupandyoumightreach
gaslimitoftheblock
,go
toolowandthepricemightbetoolow,orthegasinsufficientforthetransactiontobepickedup.
Afteryourcodehasbeenaccepted,
eth.getCode(codeAddress)
willreturnalongstringof
numbers.Ifthatsthecase,congratulations,yourlittleGreeterislive!Ifthecontractiscreated
again(byperforminganothereth.sendTransaction),itwillbepublishedtoanewaddress.
Nowthatyourcontractisliveonthenetwork,anyonecaninteractwithitbyinstantiatingalocal
copy.Butinordertodothat,yourcomputerneedstoknowhowtointeractwithit,whichiswhatthe
ApplicationBinaryInterface
(ABI)isfor.TogenerateacontractfromABIyouhavetodothis:
greeterContract=
eth.contract(greeterCompiled.greeter.info.abiDefinition)
Tip:
ifthesoliditycompilerisn'tproperlyinstalledinyourmachine,youcangettheABIfromthe
onlinecompiler
.Todoso,usethecodebelowcarefullyreplacing
greeterCompiled.greeter.info.abiDefinition
withtheabifromyourcompiler.
Afterhavingcreatedalocalcopyoftheobject,thisishowyouactuallyinstantiatethatobjectfroma
livecontractaddress:
greeterInstance=greeterContract.at(greeterAddress)
Alternatively,thosetwolinescouldbewrittentogetherinasinglecall:
greeterInstance=
eth.contract(greeterCompiled.greeter.info.abiDefinition).at(greeterAddres
s)
Yourinstanceisready.Inordertocallit,justtypethefollowingcommandinyourterminal:
greeterInstance.greet.call("")
IfyourgreeterreturnedHelloWorldthencongratulations,youjustcreatedyourfirstdigital
conversationalistbot!Tryagainwith:
greeterInstance.greet.call("hi")
Cleaningupafteryourself:
Youmustbeveryexcitedtohaveyourfirstcontractlive,butthis
excitementwearsoffsometimes,whentheownersgoontowritefurthercontracts,leadingtothe
unpleasantsightofabandonedcontractsontheblockchain.Inthefuture,blockchainrentmightbe
implementedinordertoincreasethescalabilityoftheblockchainbutfornow,beagoodcitizenand
humanelyputdownyourabandonedbots.Thesuicideissubsidizedbythecontractcreationsoit
willcostmuchlessthanausualtransaction.
greeterInstance.kill.sendTransaction({from:eth.accounts[0],gasPrice:
web3.toWei(0.001,"finney")})
Noticethateverycontracthastoimplementit'sown
killclause
.Inthisparticularcaseonlythe
accountthatcreatedthecontractcankillit.Ifyoudon'taddanykillclauseitcouldpotentiallylive
forever(oratleastuntilthefrontiercontractsareallwiped)independentlyofyouandanyearthly
borders,sobeforeyouputitlivecheckwhatyourlocallawssayaboutit,includinganypossible
limitationontechnologyexport,restrictionsonspeechandmaybefuturelegislationoncivilrightsof
sentientdigitalbeings.
Tryityourself:
Youcanexperimentchangingitsparameterstomakeitsmarter.Challenge
yourselftohaveitchargeetherforitsprofoundadvicebyaddingthefollowingfunctiononthe
"greet".Here'sasimpleexampleonhowtomakethegreeterintoajokerbymakingitselljokes*:
if(input=="Who'sthere?"){
/*insertajokehere*/
}elseif(msg.value>1000){
/*atrillionthofanether.It'sacheapjoke.*/
return"Knockknock!"
}
Anybalanceyourgreeterisabletomakewillbeforwardedtoyouonthekillcall.
*Actuallytheblockchainisopensourceandanyonecouldreadyourjokeforfree,buthasanyoneeverlaughedbyreading
sourcecode?
Testitwithothers:
anyoneelserunningthegethconsolecaninteractwithyourcontractbyfirst
instantiatingitusingthislineofcode:
greeterInstance=
eth.contract([{constant:false,inputs:[],name:'kill',outputs:[],type:'func
tion'},{constant:false,inputs:[{name:'input',type:'bytes32'}],name:'greet
',outputs:[{name:'',type:'bytes32'}],type:'function'},{inputs:[],type:'co
nstructor'}]).at(greeterAddress)
Nowlet'screateacoinforyourcountry.Coinsaremuchmoreinterestingandusefulthanthey
seem,theyareinessencejustatradeabletoken,butcanbecomemuchmore,dependingonhow
youusethem.It'svaluedependsonit'suse:atokencanbeusedtocontrolaccess(anentrance
ticket),canbeusedforvotingrightsinanorganization(ashare),canbeplaceholdersforanasset
heldbyathirdparty(acertificateofownership)orevenbesimplyusedasanexchangeofvalue
withinacommunity(acurrency).
Youcoulddoallthosethingsbycreatingacentralizedserver,butusinganEthereumtoken
contractcomeswithsomefreequalities:forone,it'sadecentralizedserviceandtokenscanbestill
exchangedeveniftheoriginalservicegoesdownforanyreason.Thecodeguaranteesthatno
tokenswilleverbecreatedotherthantheonessetintheoriginalcode.Finally,byhavingeachuser
holdit'sowntoken,thiseliminatesthescenarioswhereonesingleserverbreakincanresultinthe
lossoffundsfromthousandsofclients.
Thisisthecodeforthecontractwe'rebuilding:
contracttoken{
mapping(address=>uint)publicbalance
/*Initializescontractwith10000tokenstothecreatorofthecontract*/
functiontoken(){
balance[msg.sender]=10000
}
/*Verysimpletradefunction*/
functionsendToken(addressreceiver,uintamount)returns(boolsufficient){
if(balance[msg.sender]<amount)returnfalse
balance[msg.sender]=amount
balance[receiver]+=amount
returntrue
}
Ifyouhaveeverprogrammed,youwon'tfindithardtounderstandwhatitdoes:it'sacontractthat
generates10thousandtokenstothecreatorofthecontract,andthenallowsanyonewithabalance
tosendittoothers.Thesetokensaretheminimumtradeableunitandcannotbesubdivided,butfor
thefinaluserscouldbepresentedasa100unitssubdividableby100subunits,soowningasingle
tokenwouldrepresenthaving0.01%ofthetotal.Ifyourapplicationneedsmorefinegrainatomic
divisibility,thenjustincreasetheinitialissuanceamount.
Inthisexamplewedeclaredthevariable"balance"tobepublic,thiswillautomaticallycreatea
functionthatchecksanyaccountsbalance.
Solet'srunit!
vartokenSource='contracttoken{mapping(address=>uint)public
balance/*Initializescontractwith10000tokenstothecreatorofthe
contract*/functiontoken(){balance[msg.sender]=10000}/*Very
simpletradefunction*/functionsendToken(addressreceiver,uint
amount)returns(boolsufficient){if(balance[msg.sender]<amount)
returnfalsebalance[msg.sender]=amountbalance[receiver]+=amount
returntrue}}'
Nowletssetupthecontract,justlikewedidintheprevioussection..
vartokenCompiled=eth.compile.solidity(tokenSource)
vartokenAddress=eth.sendTransaction({data:tokenCompiled.token.code,
from:eth.accounts[0],gas:1000000,gasPrice:web3.toWei(0.001,
"finney")})
Waitminuteuntilandusethecodebelowtotestifyourcodehasbeendeployed.
eth.getCode(tokenAddress)
Andthen
tokenInstance=
eth.contract(tokenCompiled.token.info.abiDefinition).at(tokenAddress)
Youcancheckyourownbalancewith:
tokenInstance.balance.call(eth.accounts[0])
Itshouldhaveallthe10000tokensthatwerecreatedoncethecontractwaspublished.Sincethere
isnotanyotherdefinedwayfornewcoinstobeissued,thoseareallthatwilleverexist.
Nowofcoursethosetokensaren'tveryusefulifyouhoardthemall,soinordertosendthemto
someoneelse,usethiscommand:
tokenInstance.sendToken.sendTransaction(eth.accounts[1],1000,{from:
eth.accounts[0]})
Ifafriendhasregisteredanameontheregistraryoucansenditwithoutknowingtheiraddress,
doingthis:
tokenInstance.sendToken.sendTransaction(registrar.addr("Alice"),2000,
{from:eth.accounts[0]})
Thereasonthatthefirstcommandwas.call()andthesecondisa.sendTransaction()isthatthe
formerisjustareadoperationandthelatterisusinggastochangethestateoftheblockchain,and
assuch,itneedstobesetwhoisitcomingfrom.Now,waitaminuteandcheckbothaccounts
balances:
tokenInstance.balance.call(eth.accounts[0])
tokenInstance.balance.call(eth.accounts[1])
tokenInstance.balance.call(registrar.addr("Alice"))
Tryforyourself:
Youjustcreatedyourowncryptocurrency!Rightnowthiscryptocurrencyisquite
limitedastherewillonlyeverbe10,000coinsandallarecontrolledbythecoincreator,butyoucan
changethat.Youcouldforexamplerewardethereumminers,bycreatingatransactionthatwill
rewardwhofoundthecurrentblock:
mapping(uint=>address)miningReward
functionclaimMiningReward(){
if(miningReward[block.number]==0){
balances[block.coinbase]+=1
miningReward[block.number]=block.coinbase
}
}
Youcouldmodifythistoanythingelse:mayberewardsomeonewhofindsasolutionforanew
puzzle,winsagameofchess,installasolarpanelaslongasthatcanbesomehowtranslatedto
acontract.Ormaybeyouwanttocreateacentralbankforyourpersonalcountry,soyoucankeep
trackofhoursworked,favorsowedorcontrolofproperty.Inthatcaseyoumightwanttoadda
functiontoallowthebanktoremotelyfreezefundsanddestroytokensifneeded.
Gettingotherstointeractwithyourcontract
ThecommandsmentionedonlyworkbecauseyouhavetokenInstanceinstantiatedonyourlocal
machine.Ifyousendtokenstosomeonetheywon'tbeabletomovethemforwardbecausethey
don'thavethesameobject.Infactifyourestartyourconsoletheseobjectswillbedeletedandthe
contractsyou'vebeenworkingonwillbelostforever.Sohowdoyouinstantiatethecontractona
cleanmachine?
Therearetwoways.Let'sstartwiththequickanddirty,providingyourfriendswithareferenceto
yourcontractsABI:
tokenInstance=
eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{n
ame:'amount',type:'uint256'}],name:'sendToken',outputs:[{name:'sufficient
',type:'bool'}],type:'function'},{type:'function',constant:true,inputs:[{
name:'',type:'address'}],name:'balance',outputs:[{name:'',type:'uint256'}
]},{inputs:[],type:'constructor'}]).at('0x4a4ce7844735c4b6fc66392b200ab6f
e007cfca8')
Justreplacetheaddressattheendforyourowntokenaddress,thenanyonethatusesthissnippet
willimmediatelybeabletouseyourcontract.Ofcoursethiswillworkonlyforthisspecificcontract
solet'sanalyzestepbystepandseehowtoimprovethiscodesoyou'llbeabletouseitanywhere.
First,ifyouregisteraname,thenyouwon'tneedthehardcodedaddressintheend.Selectanice
coinnameforyouandtrytoreserveforyourself.
vartokenName="MyFirstCoin"
registrar.reserve.sendTransaction(tokenName,{from:eth.accounts[0]})
Waitfortheprevioustransactiontobepickedupandthensetthatnametopointtoyourcoin
address:
registrar.setAddress.sendTransaction(tokenName,tokenAddress,true,{from:
eth.accounts[0]})
Waitalittlebitforthattransactiontobepickeduptooandtestit:
registrar.addr("MyFirstCoin")
Thisshouldnowreturnyourtokenaddress,meaningthatnowthepreviouscodetoinstantiate
coulduseanameinsteadofanaddress.
tokenInstance=
eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{n
ame:'amount',type:'uint256'}],name:'sendToken',outputs:[{name:'sufficient
',type:'bool'}],type:'function'},{type:'function',constant:true,inputs:[{
name:'',type:'address'}],name:'balance',outputs:[{name:'',type:'uint256'}
]},{inputs:[],type:'constructor'}]).at(registrar.addr("MyFirstCoin"))
Thisalsomeansthattheownerofthecoincanupdatethecoinbypointingtheregistrartothenew
contract.Thiswould,ofcourse,requirethecoinholderstrusttheownersetat
registrar.owner("MyFirstCoin")
Thecodeisstilllongandnotveryfriendly,andthat'smostlybecauseoftheABIthatusesmostof
thecontractcodespace.Ideallytheonlythingtheusershouldneedtoknowtoaccessthecontract
wouldbeit'sname.Inordertodothatwehavetoregistertheabisomewherealso,whichwhatthe
ContractMetadataRegistry
isfor.
Toinitiatetheprocess,executethis:
admin.contractInfo.newRegistry(eth.accounts[0])
InthefutureEthereumwillhavesupportforapurehashbasedcontentsystemtoallowanydatato
besavedintheP2Pnetwork,butfornowwe'llhavetocreatesomefilesanduploadthem
manually.Firstcreateafileonyoursystem(e.g.inyourdesktop,ifyou'remessylikeme)andadd
itspathlikethis:
varlocalFilePath='/Users/yourusername/Desktop/abi.json'
Nowusethislinetowritetothatfileandsaveitshash:
contentHash=admin.contractInfo.register(eth.accounts[0],tokenAddress,
tokenCompiled.token,localFilePath)
Younowhavetoputthe.jsonfileyoujustcreatedsomewherepubliclyaccessible.Ifyouhavean
httpserveryoucanjustdragintoit,butyoucanalsouseaservicelike
PasteBin
or
Gist
.Createa
newunlisted/privatefile,copythecontentfromthefileyoujustcreatedandsaveit.Thenclickthe
"raw"linkandgetthelinklikethis:
varremoteFilePath=
'https://gist.githubusercontent.com/alexvandesande/ee0d34f5ac47937b6330/r
aw/6813c4e5eee9af33a1728565141ca4572530ffcd/abi.json'
NowfinallyyoucanregistertheABIwith:
admin.contractInfo.registerUrl(eth.accounts[0],contentHash,
remoteFilePath)
Waitfortheminerstopickitupandcheckifeverythingwentwellwith:
admin.contractInfo.get(registrar.addr(tokenName)).AbiDefinition
ThisshouldreturntheABI.Ifitdoesn't,thendoublechecktheprocessandmaybetryuploading
yourfiletoadifferenthost.Nowinordertoinstantiatethecontractinanycomputerallonehasto
knowiseitheritsaddressorregisteredname.
vartokenAddress=registrar.addr("MyFirstCoin")
vartokenInstance=
eth.contract(admin.contractInfo.get(tokenAddress).AbiDefinition).at(token
Address)
Futureimprovements,notyetimplemented:
Formalproofing
isawaywherethecontractdeveloperwillbeabletoassertsome
invariantqualitiesofthecontract,likethetotalcapofthecoin.
Metacoinstandard
isaproposedstandardizationoffunctionnamesforcoinandtoken
contracts,toallowthemtobeautomaticallyaddedtootherethereumcontractthatutilizes
trading,likeexchangesorescrow.
Sinceyoualreadyhaveyourowninternalcurrency,youcanusethattohelpgatherfunds.Inthis
crowdsalecontracteveryonewhocontributewillalsogetaproportionalamountofthetokensyou
created.Thiscanbeusedtoasaproofofcitizenship,asasharesystemorsimplyasarewardfor
theirhelpasearlypioneers.
Attention:AllcontractscouldbewipedoutattheendofFrontier.Whilebalancesonnormal
addresseswillbetransportedtoHomestead,balancesincontracts,aswellasaddresses
withlessthan1ether,willnot.Sousethiscrowdfundingcontractfortestingpurposesand
don'tputanysignificantfundsunlessyouknowwhatyouaredoing.
contracttoken{
functionsendToken(addressreceiver,uint256amount)returns(boolsufficient){}
functiongetBalance(addressaccount)returns(uint256balance){}
contractCrowdSale{
addresspublicadmin
addresspublicbeneficiary
uintpublicfundingGoal
uintpublicnumFunders
uintpublicamountRaised
uintpublicdeadline
uintpublicprice
tokenpublictokenReward
mapping(uint=>Funder)publicfunders
/*datastructuretoholdinformationaboutcampaigncontributors*/
structFunder{
addressaddr
uintamount
}
/*atinitialization,setuptheowner*/
functionCrowdSale(){
admin=msg.sender
}
functionsetup(address_beneficiary,uint_fundingGoal,uint_deadline,uint_price,address
_reward)returns(bytes32response){
if(msg.sender==admin&&!(beneficiary>0&&fundingGoal>0&&deadline>0)){
beneficiary=_beneficiary
fundingGoal=_fundingGoal
deadline=_deadline
price=_price
tokenReward=token(_reward)
return"campaignisset"
}elseif(msg.sender!=admin){
return"notauthorized"
}else{
return"campaigncannotbechanged"
}
}
/*Thefunctionwithoutnameisthedefaultfunctionthatiscalledwheneveranyonesendsfunds
toacntract*/
function()returns(bytes32response){
Funderf=funders[numFunders++]
f.addr=msg.sender
f.amount=msg.value
amount+=f.amount
tokenReward.sendToken(msg.sender,f.amount/price)
return"thanksforyourcontribution"
}
/*checksifthegoalortimelimithasbeenreachedandendsthecampaign*/
functioncheckGoalReached()returns(bytes32response){
if(amountRaised>=fundingGoal){
uinti=0
beneficiary.send(amount)
suicide(beneficiary)
return"GoalReached!"
}
elseif(deadline<=block.number){
uintj=0
uintn=numFunders
while(j<=n){
funders[j].addr.send(funders[j].amount)
funders[j].addr=0
funders[j].amount=0
j++
}
suicide(beneficiary)
return"Deadlinepassed"
}
return"Notreachedyet"
}
}
Youknowthedrill.
Removelinebreaks
andcopythefollowingcommandsontheterminal:
varcrowdsaleSource='contracttoken{functionsendToken(address
receiver,uint256amount)returns(boolsufficient){}function
getBalance(addressaccount)returns(uint256balance){}}contract
CrowdSale{addresspublicadminaddresspublicbeneficiaryuintpublic
fundingGoaluintpublicnumFundersuintpublicamountRaiseduint
publicdeadlineuintpublicpricetokenpublictokenRewardmapping
(uint=>Funder)publicfunders/*datastructuretoholdinformation
aboutcampaigncontributors*/structFunder{addressaddruintamount
}/*atinitialization,setuptheowner*/functionCrowdSale(){admin=
msg.sender}functionsetup(address_beneficiary,uint_fundingGoal,
uint_deadline,uint_price,address_reward)returns(bytes32response){
if(msg.sender==admin&&!(beneficiary>0&&fundingGoal>0&&
deadline>0)){beneficiary=_beneficiaryfundingGoal=_fundingGoal
deadline=_deadlineprice=_pricetokenReward=token(_reward)
return"campaignisset"}elseif(msg.sender!=admin){return"not
authorized"}else{return"campaigncannotbechanged"}}/*The
functionwithoutnameisthedefaultfunctionthatiscalledwhenever
anyonesendsfundstoacntract*/function()returns(bytes32response)
{Funderf=funders[numFunders++]f.addr=msg.senderf.amount=
msg.valueamount+=f.amounttokenReward.sendToken(msg.sender,
f.amount/price)return"thanksforyourcontribution"}/*checksif
thegoalortimelimithasbeenreachedandendsthecampaign*/function
checkGoalReached()returns(bytes32response){if(amountRaised>=
fundingGoal){uinti=0beneficiary.send(amount)suicide(beneficiary)
return"GoalReached!"}elseif(deadline<=block.number){uintj=0
uintn=numFunderswhile(j<=n){
funders[j].addr.send(funders[j].amount)funders[j].addr=0
funders[j].amount=0j++}suicide(beneficiary)return"Deadline
passed"}return"Notreachedyet"}}'
varcrowdsaleCompiled=eth.compile.solidity(crowdsaleSource)
varcrowdsaleAddress=eth.sendTransaction({data:
crowdsaleCompiled.CrowdSale.code,from:eth.accounts[0],gas:1000000,
gasPrice:web3.toWei(0.001,"finney")})
Waitminuteuntilandusethecodebelowtotestifyourcodehasbeendeployed.
eth.getCode(crowdsaleAddress)
Ifithas,thendothesecommandstoinstantiateitlocally.
crowdsaleInstance=
web3.eth.contract(crowdsaleCompiled.CrowdSale.info.abiDefinition).at(crow
dsaleAddress)
Yourfirststepnowistosetthecontractup.Youcanonlydoitonceanditneedstocomefromthe
sameaccountthatcreatedthecontractinthefirstplace.
varbeneficiary=eth.accounts[1] //createanaccountforthis
varfundingGoal=web3.toWei(100,"ether")//raisesa100ether
vardeadline=eth.blockNumber+200000//aboutfourweeks
varprice=web3.toWei(0.02,"ether")//thepriceofthetokens,in
ether
varreward=registrar.addr("MyFirstCoin")
//thetokencontract
address.
OnBeneficiaryputthenewaddressthatwillreceivetheraisedfunds.Thefundinggoalisthe
amountofethertoberaised.Deadlineismeasuredinblocktimeswhichaverage12seconds,so
thedefaultisabout4weeks.Thepriceistricky:butjustchangethenumber2fortheamountof
tokensthecontributorswillreceiveforeachetherdonated.Finallyrewardshouldbetheaddressof
thetokencontractyoucreatedinthelastsection.
Inthisexampleyouaresendingtothecrowdsalefund50%ofallthetokensthateverexisted,in
exchangefor100ether.Decidethoseparametersverycarefullyastheywillplayaveryimportant
roleonthenextpartofourguide.
crowdsaleInstance.setup.sendTransaction(beneficiary,fundingGoal,deadline,price,reward,{from:
eth.accounts[0],gas:150000,gasPrice:web3.toWei(0.001,"finney")})
Dontforgettofundyournewlycreatedcontractwiththenecessarytokenssoitcanpaybackthe
contributors!
tokenInstance.sendToken.sendTransaction(crowdsaleAddress,5000,{from:eth.accounts[0]})
Afterthetransactionispicked,youcanchecktheamountoftokensthecrowdsaleaddresshas,
andallothervariablesthisway:
tokenInstance.balance.call(crowdsaleAddress)
crowdsaleInstance.beneficiary.call()
crowdsaleInstance.amountRaised.call()
crowdsaleInstance.fundingGoal.call()
Youarenowset.Anyonecannowcontributebyfollowingthesesteps.First,sendthemthecode
addressyoujustcreated.Nowanyonecansimplyfollowthesesteps:
crowdsaleInstance=
eth.contract([{inputs:[],name:'checkGoalReached',outputs:[{name:'response',type:'bytes32'}],type:'f
unction',constant:false},{inputs:[],name:'deadline',outputs:[{name:'',type:'uint256'}],type:'functi
on',constant:true},{inputs:[],name:'beneficiary',outputs:[{name:'',type:'address'}],type:'function'
,constant:true},{outputs:[{name:'response',type:'bytes32'}],type:'function',constant:false,inputs:[
{name:'_beneficiary',type:'address'},{name:'_fundingGoal',type:'uint256'},{name:'_deadline',type:'u
int256'},{name:'_price',type:'uint256'},{name:'_reward',type:'address'}],name:'setup'},{constant:tr
ue,inputs:[],name:'tokenReward',outputs:[{name:'',type:'address'}],type:'function'},{constant:true,
inputs:[],name:'fundingGoal',outputs:[{type:'uint256',name:''}],type:'function'},{inputs:[],name:'p
rice',outputs:[{type:'uint256',name:''}],type:'function',constant:true},{constant:true,inputs:[],na
me:'amountRaised',outputs:[{name:'',type:'uint256'}],type:'function'},{constant:true,inputs:[],name
:'numFunders',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'',type:'uint256'}
],name:'funders',outputs:[{name:'addr',type:'address'},{name:'amount',type:'uint256'}],type:'functi
on',constant:true},{inputs:[],name:'admin',outputs:[{name:'',type:'address'}],type:'function',const
ant:true},{inputs:[],type:'constructor'}]).at(crowdsaleAddress)
var
crowdsaleAddress="0x000000"//important,addheretheaddressofyour
varamount=web3.toWei(4,"ether")//decidehowmuchtocontribute
eth.sendTransaction({from:eth.accounts[0],to:crowdsaleAddress,value:
amount,gas:1000000,gasPrice:web3.toWei(0.001,"finney")})
crowdsaleInstance.sendTransaction({from:eth.accounts[0],value:amount,
gas:1000000,gasPrice:web3.toWei(0.001,"finney")})
Nowwaitaminutefortheblockstopickupandyoucancheckifthecontractreceivedtheetherby
doingthis:
eth.getBalance(crowdsaleAddress)
Ifthebalancehaschanged,usenowthistocheckifyoureceivedtokens
tokenInstance.balance.call(eth.accounts[0])
Oncethedeadlineispassedsomeonehastowakeupthecontracttohavethefundssenttoeither
thebeneficiaryorbacktothefunders(ifitfailed).Thishappensbecausethereisnosuchthingas
anactivelooportimeronethereumsoanyfuturetransactionsmustbepingedbysomeone.
crowdsaleInstance.checkGoalReached.sendTransaction({from:eth.accounts[1],
gas:1000000,gasPrice:web3.toWei(0.001,"finney")})
Registeringyourcontract
Inorderforyourcontracttobeaccessiblebyotherpeopleyouhavetodoabitmorework.First,
pickanameforyourcrowdsale:
varname="mycrowdsale"
Checkifthat'savailableandregister:
registrar.addr(name)
registrar.reserve.sendTransaction(name,{from:eth.accounts[0]})
Waitfortheprevioustransactiontobepickedupandthen:
registrar.setAddress.sendTransaction(name,crowdsaleAddress,true,{from:
eth.accounts[0]})
Anyonecanaccessthecrowdsaleby:
crowdsaleInstance=
eth.contract([{constant:false,inputs:[],name:'checkGoalReached',outputs:[
{name:'response',type:'bytes32'}],type:'function'},{constant:false,inputs
:[{name:'_beneficiary',type:'address'},{name:'_fundingGoal',type:'uint256
'},{type:'uint256',name:'_deadline'},{name:'_price',type:'uint256'},{name
:'_reward',type:'address'}],name:'setup',outputs:[{name:'response',type:'
bytes32'}],type:'function'},{type:'function',constant:false,inputs:[],nam
e:'contribute',outputs:[{name:'response',type:'bytes32'}]},{inputs:[],typ
e:'constructor'}]).at(registrar.addr('mycrowdsale')
OptionallyyoucanmakethisshorterbysavingtheABIonaURL.Createablankfilecalledabi.json
inyourdesktopandthenexecutethis:
admin.contractInfo.newRegistry(eth.accounts[0])
contentHash=admin.contractInfo.register(eth.accounts[0],
crowdsaleAddress,crowdsaleCompiled.CrowdSale,
'/Users/yourusername/Desktop/abi.json')
Uploadthefiletoaserverorsimplypastethecontenton
PasteBin
or
Gist
.Createanew
unlisted/privatefile,copythecontentfromthefileyoujustcreatedandsaveit.Click"raw"andput
thelinkonthisnextcommand:
admin.contractInfo.registerUrl(eth.accounts[0],contentHash,
'https://YOURADDRESS/abi.json')
Waitfortheminerstopickitupandcheckifeverythingwentwellwith:
admin.contractInfo.get(registrar.addr(name))
Ifthisdoesn'treturnanerror,thenit'sready.Nowinordertoinstantiatethecontractinany
computerallonehastoknowiseitheritsaddressorregisteredname.
vartokenAddress=registrar.addr("MyFirstCoin")
vartokenInstance=
eth.contract(admin.contractInfo.get(tokenAddress).AbiDefinition).at(token
Address)
ThinkoftheDAOastheconstitutionofyourcountry,theexecutivebranchofit'sgovernmentor
maybelikeacompletelyroboticmiddlemanagerforanorganization.TheDAOreceivesthemoney
thatyourorganizationraisesviaanymeans,keepsitsafeandusesittofundwhateverit'scitizens
want.Therobotisincorruptible,itwillneverdefraudthebank,nevercreatesecretplans,neveruse
themoneyforanythingotherthanwhatit'sconstituentsvotedon.TheDAOwillneverdisappear,
neverrunawayandcannotbecontrolledbyanyoneotherthanit'sowncitizens.
Thetokenwecreatedusingthecrowdsaleistheonlycitizendocumentneeded.Anyonewhoholds
anytokenisabletocreateandvoteonproposals.Similartobeingashareholderinacompany,the
tokencanbetradedontheopenmarketandthevoteisproportionaltoamountsoftokensthevoter
holds.
Takeamomenttodreamabouttherevolutionarypossibilitiesthiswouldallow,andnowyoucando
ityourself,inundera100linesofcode:
contracttoken{functionsendToken(addressreceiver,uint256amount)returns(boolsufficient){}
functiongetBalance(addressaccount)returns(uint256balance){}}
contractDemocracy{
uintconstantminimumQuorum=100
uintconstantdebatingPeriod=7days
tokenvoterShare
uintnumProposals=0
addressfounder
mapping(uint=>Proposal)proposals
structProposal{
addressrecipient
uintamount
bytes32descriptionHash
uintcreationDate
uintnumVotes
uintquorum
boolactive
mapping(uint=>Vote)votes
mapping(address=>bool)voted
}
structVote{
intposition
addressvoter
}
functionDemocracy(){
founder=msg.sender
}
functionsetup(address_voterShareAddress){
if(msg.sender==founder&&numProposals==0){
voterShare=token(_voterShareAddress)
}
functionnewProposal(address_recipient,uint_amount,bytes32_descriptionHash)returns
(uintproposalID){
if(voterShare.getBalance(msg.sender)>0){
proposalID=numProposals++
Proposalp=proposals[proposalID]
p.recipient=_recipient
p.amount=_amount
p.descriptionHash=_descriptionHash
p.creationDate=now
p.numVotes=0
p.active=true
}else{
return0
}
}
functiongetProposalsCount()returns(uintcount){
returnnumProposals
}
functiongetProposalRecipient(uint_proposalID)returns(addressrecipient){
returnproposals[_proposalID].recipient
}
functiongetProposalAmount(uint_proposalID)returns(uintamount){
returnproposals[_proposalID].amount
}
functionvote(uint_proposalID,int_position)returns(uintvoteID){
if(voterShare.getBalance(msg.sender)>0&&(_position>=1||_position<=1)){
Proposalp=proposals[_proposalID]
if(!p.voted[msg.sender]){
voteID=p.numVotes++
Votev=p.votes[voteID]
v.position=_position
v.voter=msg.sender
p.voted[msg.sender]=true
}
}else{
return0
}
}
functionexecuteProposal(uint_proposalID)returns(uintresult){
Proposalp=proposals[_proposalID]
//Checkifdebatingperiodisover
if(now>p.creationDate+debatingPeriod&&p.active){
uintyea=0
uintnay=0
//tallythevotes
for(uinti=0i<=p.numVotesi++){
Votev=p.votes[i]
uintvoteWeight=voterShare.getBalance(v.voter)
p.quorum+=voteWeight
if(v.position>0){
yea+=voteWeight
}if(v.position<0){
nay+=voteWeight
}
}
//executeresult
if(p.quorum>minimumQuorum&&yea>nay){
p.recipient.send(p.amount)
p.active=false
}elseif(p.quorum>minimumQuorum&&nay>yea){
p.active=false
}
returnyeanay
}
}
}
There'salotofgoingonbutifyouhaveeverreadanykindofcodethisoneshouldbeeasily
understandable.Therulesofyourcountryareverysimple:anyonewithatleastonetokencan
createproposalstosendfundsfromthecountry'saccount.Afteraweekofdebateandvotes,ifit
hasreceivedvotestotallyatleast100tokensandhasmoreapprovalsthanrejections,thefunds
willbesent.Ifthequorumhasn'tbeenmetoritendsonatie,thenvotingiskeptuntilit'sresolved.
Otherwise,theproposalislockedandkeptforhistoricalpurposes.
Solet'srecapwhatthismeans:inthelasttwosectionsyoucreated10,000tokens,sent1,000of
thosetoanotheraccountyoucontrol,2,000toafriendnamedAliceanddistributed5,000ofthem
viaacrowdsale.Thismeansthatyounolongercontrolover50%ofthevotesintheDAO,andif
Aliceandthecommunitybandstogether,theycanoutvoteanyspendingdecisiononthe100ethers
raisedsofar.Thisisexactlyhowademocracyshouldwork.Ifyoudon'twanttobeapartofyour
countryanymoretheonlythingyoucandoissellyourowntokensonadecentralizedexchange
andoptout,butyoucannotpreventtheothersfromdoingso.
Soopenyourconsoleandlet'sgetreadytofinallyputyourcountryonline:
vardaoSource='contracttoken{functionsendToken(address
receiver,uint256amount)returns(boolsufficient){}function
getBalance(addressaccount)returns(uint256balance){}}contract
Democracy{uintconstantminimumQuorum=100uintconstant
debatingPeriod=7daystokenvoterShareuintnumProposals=0address
foundermapping(uint=>Proposal)proposalsstructProposal{address
recipientuintamountbytes32descriptionHashuintcreationDateuint
numVotesuintquorumboolactivemapping(uint=>Vote)votesmapping
(address=>bool)voted}structVote{intpositionaddressvoter}
functionDemocracy(){founder=msg.sender}functionsetup(address
_voterShareAddress){if(msg.sender==founder&&numProposals==0){
voterShare=token(_voterShareAddress)}}functionnewProposal(address
_recipient,uint_amount,bytes32_descriptionHash)returns(uint
proposalID){if(voterShare.getBalance(msg.sender)>0){proposalID=
numProposals++Proposalp=proposals[proposalID]p.recipient=
_recipientp.amount=_amountp.descriptionHash=_descriptionHash
p.creationDate=nowp.numVotes=0p.active=true}else{return0
}}functiongetProposalsCount()returns(uintcount){return
numProposals}functiongetProposalRecipient(uint_proposalID)returns
(addressrecipient){returnproposals[_proposalID].recipient}function
getProposalAmount(uint_proposalID)returns(uintamount){return
proposals[_proposalID].amount}functionvote(uint_proposalID,int
_position)returns(uintvoteID){if(voterShare.getBalance(msg.sender)>0
&&(_position>=1||_position<=1)){Proposalp=
proposals[_proposalID]if(!p.voted[msg.sender]){voteID=
p.numVotes++Votev=p.votes[voteID]v.position=_positionv.voter=
msg.senderp.voted[msg.sender]=true}}else{return0}}function
executeProposal(uint_proposalID)returns(uintresult){Proposalp=
proposals[_proposalID]if(now>p.creationDate+debatingPeriod&&
p.active){uintyea=0uintnay=0for(uinti=0i<=p.numVotes
i++){Votev=p.votes[i]uintvoteWeight=
voterShare.getBalance(v.voter)p.quorum+=voteWeightif(v.position>
0){yea+=voteWeight}if(v.position<0){nay+=voteWeight}}if
(p.quorum>minimumQuorum&&yea>nay){p.recipient.send(p.amount)
p.active=false}elseif(p.quorum>minimumQuorum&&nay>yea){
p.active=false}returnyeanay}}}'
vardaoCompiled=eth.compile.solidity(daoSource)
vardaoAddress=eth.sendTransaction({data:daoCompiled.Democracy.code,
from:eth.accounts[0],gas:1000000,gasPrice:web3.toWei(0.001,
"finney")})
Waitaminuteuntiltheminerspickitup.Itwillcostyouabout0.6ethersincurrentmarketprice.
Onceit'spickedupit'stimetoinstantiateitandsetitup,bypointingittothecorrectaddressofthe
tokencontractyoucreatedpreviously.Let'salsoregisteranameforyourcontractsoit'seasily
accessible(don'tforgettocheckyournameavailabilitywith
registrar.addr("nameYouWant")
beforereserving!)
varname="MyPersonalCountry"
registrar.reserve.sendTransaction(name,{from:eth.accounts[0]})
vardaoInstance=
eth.contract(daoCompiled.Democracy.info.abiDefinition).at(daoAddress)
daoInstance.setup.sendTransaction(registrar.addr("MyFirstCoin"),{from:eth
.accounts[0]})
daoInstance.getProposalCount.call()
Waitfortheprevioustransactionstobepickedupandthen:
registrar.setAddress.sendTransaction(name,daoAddress,true,{from:
eth.accounts[0]})
IfeverythingissetupthenyourDAOshouldreturnaproposalcountof0,showingithasno
proposalsyet.Whiletheproposalcountis0,thefounderoftheDAOcanchangetheaddressofthe
tokentoanythingitwants.Afteryouaresatisfiedwithwhatyouwant,it'stimetogetallthatether
yougotfromthecrowdfundingandintoyournewcountry:
eth.sendTransaction({from:eth.accounts[1],to:daoAddress,value:
web3.toWei(100,"ether")})
Thisshouldtakeonlyaminuteandyourcountryisreadyforbusiness!Now,asafirstpriority,your
countryneedsaniceflag,butunlessyouareaflagexpert,youhavenoideahowtodothat.For
thesakeofargumentlet'ssayyoufindthatyourfriendBobisagreatflagdesignerwho'swillingto
doitforonly10ethers,soyouwanttoproposetohirehimtodesignaflag.
recipient=registrar.addr("bob")
amount=web3.toWei(10,"ether")
shortNote="FlagDesign"
daoInstance.newProposal.sendTransaction(recipient,amount,shortNote,
{from:eth.accounts[0],gas:1000000,gasPrice:web3.toWei(0.001,
"finney")})
Afteraminute,anyonecanchecktheproposalrecipientandamountbyexecutingthese
commands:
daoInstance.getProposalRecipient.call(0)
daoInstance.getProposalAmount.call(0)
Unlikemostgovernments,yourcountry'sgovernmentiscompletelytransparentandeasily
programmable.Asasmalldemonstrationhere'sasnippetofcodethatgoesthroughallthecurrent
proposalsandprintswhattheyareandforwhom:
functioncheckAllProposals(){
for(i=0i<daoInstance.getProposalsCount.call()i++){
console.log("Proposal#"+i+"
Send"+web3.fromWei(
daoInstance.getProposalAmount.call(i),"ether")+"ethertoaddress"+
daoInstance.getProposalRecipient.call(i))
}
}
checkAllProposals()
Aconcernedcitizencouldeasilywriteabotthatperiodicallypingstheblockchainandthen
publicizesanynewproposalsthatwereputforth,guaranteeingtotaltransparency.
Nowofcourseyouwantotherpeopletobeabletovoteonyourproposals.Youcancheckthe
crowdsaletutorialonthebestwaytoregisteryourcontractappsothatalltheuserneedsisa
name,butfornowlet'susetheeasierversion.Anyoneshouldbeabletoinstantiatealocalcopyof
yourcountryintheircomputerbyusingthisgiantcommand:
daoInstance=
eth.contract([{constant:false,inputs:[{name:'_proposalID',type:'uint256'}
],name:'executeProposal',outputs:[{name:'result',type:'uint256'}],type:'f
unction'},{constant:false,inputs:[{name:'_proposalID',type:'uint256'}],na
me:'getProposalAmount',outputs:[{name:'amount',type:'uint256'}],type:'fun
ction'},{constant:false,inputs:[{name:'_proposalID',type:'uint256'},{name
:'_position',type:'int256'}],name:'vote',outputs:[{name:'voteID',type:'ui
nt256'}],type:'function'},{type:'function',constant:false,inputs:[{name:'
_voterShareAddress',type:'address'}],name:'setup',outputs:[]},{constant:f
alse,inputs:[],name:'getProposalsCount',outputs:[{name:'count',type:'uint
256'}],type:'function'},{inputs:[{name:'_recipient',type:'address'},{name
:'_amount',type:'uint256'},{name:'_descriptionHash',type:'bytes32'}],name
:'newProposal',outputs:[{name:'proposalID',type:'uint256'}],type:'functio
n',constant:false},{type:'function',constant:false,inputs:[{type:'uint256
',name:'_proposalID'}],name:'getProposalRecipient',outputs:[{name:'recipi
ent',type:'address'}]},{type:'constructor',inputs:[]}]).at(registrar.addr
('MyPersonalCountry'))
Thenanyonewhoownsanyofyourtokenscanvoteontheproposalsbydoingthis:
varproposalID=0
varposition=1//+1forvotingyea,1forvotingnay,0abstainsbut
countsasquorum
daoInstance.vote.sendTransaction(proposalID,position,{from:
eth.accounts[0]})
Unlessyouchangedthebasicparametersinthecode,anyproposalwillhavetobedebatedforat
leastaweekuntilitcanbeexecuted.Afterthatanyoneevenanoncitizencandemandthe
votestobecountedandtheproposaltobeexecute.Thevotesaretalliedandweightedatthat
momentandiftheproposalisacceptedthentheetherissentimmediatelyandtheproposal.Ifthe
votesendinatieortheminimumquorumhasntbeenreached,thevotingiskeptopenuntilthe
stalemateisresolved.Ifitloses,thenit'sarchivedandcannotbevotedagain.
varproposalID=0
daoInstance.executeProposal.sendTransaction(proposalID,{from:
eth.accounts[0]})
IftheproposalpassedthenyoushouldbeabletoseeBob'sethersarrivingonhisaddress:
eth.getBalance(registrar.addr("bob"))
Tryforyourself:
Thisisaverysimpledemocracycontract,whichcouldbevastlyimproved:
currently,allproposalshavethesamedebatingtimeandarewonbydirectvoteandsimple
majority.Canyouchangethatsoitwillhavesomesituations,dependingontheamountproposed,
thatthedebatemightbelongerorthatitwouldrequirealargermajority?Alsothinkaboutsome
waywherecitizensdidn'tneedtovoteoneveryissueandcouldtemporarilydelegatetheirvotesto
aspecialrepresentative.Youmighthavealsonoticedthatweaddedatinydescriptionforeach
proposal.Thiscouldbeusedasatitlefortheproposalorcouldbeahashofalargerdocument
describingitindetail.
Let's go exploring!
Youhavereachedtheendofthistutorial,butit'sjustthebeginningofagreatadventure.Lookback
andseehowmuchyouaccomplished:youcreatedaliving,talkingrobot,yourowncryptocurrency,
raisedfundsthroughatrustlesscrowdfundingandusedittokickstartyourownpersonalcountry.
Forthesakeofsimplicity,thesimpledemocraticorganizationyoucreatedcanonlysendether
around,thenativecurrencyofethereum.Whilethatmightbegoodenoughforsome,thisisonly
scratchingthesurfaceofwhatcanbedone.Intheethereumnetworkcontractshaveallthesame
rightsasanynormaluser,meaningthatyourorganizationcouldbeprogrammedinsuchwaythatit
coulddoanyofthetransactionsthatyouexecutedcomingfromyourownaccounts.
Whatcouldhappennext?
Thegreetercontractyoucreatedatthebeginningcouldbeimprovedtochargeetherforits
servicesandcouldfunnelthosefundsintotheDAO.
Thetokensyoustillcontrolcouldbesoldonadecentralizedexchangeortradedforgoods
andservicestofundfurtherdevelopthefirstcontractandgrowtheorganization.
YourDAOcouldownit'sownnameonthenameregistrar,andthenchangewhereit's
redirectinginordertoupdateitselfifthetokenholdersapproved.
Theorganizationcouldholdnotonlyethers,butanykindofothercoincreatedonethereum,
includingassetswhosevaluearetiedtothebitcoinordollar.
TheDAOcouldbeprogrammedtoallowaproposalwithmultipletransactions,some
scheduledtothefuture.
ItcouldalsoownsharesofotherDAO's,meaningitcouldvoteonlargerorganizationorbe
apartofafederationofDAO's
TheTokenContractcouldbereprogrammedtoholdetherortoholdothertokensand
distributeittothetokenholders,linkingthereforethevalueofthetokentothevalueofother
assets,sopayingdividendscouldbeaccomplishedbysimplymovingfundstothetoken
address
Thisallmeansthatthistinysocietyyoucreatedcouldgrow,getfundingfromthirdparties,pay
recurrentsalaries,ownanykindofcryptoassetsandevenusecrowdsalestofunditsactivities.All
withfulltransparency,completeaccountabilityandcompleteimmunityfromanyhuman
interference.Whilethenetworklivesthecontractswillexecuteexactlythecodetheywerecreated
toexecute,withoutanyexception,forever.
Sowhatwillyourcontractbe?Willitbeacountry,acompany,anonprofitgroup?Whatwillyour
codedo?
That'suptoyou.
More stuff to do
Youaccomplishedalottoday,youshouldfeelproud.Butifyouarestillthirstyforknowledge,here
aresomecoolprojectsthatareliveandyoucanparticipatein:
Etherex
Augur
eDollar
Redditflairmanager(suggestion:basiccontractwhereuserscanrequestfrontierflairsin
thesubreddit)
etc..
More references
https://github.com/ethereum/wiki/wiki/SolidityTutorial
https://dappsforbeginners.wordpress.com/tutorials/contractsthatsendtransactions/