avatarKeno Leon

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

16509

Abstract

l machine run on a blockchain, is that state computations on contracts are not immediate, a transaction has to be sent, and then mined.As previously mentioned sent transactions that affect a contract state do not return any values, so we need another way to check when and if a transaction and contracts method returned something.</p><p id="7615">One solution is to watch the blockchain for our contract and then call our contract method when our transaction gets accepted.</p><p id="13b2">This would involve to somehow watch the blockchain from within web3.js/node, luckily this is somehow trivial :</p><div id="4be5"><pre><span class="hljs-comment">// FILE: filterWatch.js</span></pre></div><div id="0b39"><pre>// Watches the blockchain: // filter can be 'latest'<span class="hljs-built_in"> or </span>'pending'<span class="hljs-built_in"> check </span>: // https://ethereum.stackexchange.com/questions/3400/filters-whats-latest-and-pending</pre></div><div id="afdd"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Setting up...'</span>); <span class="hljs-keyword">const</span> solc = <span class="hljs-built_in">require</span>(<span class="hljs-string">'solc'</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Web3</span> = <span class="hljs-built_in">require</span>(<span class="hljs-string">'web3'</span>);</pre></div><div id="4940"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Connecting'</span>); const web3 = <span class="hljs-keyword">new</span> Web3(<span class="hljs-keyword">new</span> Web3.providers.HttpProvider(<span class="hljs-string">"http://localhost:8545"</span>));</pre></div><div id="082c"><pre><span class="hljs-attr">filter</span> = web3.eth.filter(<span class="hljs-string">'latest'</span>)<span class="hljs-comment">; </span></pre></div><div id="27bb"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Watching'</span>); <span class="hljs-built_in">filter</span>.watch(<span class="hljs-keyword">function</span>(<span class="hljs-params">error, result</span>) { <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(result); });</pre></div><p id="f199">Readout:</p><div id="5a2d"><pre>Setting <span class="hljs-meta">up</span>... Connecting Watching <span class="hljs-number">0x3296600010cd439485a254e71cc5b88fcdcf3752858df9161b55eac1586d5e3d</span> <span class="hljs-number">0x2715f22c8b5bc5ebea25d2b76f0ad789eba692591d86d0d786120b2aa8d4b49c</span> <span class="hljs-number">0x0e35d29ed8dcf93c0b7b514b6cc4d9dd181372015346f85d4b680f650a181969</span> .....</pre></div><p id="ca63">We would need to get information from each of the block hashes and query them for transactions until we got to ours, and then call the get() method, while possible, <a href="https://ethereum.stackexchange.com/questions/27376/can-you-filter-and-watch-for-a-contracts-state-changing-method-in-web3-js">the preferred way is via events</a>, which we will briefly cover next. ( <i>you also now know how to watch the blockchain</i> ).</p><h2 id="8168">Contract Events</h2><p id="71f4">In order to use contract events, the first step is to modify our basicStorage contract to log events :</p><div id="434f"><pre><span class="hljs-comment">// FILE : basicStorageEv.sol</span> <span class="hljs-comment">// Thanks to GregJeanmart for the snippet.</span></pre></div><div id="70e1"><pre><span class="hljs-attribute">pragma</span> solidity ^<span class="hljs-number">0</span>.<span class="hljs-number">4</span>.<span class="hljs-number">0</span>;</pre></div><div id="1814"><pre><span class="hljs-attribute">contract</span> basicStorage { <span class="hljs-attribute">uint</span> storedData;</pre></div><div id="373f"><pre> <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">SetEvent</span>(<span class="hljs-params"> address indexed _from, <span class="hljs-built_in">uint</span> _x </span>)</span>;</pre></div><div id="ec5b"><pre> function <span class="hljs-keyword">set</span>(uint <span class="hljs-comment">x) {</span> storedData <span class="hljs-comment">= x</span>;</pre></div><div id="3641"><pre> <span class="hljs-comment">// Log event inside set</span> <span class="hljs-built_in">SetEvent</span>(msg.sender, x); }</pre></div><div id="088e"><pre><span class="hljs-keyword">function</span> <span class="hljs-title">get</span>() constant returns (uint) { <span class="hljs-keyword">return</span> <span class="hljs-type">storedData</span>; } }</pre></div><p id="5539"><b>Compile and Deploy</b> (<i>using compiler.js</i>):</p><div id="5ccc"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Setting up...'</span>); <span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>); <span class="hljs-keyword">const</span> solc = <span class="hljs-built_in">require</span>(<span class="hljs-string">'solc'</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Web3</span> = <span class="hljs-built_in">require</span> (<span class="hljs-string">'web3'</span>); <span class="hljs-keyword">const</span> web3 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Web3</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Web3</span>.<span class="hljs-property">providers</span>.<span class="hljs-title class_">HttpProvider</span>(<span class="hljs-string">"http://localhost:8545"</span>));</pre></div><div id="5df3"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Reading contract Source...'</span>); const input = fs.readFileSync(<span class="hljs-string">'basicStorageEv.sol'</span>);</pre></div><div id="a8cb"><pre>console.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Compiling...'</span>); const <span class="hljs-built_in">output</span> = solc.compile(<span class="hljs-built_in">input</span>.toString(), <span class="hljs-number">1</span>);</pre></div><div id="4d9d"><pre><span class="hljs-keyword">if</span> (output.errors) { console.log(<span class="hljs-string">'Compiling failed with errors:'</span> + output.errors); process.<span class="hljs-keyword">exit</span>(); } const bytecode = output.contracts[<span class="hljs-string">':basicStorageEv'</span>].bytecode; const abi = output.contracts[<span class="hljs-string">':basicStorageEv'</span>].interface;</pre></div><div id="17a8"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'saving ABI'</span>); fs.writeFile(<span class="hljs-string">"./basicStorageEv.json"</span>, abi, <span class="hljs-keyword">function</span>(<span class="hljs-params">err</span>) { <span class="hljs-keyword">if</span> (err) { <span class="hljs-keyword">return</span> <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(err); } <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">"ABI Saved"</span>); });</pre></div><div id="ef1b"><pre><span class="hljs-keyword">const</span> basicStorageEv = web3.eth.<span class="hljs-keyword">contract</span>(JSON.<span class="hljs-keyword">parse</span>(abi));</pre></div><div id="ae3d"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'unlocking Coinbase account'</span>);</pre></div><div id="e1c6"><pre><span class="hljs-keyword">const</span> password = <span class="hljs-string">"your_password"</span>; <span class="hljs-keyword">try</span> { web3.personal.unlockAccount(web3.eth.coinbase, password); } <span class="hljs-keyword">catch</span>(e) { <span class="hljs-function"><span class="hljs-keyword">return</span> console.<span class="hljs-title">log</span><span class="hljs-params">(e)</span></span>; }</pre></div><div id="77cf"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">"Deploying contract..."</span>); const basicStorageEvInstance = basicStorageEv.<span class="hljs-keyword">new</span>({ <span class="hljs-attr">data</span>: <span class="hljs-string">'0x'</span> + bytecode, <span class="hljs-attr">from</span>: web3.eth.coinbase <span class="hljs-comment">// gasPrice: '4000000',</span> <span class="hljs-comment">// gas: 1000000 /</span> }, <span class="hljs-keyword">function</span>(<span class="hljs-params">err, res</span>){ <span class="hljs-keyword">if</span> (err) { <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'there were errors:'</span> + err); } <span class="hljs-keyword">if</span> (res.address) { <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'txHash:'</span> + res.transactionHash); <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Succesfully deployed Contract with address: '</span> + res.address); } });</pre></div><p id="5a41">Readout:</p><div id="118a"><pre><span class="hljs-function"><span class="hljs-title">Setting</span></span> up... <span class="hljs-function"><span class="hljs-title">Reading</span></span> contract Source... <span class="hljs-function"><span class="hljs-title">Compiling</span></span>... saving ABI unlocking Coinbase account <span class="hljs-function"><span class="hljs-title">Deploying</span></span> contract... ABI Saved txHash:<span class="hljs-number">0x344020880f594d9c776b750d84f9d1bec9f1c1d6ff6e66663e99cf3dde73c098</span> Succesfully deployed Contract with address: <span class="hljs-number">0xac88d694726e84ae46e2450cc8e30ea882a0cc43</span></pre></div><p id="768f">And now in order to watch the event we need to subscribe to it like this:</p><div id="777d"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Setting up...'</span>); <span class="hljs-keyword">const</span> solc = <span class="hljs-built_in">require</span> (<span class="hljs-string">'solc'</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Web3</span> = <span class="hljs-built_in">require</span> (<span class="hljs-string">'web3'</span>); <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Reading abi'</span>); <span class="hljs-keyword">const</span> contractABI = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./basicStorageEv.json"</span>);</pre></div><div id="1c6d"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Connecting'</span>); const web3 = <span class="hljs-keyword">new</span> Web3(<span class="hljs-keyword">new</span> Web3.providers.HttpProvider(<span class="hljs-string">"http://localhost:8545"</span>));</pre></div><div id="5938"><pre>console.<span class="hljs-built_in">log</span>('Creating <span class="hljs-built_in">contract</span> instance'); const basicStorageEv = web3.eth.<span class="hljs-built_in">contract</span>(contractABI); <span class="hljs-built_in">var</span> basicStorageEvI = basicStorageEv.<span class="hljs-built_in">at</span>(<span class="hljs-string">"0xac88d694726e84ae46e2450cc8e30ea882a0cc43"</span>);</pre></div><div id="6284"><pre><span class="hljs-keyword">var</span> myEvent = basicStorageEvI.<span class="hljs-title function_ invoke__">SetEvent</span>({}, {<span class="hljs-attr">fromBlock</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">toBlock</span>: <span class="hljs-string">'latest'</span>});</pre></div><div id="2a2d"><pre>console.<span class="hljs-built_in">log</span>(<span class="hljs-string">"Start watching events"</span>); myEvent.watch(function(<span class="hljs-keyword">error</span>, <span class="hljs-literal">result</span>){ <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">error</span>) { console.<span class="hljs-built_in">log</span>(<span class="hljs-literal">result</span>); } <span class="hljs-keyword">else</span> { console.<span class="hljs-built_in">log</span>(<span class="hljs-keyword">error</span>); } });</pre></div><p id="2013">I previously called set 3 times: s<b>et(10)</b>, so I would get this redout:</p><div id="6755"><pre><span class="hljs-symbol">FILE:</span> watchEvents.js</pre></div><div id="8f29"><pre>Setting up... Reading abi Connecting Creating contract instance Start watching events { address: '0xac88d<span class="hljs-number">694726</span>e84ae46e<span class="hljs-number">2450</span>cc8e30ea882a0cc43', blockHash: '0x69ee11dec<span class="hljs-number">312171</span>5a8ec082ca386d4b4d547aa<span class="hljs-number">18473922830716</span>4a105dbb7c24', blockNumber: <span class="hljs-number">4061192</span>, logIndex: <span class="hljs-number">1</span>, transactionHash: '0x4e75edab76bd<span class="hljs-number">8391</span>1caf003e6de<span class="hljs-number">0532</span>4f3f10cc7f<span class="hljs-number">9088</span>6e3d<span class="hljs-number">0112139956</span>bc640', transactionIndex: <span class="hljs-number">1</span>, transactionLogIndex: '0x0', type: 'mined', event: 'SetEvent', args: { _from: '0x<span class="hljs-number">001301</span>ad<span class="hljs-number">1556</span>fd419cf<span class="hljs-number">8970</span>b174fe9af<span class="hljs-number">3426</span>7eb8', _x: { [String: '10'] s: <span class="hljs-number">1</span>, e: <span class="hljs-number">1</span>, c: [Array] } } } { address: '0xac88d<span class="hljs-number">694726</span>e84ae46e<span class="hljs-number">2450</span>cc8e30ea882a0cc43', blockHash: '0x9a09b<span class="hljs-number">292007</span>2fd0eaf4bbc0fe5f38c431b80e747e<span class="hljs-number">8443</span>b4eb<span class="hljs-number">105011</span>4acbc5ddf', blockNumber: <span class="hljs-number">4061200</span>, logIndex: <span class="hljs-number">3</span>, transactionHash: '0xd3eb8d1dd11e6db<span class="hljs-number">6140</span>bb8a<span class="hljs-number">3741889462</span>d7c<span class="hljs-number">4102</span>c2c08eed<span class="hljs-number">405664</span>fa5b30e91b', transactionIndex: <span class="hljs-number">1</span>, transactionLogIndex: '0x0', type: 'mined', event: 'SetEvent', args: { _from: '0x<span class="hljs-number">001301</span>ad<span class="hljs-number">1556</span>fd419cf<span class="hljs-number">8970</span>b174fe9af<span class="hljs-number">3426</span>7eb8', _x: { [String: '10'] s: <span class="hljs-number">1</span>, e: <span class="hljs-number">1</span>, c: [Array] } } } { address: '0xac88d<span class="hljs-number">694726</span>e84ae46e<span class="hljs-number">2450</span>cc8e30ea882a0cc43', blockHash: '0xad9d<span class="hljs-number">8038</span>f8e<span class="hljs-number">033404</span>6fe<span class="hljs-number">530306</span>c980f<span class="hljs-number">773698</span>eae<span class="hljs-number">1873</span>e<span class="hljs-number">224899</span>dce1fe3fbc276', blockNumber: <span class="hljs-number">4061224</span>, logIndex: <span class="hljs-number">3</span>, transactionHash: '0x5c0fa62c3c3b<span class="hljs-number">7015</span>fda363b8d<span class="hljs-number">973708</span>d<span class="hljs-number">7526</span>c998b4fb8ae53cfe7adbd<span class="hljs-number">7612</span>3fe', transactionIndex: <span class="hljs-number">1</span>, transactionLogIndex: '0x0', type: 'mined', event: 'SetEvent', args: { _from: '0x<span class="hljs-number">001301</span>ad<span class="hljs-number">1556</span>fd419cf<span class="hljs-number">8970</span>b174fe9af<span class="hljs-number">3426</span>7eb8', _x: { [String: '10'] s: <span class="hljs-number">1</span>, e: <span class="hljs-number">1</span>, c: [Array] } } }</pre></div><p id="28f5">You can <a href="https://ethereum.stackexchange.com/questions/12950/what-are-event-topics">watch for specific events via topics</a> ( you might need to modify your event emmiter in the contract) and you can get specific information back

