{"id":127877,"date":"2022-09-06T17:56:59","date_gmt":"2022-09-06T17:56:59","guid":{"rendered":"https:\/\/blog.finxter.com\/?p=651290"},"modified":"2022-09-06T17:56:59","modified_gmt":"2022-09-06T17:56:59","slug":"solidity-by-example-simple-open-auction-explained","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2022\/09\/06\/solidity-by-example-simple-open-auction-explained\/","title":{"rendered":"Solidity by Example \u2013 Simple Open Auction (Explained)"},"content":{"rendered":"\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-top\" data-payload=\"{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;651290&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;top&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;1&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\\\/5 - (1 vote)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;width&quot;:&quot;142.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}\">\n<div class=\"kksr-stars\">\n<div class=\"kksr-stars-inactive\">\n<div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"kksr-stars-active\" style=\"width: 142.5px;\">\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/div>\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\"> 5\/5 &#8211; (1 vote) <\/div>\n<\/div>\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube\"><a href=\"https:\/\/blog.finxter.com\/solidity-by-example-part-12-simple-open-auction\/\"><img decoding=\"async\" src=\"https:\/\/blog.finxter.com\/wp-content\/plugins\/wp-youtube-lyte\/lyteCache.php?origThumbUrl=https%3A%2F%2Fi.ytimg.com%2Fvi%2FaHFRws9Deq8%2Fhqdefault.jpg\" alt=\"YouTube Video\"><\/a><figcaption><\/figcaption><\/figure>\n<p>This article continues on the series we started the last time: <a href=\"https:\/\/blog.finxter.com\/how-does-the-solidity-voting-smart-contract-work\/\" data-type=\"URL\" data-id=\"https:\/\/blog.finxter.com\/how-does-the-solidity-voting-smart-contract-work\/\" target=\"_blank\" rel=\"noreferrer noopener\">Solidity smart contract examples<\/a>, which implement a simplified real-world process. <\/p>\n<p>Here, we&#8217;re walking through an example of a simple open auction.<\/p>\n<p class=\"has-base-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f30d.png\" alt=\"\ud83c\udf0d\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> <strong>Original Source Code<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.soliditylang.org\/en\/v0.8.15\/solidity-by-example.html#simple-open-auction\" data-type=\"URL\" data-id=\"https:\/\/docs.soliditylang.org\/en\/v0.8.15\/solidity-by-example.html#simple-open-auction\" target=\"_blank\">Solidity Docs<\/a><\/p>\n<p>We&#8217;ll first lay out the entire <a href=\"https:\/\/blog.finxter.com\/introduction-to-smart-contracts-and-solidity-part-3-blockchain-basics\/\" data-type=\"post\" data-id=\"537705\" target=\"_blank\" rel=\"noreferrer noopener\">smart contract<\/a> example without the comments for readability and development purposes. <\/p>\n<p>Then we&#8217;ll dissect it part by part, analyze it and explain it. <\/p>\n<p>Following this path, we&#8217;ll get a hands-on experience with smart contracts, as well as good practices in coding, understanding, and <a href=\"https:\/\/blog.finxter.com\/top-8-scary-smart-contract-hacks-that-exploit-your-dapp-video\/\" data-type=\"post\" data-id=\"437387\" target=\"_blank\" rel=\"noreferrer noopener\">debugging<\/a> smart contracts.<\/p>\n<h2><a><\/a>Smart contract &#8211; Simple Open Auction<\/h2>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.4; contract SimpleAuction { address payable public beneficiary; uint public auctionEndTime; address public highestBidder; uint public highestBid; mapping(address => uint) pendingReturns; bool ended; event HighestBidIncreased(address bidder, uint amount); event AuctionEnded(address winner, uint amount); error AuctionAlreadyEnded(); error BidNotHighEnough(uint highestBid); error AuctionNotYetEnded(uint timeToAuctionEnd); error AuctionEndAlreadyCalled(); constructor( uint biddingTime, address payable beneficiaryAddress ) { beneficiary = beneficiaryAddress; auctionEndTime = block.timestamp + biddingTime; } function bid() external payable { if (block.timestamp > auctionEndTime) revert AuctionAlreadyEnded(); if (msg.value &lt;= highestBid) revert BidNotHighEnough(highestBid); if (highestBid != 0) { pendingReturns[highestBidder] += highestBid; } highestBidder = msg.sender; highestBid = msg.value; emit HighestBidIncreased(msg.sender, msg.value); } function withdraw() external returns (bool) { uint amount = pendingReturns[msg.sender]; if (amount > 0) { pendingReturns[msg.sender] = 0; if (!payable(msg.sender).send(amount)) { pendingReturns[msg.sender] = amount; return false; } } return true; } function auctionEnd() external { if (block.timestamp &lt; auctionEndTime) revert AuctionNotYetEnded(auctionEndTime - block.timestamp); if (ended) revert AuctionEndAlreadyCalled(); ended = true; emit AuctionEnded(highestBidder, highestBid); beneficiary.transfer(highestBid); }\n}\n<\/pre>\n<h2><a><\/a>Code breakdown and analysis<\/h2>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ SPDX-License-Identifier: GPL-3.0<\/pre>\n<p>Compiles only with Solidity compiler version 0.8.4 and later, but before version 0.9.<\/p>\n<p class=\"has-base-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f30d.png\" alt=\"\ud83c\udf0d\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> <strong>Learn More<\/strong>: <a href=\"https:\/\/blog.finxter.com\/layout-of-a-solidity-source-file\/\" data-type=\"post\" data-id=\"455693\">Layout of a Solidity File<\/a><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">pragma solidity ^0.8.4; contract SimpleAuction {\n<\/pre>\n<p>Parameters of the auction are variables <code>beneficiary<\/code> and <code>auctionEndTime<\/code> which we&#8217;ll initialize with contract creation arguments while the contract gets <a href=\"https:\/\/blog.finxter.com\/ethereum-virtual-machine-evm-message-calls-solidity-smart-contracts\/\" data-type=\"post\" data-id=\"592250\" target=\"_blank\" rel=\"noreferrer noopener\">created<\/a>, i.e. in the contract constructor. <\/p>\n<p>Data type for time variables is unsigned integer <code>uint<\/code>, so that we can represent either absolute Unix timestamps (seconds since 1970-01-01) or time periods in seconds (seconds lapsed from the reference moment we chose).<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> address payable public beneficiary; uint public auctionEndTime;\n<\/pre>\n<p>The current state of the auction is reflected in two variables, <code>highestBidder<\/code> and <code>highestBid<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> address public highestBidder; uint public highestBid;\n<\/pre>\n<p>Previous bids can be withdrawn, that&#8217;s why we have mapping data structure to record <code>pendingReturns<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> mapping(address => uint) pendingReturns;<\/pre>\n<p>Indicator flag variable for the auction end. By default, the flag is initialized to <code>false<\/code>; we&#8217;ll prevent changing it once it switches to <code>true<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> bool ended;<\/pre>\n<p>When changes occur, we want our smart contract to <a href=\"https:\/\/blog.finxter.com\/ethereum-virtual-machine-evm-message-calls-solidity-smart-contracts\/\" data-type=\"post\" data-id=\"592250\" target=\"_blank\" rel=\"noreferrer noopener\">emit<\/a> the corresponding change events.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> event HighestBidIncreased(address bidder, uint amount); event AuctionEnded(address winner, uint amount);\n<\/pre>\n<p>We&#8217;re defining four errors to describe relevant failures. Along with these errors, we&#8217;ll also introduce &#8220;triple-slash&#8221; comments, commonly known as <code>natspec<\/code> comments. They enable users to see comments when an error is displayed or when users are asked to confirm the transaction. <\/p>\n<p class=\"has-base-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f30d.png\" alt=\"\ud83c\udf0d\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> <strong>Learn More<\/strong>: Natspec comments are formally defined in <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.soliditylang.org\/en\/develop\/natspec-format.html\" data-type=\"URL\" data-id=\"https:\/\/docs.soliditylang.org\/en\/develop\/natspec-format.html\" target=\"_blank\">Ethereum Natural Language Specification Format<\/a>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> \/\/\/ The auction has already ended. error AuctionAlreadyEnded(); \/\/\/ There is already a higher or equal bid. error BidNotHighEnough(uint highestBid); \/\/\/ The auction has not ended yet, the remaining seconds are displayed. error AuctionNotYetEnded(uint timeToAuctionEnd); \/\/\/ The function auctionEnd has already been called. error AuctionEndAlreadyCalled();\n<\/pre>\n<p>Initialization of the contract with the contract creation arguments <code>biddingTime<\/code> and <code>beneficiaryAddress<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> \/\/\/ Create a simple auction with `biddingTime` \/\/\/ seconds bidding time on behalf of the \/\/\/ beneficiary address `beneficiaryAddress`. constructor( uint biddingTime, address payable beneficiaryAddress ) { beneficiary = beneficiaryAddress; auctionEndTime = block.timestamp + biddingTime; }\n<\/pre>\n<p>A bidder bids by sending the currency (<a href=\"https:\/\/blog.finxter.com\/what-is-payable-in-solidity\/\" data-type=\"post\" data-id=\"37282\" target=\"_blank\" rel=\"noreferrer noopener\">pa<\/a>y<a href=\"https:\/\/blog.finxter.com\/what-is-payable-in-solidity\/\" data-type=\"post\" data-id=\"37282\" target=\"_blank\" rel=\"noreferrer noopener\">ing<\/a>) to the smart contract representing the beneficiary, hence the <code>bid()<\/code> function is defined as <code><a href=\"https:\/\/blog.finxter.com\/what-is-payable-in-solidity\/\" data-type=\"post\" data-id=\"37282\" target=\"_blank\" rel=\"noreferrer noopener\">payable<\/a><\/code>.<\/p>\n<p class=\"has-base-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f30d.png\" alt=\"\ud83c\udf0d\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> <strong>Learn More<\/strong>: <a href=\"https:\/\/blog.finxter.com\/what-is-payable-in-solidity\/\" data-type=\"post\" data-id=\"37282\">What is <code>payable<\/code> in Solidity?<\/a><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> \/\/\/ Bid on the auction with the value sent \/\/\/ together with this transaction. \/\/\/ The value will only be refunded if the \/\/\/ auction is not won. function bid() external payable {\n<\/pre>\n<p>The function call reverts if the bidding period ended.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> if (block.timestamp > auctionEndTime) revert AuctionAlreadyEnded();\n<\/pre>\n<p>The function rolls back the transaction to the bidder if the bid does not exceed the highest one.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> if (msg.value &lt;= highestBid) revert BidNotHighEnough(highestBid);\n<\/pre>\n<p>The previous highest bidder was outbid and his bid is added to his previous bids reserved for a refund. <\/p>\n<p class=\"has-global-color-8-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f4a1.png\" alt=\"\ud83d\udca1\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> A direct refund is considered a <a href=\"https:\/\/blog.finxter.com\/top-8-scary-smart-contract-hacks-that-exploit-your-dapp-video\/\" data-type=\"post\" data-id=\"437387\">secu<\/a><a rel=\"noreferrer noopener\" href=\"https:\/\/blog.finxter.com\/top-8-scary-smart-contract-hacks-that-exploit-your-dapp-video\/\" data-type=\"post\" data-id=\"437387\" target=\"_blank\">r<\/a><a href=\"https:\/\/blog.finxter.com\/top-8-scary-smart-contract-hacks-that-exploit-your-dapp-video\/\" data-type=\"post\" data-id=\"437387\">ity risk<\/a> due to the possibility of executing an untrusted contract. <\/p>\n<p>Instead, the bidders (recipients) will withdraw their bids themselves by using withdraw() function below.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> if (highestBid != 0) { pendingReturns[highestBidder] += highestBid; }\n<\/pre>\n<p>The new highest bidder and his bid are recorded; the event <code>HighestBidIncreased<\/code> is emitted carrying this information pair.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> highestBidder = msg.sender; highestBid = msg.value; emit HighestBidIncreased(msg.sender, msg.value); }\n<\/pre>\n<p>Bidders call the <code>withdraw()<\/code> function to retrieve the amount they bid.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> \/\/\/ Withdraw a bid that was overbid. function withdraw() external returns (bool) { uint amount = pendingReturns[msg.sender]; if (amount > 0) {\n<\/pre>\n<p>It is possible to call the <code>withdraw()<\/code> function again before the <code>send()<\/code> function returns. That&#8217;s the reason why we need to disable multiple sequential withdrawals from the same sender by setting the pending returns for a sender to 0.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> pendingReturns[msg.sender] = 0;<\/pre>\n<p>Variable type of <code>msg.sender<\/code> is not address <code>payable<\/code>, therefore we need to convert it explicitly by using function payable() as a wrapping function. <\/p>\n<p>If the <code>send()<\/code> function ends with an error, we&#8217;ll just reset the pending amount and return <code>false<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> if (!payable(msg.sender).send(amount)) { \/\/ No need to call throw here, just reset the amount owing pendingReturns[msg.sender] = amount; return false; } } return true; }\n<\/pre>\n<p>The <code>auctionEnd()<\/code> function ends the auction and sends the highest bid to the beneficiary. <\/p>\n<p>The official Solidity documentation recommends dividing the interacting functions into three functional parts:<\/p>\n<ul>\n<li>checking the conditions,<\/li>\n<li>performing the actions, and<\/li>\n<li>interacting with other contracts.<\/li>\n<\/ul>\n<p>Otherwise, by combining these parts rather than keeping them separated, more than one calling contract could try and modify the state of the called contract and change the called contract&#8217;s state.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> \/\/\/ End the auction and send the highest bid \/\/\/ to the beneficiary. function auctionEnd() external {\n<\/pre>\n<p>Checking the conditions&#8230;<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> if (block.timestamp &lt; auctionEndTime) revert AuctionNotYetEnded(auctionEndTime - block.timestamp); if (ended) revert AuctionEndAlreadyCalled();\n<\/pre>\n<p>&#8230;performing the actions&#8230;<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> ended = true; emit AuctionEnded(highestBidder, highestBid);\n<\/pre>\n<p>&#8230;and interacting with other contracts.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> beneficiary.transfer(highestBid); }\n}\n<\/pre>\n<p>Our smart contract example is a simple, but a powerful one, enabling us to bid an amount of currency to the beneficiary. <\/p>\n<p>When the contract instantiates via its constructor, it sets the auction end time and its beneficiary, i.e. beneficiary address. <\/p>\n<p>The contract has three simple features, implemented via dedicated functions: bidding, withdrawing the bids and ending the auction.<\/p>\n<p>A new bid is accepted only if its amount is strictly larger than the current highest bid. A new bid acceptance means that the current highest bid is added to the bidder&#8217;s balance for later withdrawal. The new highest bidder becomes the current highest bidder and the new highest bid becomes the current highest bid.<\/p>\n<p>Bid withdrawing returns all summed previous bids to each bidder (<code>mapping pendingReturns<\/code>).<\/p>\n<h2><a><\/a>Contract Test Scenario<\/h2>\n<p>Open auction duration (in seconds): <code>240<\/code><\/p>\n<p>Beneficiary: <code>0x5B38Da6a701c568545dCfcB03FcB875f56beddC4<\/code><\/p>\n<p>Testing\/demonstration steps:<\/p>\n<ol type=\"1\">\n<li><code>Account 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 bids 10 Wei;<\/code><\/li>\n<li><code>Account 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db bids 25 Wei;<\/code><\/li>\n<li><code>Account 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB bids 25 Wei (rejected);<\/code><\/li>\n<li><code>Account 0x617F2E2fD72FD9D5503197092aC168c91465E7f2 bids 35 Wei;<\/code><\/li>\n<li><code>Account 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 bids 40 Wei + initiates premature auction end;<\/code><\/li>\n<li><code>Account 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 withdraws his bids;<\/code><\/li>\n<li><code>Account 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db withdraws his bids;<\/code><\/li>\n<li><code>Account 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB withdraws his bids;<\/code><\/li>\n<li><code>Account 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB initiates timely auction end;<\/code><\/li>\n<li><code>Account 0x617F2E2fD72FD9D5503197092aC168c91465E7f2 withdraws his bids;<\/code><\/li>\n<\/ol>\n<h2><a><\/a>Appendix &#8211; The Contract Arguments<\/h2>\n<p>In this section is additional information for running the contract. We should expect that our example accounts may change with each refresh\/reload of Remix.<\/p>\n<p>Our contract creation arguments are the <em>open auction duration<\/em> (in seconds) and the beneficiary address (copy this line when deploying the example):<\/p>\n<pre class=\"wp-block-preformatted\"><code>300, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4<\/code><\/pre>\n<p class=\"has-global-color-8-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f4a1.png\" alt=\"\ud83d\udca1\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> <strong>Info<\/strong>: we could&#8217;ve used any amount of time, but I went with 300 seconds to timely simulate both a rejected attempt of ending the auction and the successful ending of the auction.<\/p>\n<h2><a><\/a>Conclusion<\/h2>\n<p>We continued our smart contract example series with this article that implements a simple open auction.<\/p>\n<p>First, we laid out clean source code (without any comments) for readability purposes. Omitting the comments is not recommended, but we love living on the edge &#8211; and trying to be funny! <img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f600.png\" alt=\"\ud83d\ude00\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<p>Second, we dissected the code, analyzed it, and explained each possibly non-trivial segment. Just because we&#8217;re terrific, safe players who never risk it and do everything by the book <img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f642.png\" alt=\"\ud83d\ude42\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/academy.finxter.com\/university\/solidity-basics\/\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"363\" height=\"650\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2022\/05\/image-308.png\" alt=\"\" class=\"wp-image-387313\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2022\/05\/image-308.png 363w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2022\/05\/image-308-168x300.png 168w\" sizes=\"auto, (max-width: 363px) 100vw, 363px\" \/><\/a><\/figure>\n<\/div>\n<h2>Programmer Humor &#8211; Blockchain<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"280\" height=\"394\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2022\/07\/image-31.png\" alt=\"\" class=\"wp-image-457795\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2022\/07\/image-31.png 280w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2022\/07\/image-31-213x300.png 213w\" sizes=\"auto, (max-width: 280px) 100vw, 280px\" \/><figcaption><em>&#8220;Blockchains are like grappling hooks, in that it&#8217;s extremely cool when you encounter a problem for which they&#8217;re the right solution, but it happens way too rarely in real life.&#8221;<\/em> <strong>source <\/strong> &#8211; <a href=\"https:\/\/imgs.xkcd.com\/comics\/blockchain.png\" data-type=\"URL\" data-id=\"https:\/\/imgs.xkcd.com\/comics\/blockchain.png\" target=\"_blank\" rel=\"noreferrer noopener\">xkcd<\/a><\/figcaption><\/figure>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>5\/5 &#8211; (1 vote) This article continues on the series we started the last time: Solidity smart contract examples, which implement a simplified real-world process. Here, we&#8217;re walking through an example of a simple open auction. Original Source Code: Solidity Docs We&#8217;ll first lay out the entire smart contract example without the comments for readability [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[857],"tags":[73,468,528],"class_list":["post-127877","post","type-post","status-publish","format-standard","hentry","category-python-tut","tag-programming","tag-python","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/127877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=127877"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/127877\/revisions"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=127877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=127877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=127877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}