Options

via the args variable: (<b><i>result.args._x </i></b><i>in our case</i>):</p><h2 id="d573">GAS :</h2><p id="dd64">So far I’ve been glossing over gas costs in transactions since gas in testnets is basically free, but an important part of deploying contracts succesfuly as well as estimating costs in real money hinges on understanding gas, so let’s see how gas works and how to estimate and adjust it.</p><ul><li><a href="https://ethereum.stackexchange.com/questions/3/what-is-meant-by-the-term-gas"><b>Gas is complex</b></a><b>. </b>In short it is the cost of making operations on ethereums Virtual Machine (VM), and has a price that is somehow independent of Ether,it is set in a sliding scale by miners and varies by operation, there are a thousand analogies out there, but the critical bit is if you don’t get the price and the amount right when deploying and interacting with your contracts, your transactions will fail and you might even loose some ether in the process.</li></ul><p id="43c8">Let’s first fail a transaction:</p><div id="bffa"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Setting up...'</span>); <span class="hljs-keyword">const</span> solc = <span class="hljs-built_in">require</span> (<span class="hljs-string">'solc'</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Web3</span> = <span class="hljs-built_in">require</span> (<span class="hljs-string">'web3'</span>); <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Reading abi'</span>); <span class="hljs-keyword">const</span> contractABI = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./basicStorage.json"</span>);</pre></div><div id="25be"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Connecting'</span>); const web3 = <span class="hljs-keyword">new</span> Web3(<span class="hljs-keyword">new</span> Web3.providers.HttpProvider(<span class="hljs-string">"http://localhost:8545"</span>));</pre></div><div id="9ad4"><pre>console.<span class="hljs-built_in">log</span>('Creating <span class="hljs-built_in">contract</span> instance'); const basicStorage = web3.eth.<span class="hljs-built_in">contract</span>(contractABI); <span class="hljs-built_in">var</span> basicStorageInstance = basicStorage.<span class="hljs-built_in">at</span>(<span class="hljs-string">"0x20ed8cc5c767b100c6a5b018e533e38b44b36326"</span>);</pre></div><div id="6b1d"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'unlocking Coinbase account'</span>); <span class="hljs-keyword">const</span> password = <span class="hljs-string">"your_password"</span>; <span class="hljs-keyword">try</span> { web3.<span class="hljs-property">personal</span>.<span class="hljs-title function_">unlockAccount</span>(web3.<span class="hljs-property">eth</span>.<span class="hljs-property">coinbase</span>, password); } <span class="hljs-keyword">catch</span>(e) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(e); <span class="hljs-keyword">return</span>; }</pre></div><div id="93e8"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span> (<span class="hljs-string">'sending Transaction to the contract'</span>);</pre></div><div id="74b8"><pre>const <span class="hljs-attr">transaction</span> <span class="hljs-operator">=</span> <span class="hljs-punctuation">{</span> <span class="hljs-symbol"> from:</span> web3.eth.coinbase, <span class="hljs-symbol"> gas:</span> <span class="hljs-number">0</span>, <span class="hljs-symbol"> gasPrice:</span> <span class="hljs-number">0</span> <span class="hljs-punctuation">}</span></pre></div><div id="eff4"><pre>basicStorageInstance.set.sendTransaction(<span class="hljs-number">220</span>, transaction, <span class="hljs-keyword">function</span>(<span class="hljs-params">err, txHash</span>) { <span class="hljs-keyword">if</span> (err != <span class="hljs-literal">null</span>) { <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error while sending transaction: "</span> + err); } <span class="hljs-keyword">else</span>{ <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">"Transaction Sent here's you txHash: "</span> + txHash); } });</pre></div><p id="d9be">Readout:</p><div id="c881"><pre>Setting up... Reading abi Connecting Creating contract<span class="hljs-built_in"> instance </span>unlocking Coinbase account sending Transaction to the contract Error while sending transaction: Error: Transaction gas is too low. There is<span class="hljs-built_in"> not </span>enough gas to cover minimal cost of the transaction (minimal: 21464, got: 0). Try increasing supplied gas.</pre></div><p id="ee61"><b>Estimating gas prices:</b></p><p id="b915">The first thing we need to do is estimate gas prices :</p><div id="e1fc"><pre><span class="hljs-built_in">File</span>: estimateGas.js</pre></div><div id="7b51"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Setting up...'</span>); <span class="hljs-keyword">const</span> solc = <span class="hljs-built_in">require</span> (<span class="hljs-string">'solc'</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Web3</span> = <span class="hljs-built_in">require</span> (<span class="hljs-string">'web3'</span>); <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Reading abi'</span>); <span class="hljs-keyword">const</span> contractABI = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./basicStorage.json"</span>);</pre></div><div id="b944"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Connecting'</span>); const web3 = <span class="hljs-keyword">new</span> Web3(<span class="hljs-keyword">new</span> Web3.providers.HttpProvider(<span class="hljs-string">"http://localhost:8545"</span>));</pre></div><div id="ee9d"><pre>console.<span class="hljs-built_in">log</span>('Creating <span class="hljs-built_in">contract</span> instance'); const basicStorage = web3.eth.<span class="hljs-built_in">contract</span>(contractABI); <span class="hljs-built_in">var</span> basicStorageInstance = basicStorage.<span class="hljs-built_in">at</span>(<span class="hljs-string">"0x20ed8cc5c767b100c6a5b018e533e38b44b36326"</span>);</pre></div><div id="8803"><pre>var estimatedTransactionGas <span class="hljs-operator">=</span> basicStorageInstance.set.estimateGas(<span class="hljs-number">220</span>)<span class="hljs-comment">;</span></pre></div><div id="2fd6"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Estimated Transaction Gas:'</span> + estimatedTransactionGas);</pre></div><p id="cc16">Readout:</p><div id="92fe"><pre>Setting up... Reading abi Connecting Creating contract<span class="hljs-built_in"> instance </span>Estimated Transaction Gas:26586</pre></div><p id="d998">As mentioned, the gas price is set by miners resolving blocks; we can get the median gas price ( in wei ) like so:</p><div id="5623"><pre><span class="hljs-keyword">var</span> gasPrice = web3.eth.gasPrice; <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Current Gas price:'</span> + gasPrice.toString(<span class="hljs-number">10</span>));</pre></div><div id="f4c4"><pre><span class="hljs-comment">// Current Gas price:20000000000</span></pre></div><div id="be4c"><pre><span class="hljs-regexp">//</span> See: https:<span class="hljs-regexp">//</span>ethereum.stackexchange.com<span class="hljs-regexp">/questions/</span><span class="hljs-number">27452</span>/how-to-estimate-gas-cost</pre></div><p id="3c6a">Going back to our failed transaction, we can now better estimate our gas requirements and submit them as part of the transaction:</p><div id="1ca8"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Setting up...'</span>); <span class="hljs-keyword">const</span> solc = <span class="hljs-built_in">require</span> (<span class="hljs-string">'solc'</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Web3</span> = <span class="hljs-built_in">require</span> (<span class="hljs-string">'web3'</span>); <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Reading abi'</span>); <span class="hljs-keyword">const</span> contractABI = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./basicStorage.json"</span>);</pre></div><div id="4ac2"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Connecting'</span>); const web3 = <span class="hljs-keyword">new</span> Web3(<span class="hljs-keyword">new</span> Web3.providers.HttpProvider(<span class="hljs-string">"http://localhost:8545"</span>));</pre></div><div id="d23f"><pre>console.<span class="hljs-built_in">log</span>('Creating <span class="hljs-built_in">contract</span> instance'); const basicStorage = web3.eth.<span class="hljs-built_in">contract</span>(contractABI); <span class="hljs-built_in">var</span> basicStorageInstance = basicStorage.<span class="hljs-built_in">at</span>(<span class="hljs-string">"0x20ed8cc5c767b100c6a5b018e533e38b44b36326"</span>);</pre></div><div id="5058"><pre>var estimatedTransactionGas <span class="hljs-operator">=</span> basicStorageInstance.set.estimateGas(<span class="hljs-number">220</span>)<span class="hljs-comment">;</span> var gasPrice <span class="hljs-operator">=</span> web3.eth.gasPrice<span class="hljs-comment">;</span></pre></div><div id="90c2"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Cost estimates: '</span> ); <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'Estimated Transaction gas: '</span> + estimatedTransactionGas ); <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">'gas Price: '</span> + gasPrice);</pre></div><div id="5f5b"><pre><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'unlocking Coinbase account'</span>); <span class="hljs-keyword">const</span> password = <span class="hljs-string">"your_password"</span>; <span class="hljs-keyword">try</span> { web3.<span class="hljs-property">personal</span>.<span class="hljs-title function_">unlockAccount</span>(web3.<span class="hljs-property">eth</span>.<span class="hljs-property">coinbase</span>, password); } <span class="hljs-keyword">catch</span>(e) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(e); <span class="hljs-keyword">return</span>; }</pre></div><div id="91b6"><pre><span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span> (<span class="hljs-string">'sending Transaction to the contract'</span>);</pre></div><div id="8907"><pre>const <span class="hljs-attr">transaction</span> <span class="hljs-operator">=</span> <span class="hljs-punctuation">{</span> <span class="hljs-symbol"> from:</span> web3.eth.coinbase, <span class="hljs-symbol"> gas:</span> estimatedTransactionGas, <span class="hljs-symbol"> gasPrice:</span> gasPrice <span class="hljs-punctuation">}</span></pre></div><div id="732f"><pre>basicStorageInstance.set.sendTransaction(<span class="hljs-number">220</span>, transaction, <span class="hljs-keyword">function</span>(<span class="hljs-params">err, txHash</span>) { <span class="hljs-keyword">if</span> (err != <span class="hljs-literal">null</span>) { <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error while sending transaction: "</span> + err); } <span class="hljs-keyword">else</span>{ <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string">"Transaction Sent here's you txHash: "</span> + txHash); } });</pre></div><p id="1926">And out readout:</p><div id="1b1b"><pre>Setting up... Reading abi Connecting Creating contract<span class="hljs-built_in"> instance </span>Cost estimates: Estimated Transaction gas: 26586 gas Price: 20000000000 (<span class="hljs-built_in"> or </span>20 Gwei<span class="hljs-built_in"> or </span>0.00000002 ether ) unlocking Coinbase account sending Transaction to the contract Transaction Sent here's you txHash: 0x9617338ce298b2da4d4610aeca6324c1c5aa05b21347aac6a572b3b7b9253d3b</pre></div><p id="141a">If we now inspect our txHash, we can get the real costs and compare them:</p><figure id="4a42"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*0RFG4v4NpDLgH4Yr7Af_kA.jpeg"><figcaption></figcaption></figure><div id="d22c"><pre>Note: Gas estimation <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> a perfect science, <span class="hljs-keyword">at</span> least <span class="hljs-keyword">to</span> <span class="hljs-keyword">me</span>,your <span class="hljs-keyword">transaction</span> might still fail due <span class="hljs-keyword">to</span> sudden gas price changes <span class="hljs-keyword">or</span> other network variables, so you might have <span class="hljs-keyword">to</span> increase <span class="hljs-keyword">by</span> a factor both gas price <span class="hljs-keyword">and</span> <span class="hljs-keyword">the</span> gas used <span class="hljs-keyword">if</span> you want <span class="hljs-keyword">to</span> insure your transactions succeed.</pre></div><p id="4fb0">I really wanted to make a token for our next part, but I think it is better to first cover a few other gotchas and features of smart contracts we will be using as to have a better foundation. Recap time:</p><ul><li><a href="https://readmedium.com/ethereum-tokens-smart-contracts-f04cb9bb9431"><b>Notes Part 1 : Setting up </b></a><b>:</b> Getting a wallet/client , connecting to a test ethereum blockchain and getting some test ether.</li><li><a href="https://readmedium.com/ethereum-tokens-smart-contracts-a263b43d4c54"><b>Notes Part 2: web3.js/node</b></a><b> : </b>Interacting with the blockchain through web3.js and node for more convenience and ease of development.</li><li><a href="https://readmedium.com/ethereum-tokens-smart-contracts-3346b62d2a0"><b>Notes Part 3: Solidity</b> </a>: Installing solidity (Ethereums contract writing language ) , Creating a very basic contract, compiling it, deploying it to the blockchain ( the test one) and interacting with it.</li><li><b>Notes Part 4: Smart Contracts </b>( <i>this post </i>) We modified our simple contract so we could store and retrieve information (making it smarter) , in the process we also covered how to watch the blockchain and contracts and finally we took a look at gas and how to estimate it.</li></ul><figure id="cc3e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*mtIpI9lIZdbye5giXJKB5Q.jpeg"><figcaption></figcaption></figure><div id="2e3c"><pre>Want <span class="hljs-keyword">to</span> <span class="hljs-keyword">take</span> these notes offline ?</pre></div><div id="52fb"><pre>If you are looking for an introduction <span class="hljs-selector-tag">to</span> Ethereum, Solidity and Smart Contracts these notes are now available in <span class="hljs-selector-tag">a</span> paper and ebook <span class="hljs-selector-tag">form</span>! ❤️📖❤️</pre></div><div id="66a6"><pre>https:<span class="hljs-regexp">//</span>www.amazon.com<span class="hljs-regexp">/dp/</span>B078CQ8L7V </pre></div><p id="fbfd">Cheers !</p><p id="2735">Keno</p><p id="c98a"><b>About the Author :</b></p><p id="14ec"><i>Born Eugenio Noyola Leon (Keno) I am a Designer,Web Developer/programmer, Artist and Inventor, currently living in Mexico City, you can find me at <a href="http://www.k3no.com">www.k3no.com</a></i></p></article></body>

Ethereum, tokens & smart contracts.

Notes on getting started Part 4. Smart Contracts

Previous notes in case you are just joining us:
Part 1. Setting up.
Part 2. Web3.js/node. 
Part 3. Solidity.

Our hello world contract from the previous notes while awesome, is not particularly smart, we now need to start adding complexity and features in order to really create a smart contract, let’s start with with giving it some memory in the form of basic storage.

Basic Storage:

FILE: basicStorage.sol
/* Stolen from the docs */
pragma solidity ^0.4.0;
contract basicStorage {
    uint storedData;
function set(uint x) {
        storedData = x;
    }
function get() constant returns (uint) {
        return storedData;
    }
}

There is not much happening here, a variable declaration and 2 contract methods in the form of a getter and a setter which will allow us to save and modify storedData. For comparisons sake this is what a similar javascript class would look like:

// JAVASCRIPT ES6
// Source : dVvoWr
class basicStorage {
  constructor(Data) {
    this.storedData = Data;  
  }
  
  set(x) {
    this.storedData = x;
  }
  
  get() {
    return this.storedData;
  }
  
}
  
var BS = new basicStorage(0);
BS.set(10);
console.log(BS.get()); // 10

Compile and Deploy :

A slightly more verbose compiler:

FILE: Compiler.js
console.log('Setting up...');
const fs = require('fs');
const solc = require('solc');
const Web3 = require ('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Reading contract Source...');
const input = fs.readFileSync('basicStorage.sol');
console.log('Compiling...');
const output = solc.compile(input.toString(), 1);
if (output.errors) {
  console.log('Compiling failed with errors:' + output.errors);
  process.exit();
}
const bytecode = output.contracts[':basicStorage'].bytecode;
const abi = output.contracts[':basicStorage'].interface;
console.log('saving ABI');
fs.writeFile("./basicStorage.json", abi, function(err) {
  if (err) {
    return console.log(err);
  }
  console.log("ABI Saved");
});
const basicStorage = web3.eth.contract(JSON.parse(abi));
console.log('unlocking Coinbase account');
const password = "yourPasswordHere";
try {
  web3.personal.unlockAccount(web3.eth.coinbase, password);
} catch(e) {
  return console.log(e);
}
console.log("Deploying contract...");
const basicStorageInstance = basicStorage.new({
    data: '0x' + bytecode,
    from: web3.eth.coinbase,
    gas: 400000
}, function(err, res){
    if (err) {
      console.log('there were errors:' + err);
    }
    if (res.address) {
        console.log('txHash:' + res.transactionHash);
        console.log('Succesfully deployed Contract with address: ' + res.address);
    }
});

Readout:

Setting up...
Reading contract Source...
Compiling...
saving ABI
unlocking Coinbase account
Deploying contract...
ABI Saved
txHash:0x2d053628cea870c20d4757e706c4312ea3db14c74887131b7d4f5560ad0d04ee
Successfully deployed Contract with address: 0x20ed8cc5c767b100c6a5b018e533e38b44b36326

So far nothing new, what we will now do is set ( via a transaction ) and read via a call the storage on our contract:

1.set()

// FILE: setTransaction.js
console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./basicStorage.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
const basicStorage = web3.eth.contract(contractABI);
var basicStorageInstance = basicStorage.at("0x20ed8cc5c767b100c6a5b018e533e38b44b36326");
console.log('unlocking Coinbase account');
const password = "your_password";
try {
  web3.personal.unlockAccount(web3.eth.coinbase, password);
} catch(e) {
  console.log(e);
  return;
}
console.log ('sending Transaction to the contract');
basicStorageInstance.set.sendTransaction(42, {from:web3.eth.coinbase}, function(err, txHash) {
  if (err != null) {
         console.error("Error while sending transaction: " + err);
       }
       else{
         console.log("Transaction Sent here's you  txHash: " + txHash);
       }
});
// If you are not interested in the callback/want a shorter version  you can use:
// basicStorageInstance.set(42, {from:web3.eth.coinbase});

And our readout :

Setting up...
Reading abi
Connecting
Creating contract instance
unlocking Coinbase account
sending Transaction to the contract
Transaction Sent here's you  txHash: 0x05e71b56c95c66d6fe59984d9af0bee00cac7c62cd210571a5c0c96009f28d83

This will in theory set our contracts storedData variable to 42 ( and it did cost ether btw) , in order to read this value ( there are timing issues, but for now we’ll skip them ). we will have to call our get function:

2.call()

// FILE: getCall.js
console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./basicStorage.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
const basicStorage = web3.eth.contract(contractABI);
var basicStorageI = basicStorage.at("0x20ed8cc5c767b100c6a5b018e533e38b44b36326");
console.log ('calling contract');
var returner = parseInt(basicStorageI.get.call());
console.log(returner + 10);
// 52

We can now retrieve our previously stored variable (storedData). Notice we are casting it again as an Int in order to use it in an operation ( 42 +10 = 52 ) and as noted previously this does not incurr in gas/ether costs.

Note: web3 is in active development, calling methods might be slightly different in the next version or 1.0.0.

Watching contracts:

One of the quirks of having a virtual machine run on a blockchain, is that state computations on contracts are not immediate, a transaction has to be sent, and then mined.As previously mentioned sent transactions that affect a contract state do not return any values, so we need another way to check when and if a transaction and contracts method returned something.

One solution is to watch the blockchain for our contract and then call our contract method when our transaction gets accepted.

This would involve to somehow watch the blockchain from within web3.js/node, luckily this is somehow trivial :

// FILE: filterWatch.js
// Watches the blockchain:
// filter can be 'latest' or 'pending' check :
// https://ethereum.stackexchange.com/questions/3400/filters-whats-latest-and-pending
console.log('Setting up...');
const solc = require('solc');
const Web3 = require('web3');
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
filter = web3.eth.filter('latest'); 
console.log('Watching');
filter.watch(function(error, result) {
      console.log(result);
    });

Readout:

Setting up...
Connecting
Watching
0x3296600010cd439485a254e71cc5b88fcdcf3752858df9161b55eac1586d5e3d
0x2715f22c8b5bc5ebea25d2b76f0ad789eba692591d86d0d786120b2aa8d4b49c
0x0e35d29ed8dcf93c0b7b514b6cc4d9dd181372015346f85d4b680f650a181969
.....

We would need to get information from each of the block hashes and query them for transactions until we got to ours, and then call the get() method, while possible, the preferred way is via events, which we will briefly cover next. ( you also now know how to watch the blockchain ).

Contract Events

In order to use contract events, the first step is to modify our basicStorage contract to log events :

// FILE : basicStorageEv.sol
// Thanks to GregJeanmart for the snippet.
pragma solidity ^0.4.0;
contract basicStorage {
    uint storedData;
    event SetEvent(
        address indexed _from,
        uint _x
    );
    function set(uint x) {
        storedData = x;
    // Log event inside set
        SetEvent(msg.sender, x);
    }
function get() constant returns (uint) {
        return storedData;
    }
}

Compile and Deploy (using compiler.js):

console.log('Setting up...');
const fs = require('fs');
const solc = require('solc');
const Web3 = require ('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Reading contract Source...');
const input = fs.readFileSync('basicStorageEv.sol');
console.log('Compiling...');
const output = solc.compile(input.toString(), 1);
if (output.errors) {
  console.log('Compiling failed with errors:' + output.errors);
  process.exit();
}
const bytecode = output.contracts[':basicStorageEv'].bytecode;
const abi = output.contracts[':basicStorageEv'].interface;
console.log('saving ABI');
fs.writeFile("./basicStorageEv.json", abi, function(err) {
  if (err) {
    return console.log(err);
  }
  console.log("ABI Saved");
});
const basicStorageEv = web3.eth.contract(JSON.parse(abi));
console.log('unlocking Coinbase account');
const password = "your_password";
try {
  web3.personal.unlockAccount(web3.eth.coinbase, password);
} catch(e) {
  return console.log(e);
}
console.log("Deploying contract...");
const basicStorageEvInstance = basicStorageEv.new({
    data: '0x' + bytecode,
    from: web3.eth.coinbase
    // gasPrice: '4000000',
    // gas: 1000000 /
}, function(err, res){
    if (err) {
      console.log('there were errors:' + err);
    }
    if (res.address) {
        console.log('txHash:' + res.transactionHash);
        console.log('Succesfully deployed Contract with address: ' + res.address);
    }
});

Readout:

Setting up...
Reading contract Source...
Compiling...
saving ABI
unlocking Coinbase account
Deploying contract...
ABI Saved
txHash:0x344020880f594d9c776b750d84f9d1bec9f1c1d6ff6e66663e99cf3dde73c098
Succesfully deployed Contract with address: 0xac88d694726e84ae46e2450cc8e30ea882a0cc43

And now in order to watch the event we need to subscribe to it like this:

console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./basicStorageEv.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
const basicStorageEv = web3.eth.contract(contractABI);
var basicStorageEvI = basicStorageEv.at("0xac88d694726e84ae46e2450cc8e30ea882a0cc43");
var myEvent = basicStorageEvI.SetEvent({}, {fromBlock: 0, toBlock: 'latest'});
console.log("Start watching events");
myEvent.watch(function(error, result){
    if (!error) {
        console.log(result);
    } else {
        console.log(error);
    }
});

I previously called set 3 times: set(10), so I would get this redout:

FILE: watchEvents.js
Setting up...
Reading abi
Connecting
Creating contract instance
Start watching events
{ address: '0xac88d694726e84ae46e2450cc8e30ea882a0cc43',
  blockHash: '0x69ee11dec3121715a8ec082ca386d4b4d547aa184739228307164a105dbb7c24',
  blockNumber: 4061192,
  logIndex: 1,
  transactionHash: '0x4e75edab76bd83911caf003e6de05324f3f10cc7f90886e3d0112139956bc640',
  transactionIndex: 1,
  transactionLogIndex: '0x0',
  type: 'mined',
  event: 'SetEvent',
  args: 
   { _from: '0x001301ad1556fd419cf8970b174fe9af34267eb8',
     _x: { [String: '10'] s: 1, e: 1, c: [Array] } } }
{ address: '0xac88d694726e84ae46e2450cc8e30ea882a0cc43',
  blockHash: '0x9a09b2920072fd0eaf4bbc0fe5f38c431b80e747e8443b4eb1050114acbc5ddf',
  blockNumber: 4061200,
  logIndex: 3,
  transactionHash: '0xd3eb8d1dd11e6db6140bb8a3741889462d7c4102c2c08eed405664fa5b30e91b',
  transactionIndex: 1,
  transactionLogIndex: '0x0',
  type: 'mined',
  event: 'SetEvent',
  args: 
   { _from: '0x001301ad1556fd419cf8970b174fe9af34267eb8',
     _x: { [String: '10'] s: 1, e: 1, c: [Array] } } }
{ address: '0xac88d694726e84ae46e2450cc8e30ea882a0cc43',
  blockHash: '0xad9d8038f8e0334046fe530306c980f773698eae1873e224899dce1fe3fbc276',
  blockNumber: 4061224,
  logIndex: 3,
  transactionHash: '0x5c0fa62c3c3b7015fda363b8d973708d7526c998b4fb8ae53cfe7adbd76123fe',
  transactionIndex: 1,
  transactionLogIndex: '0x0',
  type: 'mined',
  event: 'SetEvent',
  args: 
   { _from: '0x001301ad1556fd419cf8970b174fe9af34267eb8',
     _x: { [String: '10'] s: 1, e: 1, c: [Array] } } }

You can watch for specific events via topics ( you might need to modify your event emmiter in the contract) and you can get specific information back via the args variable: (result.args._x in our case):

GAS :

So far I’ve been glossing over gas costs in transactions since gas in testnets is basically free, but an important part of deploying contracts succesfuly as well as estimating costs in real money hinges on understanding gas, so let’s see how gas works and how to estimate and adjust it.

  • Gas is complex. In short it is the cost of making operations on ethereums Virtual Machine (VM), and has a price that is somehow independent of Ether,it is set in a sliding scale by miners and varies by operation, there are a thousand analogies out there, but the critical bit is if you don’t get the price and the amount right when deploying and interacting with your contracts, your transactions will fail and you might even loose some ether in the process.

Let’s first fail a transaction:

console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./basicStorage.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
const basicStorage = web3.eth.contract(contractABI);
var basicStorageInstance = basicStorage.at("0x20ed8cc5c767b100c6a5b018e533e38b44b36326");
console.log('unlocking Coinbase account');
const password = "your_password";
try {
  web3.personal.unlockAccount(web3.eth.coinbase, password);
} catch(e) {
  console.log(e);
  return;
}
console.log ('sending Transaction to the contract');
const transaction = {
  from: web3.eth.coinbase,
  gas: 0,
  gasPrice: 0
}
basicStorageInstance.set.sendTransaction(220, transaction, function(err, txHash) {
  if (err != null) {
         console.error("Error while sending transaction: " + err);
       }
       else{
         console.log("Transaction Sent here's you  txHash: " + txHash);
       }
});

Readout:

Setting up...
Reading abi
Connecting
Creating contract instance
unlocking Coinbase account
sending Transaction to the contract
Error while sending transaction: Error: Transaction gas is too low. There is not enough gas to cover minimal cost of the transaction (minimal: 21464, got: 0). Try increasing supplied gas.

Estimating gas prices:

The first thing we need to do is estimate gas prices :

File: estimateGas.js
console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./basicStorage.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
const basicStorage = web3.eth.contract(contractABI);
var basicStorageInstance = basicStorage.at("0x20ed8cc5c767b100c6a5b018e533e38b44b36326");
var estimatedTransactionGas =  basicStorageInstance.set.estimateGas(220);
console.log('Estimated Transaction Gas:' + estimatedTransactionGas);

Readout:

Setting up...
Reading abi
Connecting
Creating contract instance
Estimated Transaction Gas:26586

As mentioned, the gas price is set by miners resolving blocks; we can get the median gas price ( in wei ) like so:

var gasPrice = web3.eth.gasPrice;
console.log('Current Gas price:' + gasPrice.toString(10));
// Current Gas price:20000000000
// See: https://ethereum.stackexchange.com/questions/27452/how-to-estimate-gas-cost

Going back to our failed transaction, we can now better estimate our gas requirements and submit them as part of the transaction:

console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./basicStorage.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
const basicStorage = web3.eth.contract(contractABI);
var basicStorageInstance = basicStorage.at("0x20ed8cc5c767b100c6a5b018e533e38b44b36326");
var estimatedTransactionGas =  basicStorageInstance.set.estimateGas(220);
var gasPrice = web3.eth.gasPrice;
console.log('Cost estimates: ' );
console.log('Estimated Transaction gas: ' + estimatedTransactionGas );
console.log('gas Price: ' + gasPrice);
console.log('unlocking Coinbase account');
const password = "your_password";
try {
  web3.personal.unlockAccount(web3.eth.coinbase, password);
} catch(e) {
  console.log(e);
  return;
}
console.log ('sending Transaction to the contract');
const transaction = {
  from: web3.eth.coinbase,
  gas: estimatedTransactionGas,
  gasPrice: gasPrice
}
basicStorageInstance.set.sendTransaction(220, transaction, function(err, txHash) {
  if (err != null) {
         console.error("Error while sending transaction: " + err);
       }
       else{
         console.log("Transaction Sent here's you  txHash: " + txHash);
       }
});

And out readout:

Setting up...
Reading abi
Connecting
Creating contract instance
Cost estimates: 
Estimated Transaction gas: 26586
gas Price: 20000000000 ( or 20 Gwei or 0.00000002 ether )
unlocking Coinbase account
sending Transaction to the contract
Transaction Sent here's you  txHash: 0x9617338ce298b2da4d4610aeca6324c1c5aa05b21347aac6a572b3b7b9253d3b

If we now inspect our txHash, we can get the real costs and compare them:

Note: Gas estimation is not a perfect science, at least to me,your transaction might still fail due to sudden gas price changes or other network variables, so you might have to increase by a factor both gas price and the gas used if you want to insure your transactions succeed.

I really wanted to make a token for our next part, but I think it is better to first cover a few other gotchas and features of smart contracts we will be using as to have a better foundation. Recap time:

  • Notes Part 1 : Setting up : Getting a wallet/client , connecting to a test ethereum blockchain and getting some test ether.
  • Notes Part 2: web3.js/node : Interacting with the blockchain through web3.js and node for more convenience and ease of development.
  • Notes Part 3: Solidity : Installing solidity (Ethereums contract writing language ) , Creating a very basic contract, compiling it, deploying it to the blockchain ( the test one) and interacting with it.
  • Notes Part 4: Smart Contracts ( this post ) We modified our simple contract so we could store and retrieve information (making it smarter) , in the process we also covered how to watch the blockchain and contracts and finally we took a look at gas and how to estimate it.
Want to take these notes offline ?
If you are looking for an introduction to Ethereum, Solidity and Smart Contracts these notes are now available in a paper and ebook form! ❤️📖❤️
https://www.amazon.com/dp/B078CQ8L7V

Cheers !

Keno

About the Author :

Born Eugenio Noyola Leon (Keno) I am a Designer,Web Developer/programmer, Artist and Inventor, currently living in Mexico City, you can find me at www.k3no.com

Solidity
Ethereum
Smart Contracts
Blockchain
Cryptocurrency
Recommended from ReadMedium