<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Paul Berg</title>
    <description>The latest articles on Forem by Paul Berg (@prberg).</description>
    <link>https://forem.com/prberg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F118019%2F8d60f248-a067-4632-a5ca-7b6540573742.jpg</url>
      <title>Forem: Paul Berg</title>
      <link>https://forem.com/prberg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/prberg"/>
    <language>en</language>
    <item>
      <title>How to Code Your Own Confidential Token on Ethereum</title>
      <dc:creator>Paul Berg</dc:creator>
      <pubDate>Sat, 16 Feb 2019 11:25:01 +0000</pubDate>
      <link>https://forem.com/prberg/how-to-code-your-own-confidential-token-on-ethereum-19io</link>
      <guid>https://forem.com/prberg/how-to-code-your-own-confidential-token-on-ethereum-19io</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A8boCJV4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/cover.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A8boCJV4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/cover.jpg" alt="Cover" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Ethereum is not private. Every time you transfer an ERC20 token or any other digital asset, information is leaked to third parties. They could find out your full financial history simply by heading to Etherscan, Blockscout or any other blockchain explorer out there.&lt;/p&gt;

&lt;p&gt;Fear not, there are ways to prevent this. For one, you could use multiple accounts, but you'd have to constantly remember not to cross-link these accounts. This would be a life admin nightmare. What if there was a more elegant and programmable way?&lt;/p&gt;

&lt;p&gt;Let me introduce AZTEC: a privacy protocol built on top of Ethereum. In this article, I will not emphasise on the cryptography underpinning the protocol, but rather on its practical applications such as developing confidential tokens.&lt;/p&gt;

&lt;p&gt;Disclaimer: I'm working at AZTEC as a full-time software engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;I will further assume that you have a basic understanding of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ethereum development using the &lt;a href="https://truffleframework.com/" rel="noopener noreferrer"&gt;Truffle Framework&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ethresear.ch/t/zero-knowledge-proofs-starter-pack/4519" rel="noopener noreferrer"&gt;Zero-knowledge proofs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cryptography and elliptic curves&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure you have node.js and npm on your machine and install Truffle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;truffle &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mental Models
&lt;/h2&gt;

&lt;p&gt;Let's pause for a moment and grasp the core technical concepts.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Protocol
&lt;/h3&gt;

&lt;p&gt;Ethereum is a &lt;strong&gt;country&lt;/strong&gt; and AZTEC is a &lt;strong&gt;forest&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this country, people interact, do finance on dApps, move to different cities (wallets) and so forth. I like to think about AZTEC as a quiet woodland confined within the geography of the country. People can go there, declare their balance before stepping in, but after that transactions are confidential.&lt;/p&gt;

&lt;p&gt;The stock picture below represents my (silly) attempt to portray the idea of fading into AZTEC. It's crystal clear what's going on in the normal environment (Ethereum), but the state of the world after one crosses the arch is fuzzy and concealed by the forest (AZTEC).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qhaa9c39--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/forest.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qhaa9c39--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/forest.jpg" alt="Forest" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Notes
&lt;/h3&gt;

&lt;p&gt;An AZTEC note is a first-class citizen and core primitive of the protocol. When you transact in zero-knowledge, smart contracts do NOT store any balances, but instead work with elliptic curve points, which are just computational noise to anyone who doesn't have the private keys.&lt;/p&gt;

&lt;p&gt;It is very important to make a distinction between ERC20 and &lt;a href="https://github.com/ethereum/EIPs/issues/1724" rel="noopener noreferrer"&gt;ERC1724&lt;/a&gt;, AZTEC's confidential token standard. The former stores a &lt;a href="https://ethereum.stackexchange.com/questions/58203/storing-millions-of-values-in-mapping-variable/58204#58204" rel="noopener noreferrer"&gt;mapping between Ethereum addresses and unencrypted balances&lt;/a&gt;. The latter does encrypt the balances. I like to compare AZTEC notes with &lt;strong&gt;Bitcoin UTXOs&lt;/strong&gt;, as the process of spending notes on AZTEC is very much similar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OEJ9_z-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/note-validation.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OEJ9_z-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/note-validation.jpg" alt="Note Validation" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The contents of a note, classified by their visibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public

&lt;ul&gt;
&lt;li&gt;Owner&lt;/li&gt;
&lt;li&gt;Encrypted Value&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Private

&lt;ul&gt;
&lt;li&gt;Spending Key&lt;/li&gt;
&lt;li&gt;Value&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;We're optimising for speed, so we stop with the fancy cryptography here. If you're hungry for more, check out our &lt;a href="https://github.com/AztecProtocol/AZTEC/blob/master/AZTEC.pdf" rel="noopener noreferrer"&gt;white paper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before continuing though, do note that AZTEC needs a trusted setup. This tutorial uses a trusted setup that was generated by our team internally. We will be releasing more information about the production trusted setup generation in the near future. Use at own risk.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Do It
&lt;/h2&gt;

&lt;p&gt;Clone this &lt;a href="https://github.com/PaulRBerg/confidential-tokens" rel="noopener noreferrer"&gt;repo&lt;/a&gt; and install the node modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone git@github.com:PaulRBerg/confidential-tokens.git
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;confidential-tokens
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get a lot of verbose logs related to "scrypt" and "keccak", that's perfectly fine because we require &lt;code&gt;aztec.js&lt;/code&gt; which requires &lt;code&gt;web3.js&lt;/code&gt; which subsequently has many cryptographic dependencies.&lt;/p&gt;

&lt;p&gt;Before actually running the demo, there's a few important steps to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an &lt;code&gt;accounts.js&lt;/code&gt; file inside the &lt;code&gt;src&lt;/code&gt; folder. Only set &lt;strong&gt;two&lt;/strong&gt; accounts. There is an example file called &lt;code&gt;accounts.js.example&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.env&lt;/code&gt; file at the root of the project and fill it with the properties below. Again, there is an example file called &lt;code&gt;.env.example&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Deploy the confidential token contract to Rinkeby. You can use Truffle to do this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;truffle migrate &lt;span class="nt"&gt;--network&lt;/span&gt; rinkeby
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment variables:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://truffleframework.com/docs/truffle/reference/truffle-commands#networks" rel="noopener noreferrer"&gt;CONFIDENTIAL_TOKEN_ADDRESS&lt;/a&gt;: note that the actual contract name is ZKERC20, get this after truffle deploys the contract&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.mycrypto.com/private-keys-passwords/how-do-mnemonic-phrases-work.html" rel="noopener noreferrer"&gt;MNEMONIC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://infura.io" rel="noopener noreferrer"&gt;INFURA_API_KEY&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, check that your project looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YA7sS_YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/project-files.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YA7sS_YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/project-files.png" alt="Project Files" width="320" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the demo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm run demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is going to take a while, because transactions are sent to Rinkeby. After a few minutes, you should have a list of receipts printed in the console. Hooray, you just performed your first confidential token transfer on Ethereum!&lt;/p&gt;

&lt;p&gt;Now, let's go through the source code in &lt;code&gt;src/demo.js&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Notes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;aztecAccounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secp256k1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateAccount&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="nx"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aztecAccounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aztecAccounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aztecAccounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aztecAccounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a bunch of random accounts. We have to use "secp256k1" because AZTEC needs the accounts' public keys, not just their addresses.&lt;/li&gt;
&lt;li&gt;Create 4 notes, with the first two belonging to the first account and the last two giving 8 tokens from the initial total amount (10) to the second account.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To better understand step 2, recall that AZTEC notes are similar in nature with Bitcoin UTXOs. When one transfers money, the leftover sums have to be converted into a new set of notes - this is by contrast to Ethereum canonical transactions, which use a balance model.&lt;/p&gt;

&lt;p&gt;Also, I separated the accounts used in Ethereum (the ones in &lt;code&gt;src/accounts.js&lt;/code&gt;) from the randomly generated AZTEC accounts (the demo script generates a file called &lt;code&gt;aztecAccounts.json&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Dem Proofs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;proofs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;joinSplit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeJoinSplitTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;inputNotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;outputNotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;senderAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputNoteOwners&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;publicOwner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;kPublic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;aztecAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;joinSplit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proof object above:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attests that &lt;code&gt;publicOwner&lt;/code&gt; is happy to transfer 10 &lt;strong&gt;public&lt;/strong&gt; ERC20 tokens into AZTEC form&lt;/li&gt;
&lt;li&gt;Makes the first randomly generated AZTEC account the new owner (recall that the first two notes are worth 5 tokens each and are both owned by that AZTEC account)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;proofs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;joinSplit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeJoinSplitTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;inputNotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;outputNotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;senderAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputNoteOwners&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aztecAccounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;aztecAccounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="na"&gt;publicOwner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;kPublic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;aztecAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;joinSplit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second proof:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Transfers 8 tokens to the second AZTEC account in &lt;strong&gt;fully-fledged zero-knowledge&lt;/strong&gt; form&lt;/li&gt;
&lt;li&gt;Burns the first two input notes so that the first AZTEC account cannot reuse them in the future
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;proofOutputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proofs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;expectedOutput&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abiEncoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputCoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProofOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedOutput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;proofHashes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proofOutputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proofOutput&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;aztec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abiEncoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputCoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashProofOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proofOutput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need the above to interact with a contract named "NoteRegistry", which is unique to every confidential token contract. You can think of &lt;code&gt;proofHashes&lt;/code&gt; as an array of unique identifiers for the previously generated proofs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approve
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;erc20Mintable&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noteRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scalingFactor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokensTransferred&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeABI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendTx&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;aztecAddresses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;erc20Mintable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We mint a bunch of tokens and grant the NoteRegistry permission to spend from the ERC20 contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;noteRegistry&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publicApprove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proofHashes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeABI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendTx&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;noteRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like ERC20, NoteRegistry needs to be granted permission to work with AZTEC proofs. We confess that this is an area of active research and we're investigating ways of making the development UX smoother.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transfer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;confidentialToken&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confidentialTransfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proofs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;proofData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeABI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendTx&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;confidentialToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;confidentialToken&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confidentialTransfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proofs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;proofData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeABI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendTx&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;confidentialToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the fun part: call the confidential token contract to make the transfers. Note that the first transaction only converts the ERC20 tokens, so third parties can find out how many tokens were transferred. However, the second transaction is fully confidential.&lt;/p&gt;

&lt;p&gt;Here's a mindmap for what we just did:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uFaITyPl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/mindmap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uFaITyPl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paulrberg.com/post/confidential-tokens/mindmap.png" alt="Mind Map" width="540" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This tutorial uses a trusted setup that was generated by our team internally. We will be releasing more information about the production trusted setup generation in the near future. Use at own risk.&lt;/li&gt;
&lt;li&gt;There's a ton of pre-approvals required before the confidential transfers can be triggered. As previously mentioned, this is something we're looking forward to improving.&lt;/li&gt;
&lt;li&gt;The AZTEC codebase may go through multiple breaking changes after this article is published. Fear not though, this tutorial uses &lt;a href="https://teamtreehouse.com/community/why-install-npm-packages-as-saveexact" rel="noopener noreferrer"&gt;exact versions&lt;/a&gt; of npm packages to prevent disruption.&lt;/li&gt;
&lt;li&gt;AZTEC uses &lt;a href="https://solidity.readthedocs.io/en/v0.4.24/" rel="noopener noreferrer"&gt;Solidity 0.4.24&lt;/a&gt;, so you must use a compatible version of OpenZeppelin, that is &lt;a href="https://github.com/OpenZeppelin/openzeppelin-solidity/releases/tag/v2.0.0" rel="noopener noreferrer"&gt;2.0.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;When the AZTEC contracts have only one user, confidentiality is leaked. Third parties can infer how much money is deposited due to ERC20's public nature - they can compare that against the total amount held by the contract. The more users join, the more confidentiality there is.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Packages
&lt;/h2&gt;

&lt;p&gt;Here's an exhaustive list of AZTEC goodies we used:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/AztecProtocol/AZTEC/tree/master/packages/aztec.js" rel="noopener noreferrer"&gt;aztec.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AztecProtocol/AZTEC/tree/master/packages/contract-addresses" rel="noopener noreferrer"&gt;@aztec/contract-addresses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AztecProtocol/AZTEC/tree/master/packages/contract-artifacts" rel="noopener noreferrer"&gt;@aztec/contract-artifacts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AztecProtocol/AZTEC/tree/master/packages/dev-utils" rel="noopener noreferrer"&gt;@aztec/dev-utils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/AztecProtocol/AZTEC/tree/master/packages/protocol" rel="noopener noreferrer"&gt;@aztec/protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The source code for all of them is available in our &lt;a href="https://github.com/AztecProtocol/AZTEC" rel="noopener noreferrer"&gt;monorepo&lt;/a&gt;. Feel free to reach out on &lt;a href="https://twitter.com/aztecprotocol" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or email at &lt;a href="mailto:hello@aztecprotocol.com"&gt;hello@aztecprotocol.com&lt;/a&gt; if you have any questions!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this tutorial and you're as excited about confidential transactions as I am. Check out these transactions which use a couple of AZTEC proofs to convert 10 ERC20 tokens into fully-fledged zero-knowledge form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rinkeby.etherscan.io/tx/0x85ab17ab8290bad0d91501083c571a63e8715a0d425828df4c0b36accb11d077" rel="noopener noreferrer"&gt;https://rinkeby.etherscan.io/tx/0x85ab17ab8290bad0d91501083c571a63e8715a0d425828df4c0b36accb11d077&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rinkeby.etherscan.io/tx/0xf5dbaf357e09abf2d4151974bdfae5e20317043b155ff653b03fbd137c940a84" rel="noopener noreferrer"&gt;https://rinkeby.etherscan.io/tx/0xf5dbaf357e09abf2d4151974bdfae5e20317043b155ff653b03fbd137c940a84&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many thanks to Zac Williamson, Arnaud Schenk and Tom Waite for their input and feedback.&lt;/p&gt;

&lt;p&gt;Find me on &lt;a href="https://twitter.com/PaulRBerg" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://keybase.io/PaulRBerg" rel="noopener noreferrer"&gt;Keybase&lt;/a&gt; if you want to chat.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>privacy</category>
      <category>tech</category>
    </item>
    <item>
      <title>How to Write Upgradeable Smart Contracts with Truffle ^5.0 and ZeppelinOS ^2.0</title>
      <dc:creator>Paul Berg</dc:creator>
      <pubDate>Sun, 30 Dec 2018 16:41:34 +0000</pubDate>
      <link>https://forem.com/prberg/how-to-write-upgradeable-smart-contracts-with-truffle-50-and-zeppelinos-20-4d6k</link>
      <guid>https://forem.com/prberg/how-to-write-upgradeable-smart-contracts-with-truffle-50-and-zeppelinos-20-4d6k</guid>
      <description>&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;In this post, we'll learn how to write upgradeable smart contracts with the latest versions of Truffle and ZeppelinOS. In particular, version ^5.0 of Truffle introduces a plethora of updates, with the most prominent one being the integration with web3 ^1.0. Let's unpack these updates and introduce upgradeable smart contracts with the state-of-the-art ZeppelinOS.&lt;/p&gt;

&lt;p&gt;This is not an introductory article to Ethereum development, if you want that, take a look at the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.zeppelin.solutions/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05" rel="noopener noreferrer"&gt;The Hitchhiker’s Guide to Smart Contracts in Ethereum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.zeppelin.solutions/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094" rel="noopener noreferrer"&gt;Gentle Introduction to Ethereum Programming&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do note that the blockchain world moves at a ridiculous pace, giving little to no time for standards to sink in. This means that a lot of code snippets from the articles above may not work as expected, but don't panic and return here when that happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure you are equipped with the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;node.js and npm&lt;/li&gt;
&lt;li&gt;ganache-cli or the &lt;a href="https://truffleframework.com/ganache" rel="noopener noreferrer"&gt;Ganache&lt;/a&gt; desktop app&lt;/li&gt;
&lt;li&gt;curiosity to learn more&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Truffle ^5.0
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2Ftruffle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2Ftruffle.png" alt="Truffle Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install truffle globally, go to your terminal and write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;truffle@^5.0.0 &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let's create our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;MyProject
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myProject
&lt;span class="nv"&gt;$ &lt;/span&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;truffle init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialise a bunch of files. If you used older versions of Truffle, you may notice that "truffle-config.js" is more verbose now and has many more configurable options. Let's go through the important changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web3 ^1.0
&lt;/h3&gt;

&lt;p&gt;This is a major API change, but it's a good one, because the new library is much more elegant and intuitive to use. Of course, there are transition costs if you had already written your Truffle tests using older versions, so bookmark the web3 ^1.0 &lt;a href="https://web3js.readthedocs.io/en/1.0/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; just in case.&lt;/p&gt;

&lt;h3&gt;
  
  
  HD Wallet Provider
&lt;/h3&gt;

&lt;p&gt;If you were previously using the "truffle-hdwallet-provider" npm module, you &lt;strong&gt;must&lt;/strong&gt; upgrade to "truffle-hdwallet-provider@web3-one" to make it work with Truffle ^5.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;truffle-hdwallet-provider@web3-one &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To load your mnemonic, you can either use the "fs" module natively provided by node or you can install "dotenv". Never hardcode it in JavaScript!&lt;/p&gt;

&lt;h3&gt;
  
  
  Bring Your Own Compiler
&lt;/h3&gt;

&lt;p&gt;It used to be a huge &lt;a href="https://ethereum.stackexchange.com/questions/17551/how-to-upgrade-solidity-compiler-in-truffle" rel="noopener noreferrer"&gt;pain in the neck&lt;/a&gt; to change the Solidity compiler when compiling with Truffle, but fear not any more! You can define whatever (remote) version you want by doing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;compilers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;solc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.4.25&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this particular example, we set the compiler version to "0.4.25", but you can choose "0.4.24" or "0.4.18" if you want to. To list all the available versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;truffle compile &lt;span class="nt"&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Support for Async, Await
&lt;/h3&gt;

&lt;p&gt;If you're a fan of JavaScript ES8's super duper cool "async" and "await", you can now make good use of them when running &lt;code&gt;$ truffle develop&lt;/code&gt; or &lt;code&gt;$ truffle console&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Others
&lt;/h3&gt;

&lt;p&gt;There a few other new features, such as the added support for plugins, but they are outside the scope of this tutorial. Check out the &lt;a href="https://github.com/trufflesuite/truffle/releases/tag/v5.0.0" rel="noopener noreferrer"&gt;changelog&lt;/a&gt; if you're looking for an exhaustive list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy a Smart Contract
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2Fsmart-contract.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2Fsmart-contract.png" alt="Smart Contract"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the mock-up Solidity contract we're going to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Note.sol
pragma solidity ^0.4.25;

contract Note  {
  uint256 private number;

  constructor(uint256 _number) public {
    number = _number;
  }

  function getNumber() public view returns (uint256 _number) {
    return number;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file called "Note.sol" in your "contracts" folder and copy and paste the code above in there. Now, make sure you've done all the steps correctly by compiling the contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;truffle compile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get no error and the following logs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compiling ./contracts/Migrations.sol...&lt;br&gt;&lt;br&gt;
Compiling ./contracts/Note.sol...&lt;br&gt;&lt;br&gt;
Writing artifacts to ./build/contracts&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let's write the migration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 2_migrate_note.js&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Note.sol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deployer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;deployer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the "migrations" folder, create a new file called "2_migrate_note.js" and copy and paste the code above. To verify the set up, you have to first spin up an Ethereum node, but don't worry, for local development there are tools like &lt;a href="https://truffleframework.com/ganache" rel="noopener noreferrer"&gt;Ganache&lt;/a&gt;. You can run it either by opening a new terminal window and executing &lt;code&gt;$ ganache-cli&lt;/code&gt; or by launching the desktop app. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;truffle migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you encounter problems, make sure that your "truffle-config.js" file looks like this (I stripped the comments for brevity):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// truffle-config.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;compilers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;solc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.4.25&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8545&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;network_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it works, you should get a beautiful report like the &lt;a href="https://gist.github.com/PaulRBerg/e582f77a6e59da1e4719b5877dd88cd8" rel="noopener noreferrer"&gt;one here&lt;/a&gt;. Awesome! Now you know how to compile and deploy a contract with Truffle ^5.0, but you haven't got your hands dirty with the cooler part yet: making the smart contracts upgradeable.&lt;/p&gt;

&lt;h2&gt;
  
  
  ZeppelinOS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2FzeppelinOS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2FzeppelinOS.png" alt="ZeppelinOS Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up
&lt;/h3&gt;

&lt;p&gt;If you're completely unfamiliar with upgradeable smart contracts, go watch Elena Nadolinski's &lt;a href="https://www.youtube.com/watch?v=FzmzUHLiutg" rel="noopener noreferrer"&gt;presentation&lt;/a&gt; on the topic. It's totally worth it and it can do a much better job than someone can on a blog.&lt;/p&gt;

&lt;p&gt;The gist of it is that we're aiming to reconcile traditional development practices with smart contracts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When running A/B testing with real users and there's a bug, we should patch the code and fix it asap.&lt;/li&gt;
&lt;li&gt;The upgradeability processes should remain fully transparent and not grant total power to the developer(s).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Point no. 2 is currently under research with many people actively &lt;a href="https://blog.zeppelinos.org/exploring-upgradeability-governance-in-zeppelinos-with-a-gnosis-multisig/" rel="noopener noreferrer"&gt;proposing&lt;/a&gt; transparent governance models. However, we won't mind decentralised autonomous organisations (DAOs) for now and focus on the technical part of the story.&lt;/p&gt;

&lt;p&gt;Let's install ZeppelinOS and its library dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;zos &lt;span class="nt"&gt;--global&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;zos-lib &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then initialise it within our Truffle project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zos init MyProject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A file called "zos.json" should've been initialised:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"zosversion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MyProject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Importantly, make sure to &lt;strong&gt;update the Note contract&lt;/strong&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Note.sol
pragma solidity ^0.4.25;

import "zos-lib/contracts/Initializable.sol";

contract Note is Initializable {
  uint256 private number;

  function initialize(uint256 _number) public initializer {
    number = _number;
  }

  function getNumber() public view returns (uint256 _number) {
    return number;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ZeppelinOS contracts don't use normal Solidity constructors but instead rely on an "Initializable" base contract which needs to have its "initialize" function overridden. Let's continue by adding the edited contract to ZeppelinOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;zos add Note
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following JavaScript object should've been added to "zos.json":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Note"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before deployment, ZeppelinOS requires you to create a session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;zos session &lt;span class="nt"&gt;--network&lt;/span&gt; development &lt;span class="nt"&gt;--from&lt;/span&gt; YOUR_DEPLOYMENT_ACCOUNT &lt;span class="nt"&gt;--expires&lt;/span&gt; 7200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explaining each parameter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;network: one of the networks defined under "truffle-config.js"&lt;/li&gt;
&lt;li&gt;from: because of a known &lt;a href="https://docs.zeppelinos.org/docs/pattern.html" rel="noopener noreferrer"&gt;transparent proxy issue&lt;/a&gt;, the deployment account mustn't be the default address designated by truffle or ganache&lt;/li&gt;
&lt;li&gt;expires: the time-to-live of the session, measured in seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, to clarify a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The session is sort of a "behavioural sugar" - while deploying, you don't have to specify the "network" and the "from" parameters.&lt;/li&gt;
&lt;li&gt;You might wonder what "from" parameter to set. Simply put, any account &lt;strong&gt;except&lt;/strong&gt; the first one. Find a picture below for an example on the Ganache desktop app:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2Fganache-account.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaulrberg.com%2Fpost%2Fupgradeable-smart-contracts%2Fganache-account.png" alt="Ganache Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ready for prime time?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;zos push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it worked, you should've got something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compiling contracts&lt;br&gt;&lt;br&gt;
Compiling ./contracts/Migrations.sol...&lt;br&gt;&lt;br&gt;
Compiling ./contracts/Note.sol...&lt;br&gt;&lt;br&gt;
Compiling zos-lib/contracts/Initializable.sol...&lt;br&gt;&lt;br&gt;
Writing artifacts to ./build/contracts  &lt;/p&gt;

&lt;p&gt;Validating contract Note&lt;br&gt;&lt;br&gt;
Uploading Note contract as Note&lt;br&gt;&lt;br&gt;
Deploying logic contract for Note&lt;br&gt;&lt;br&gt;
Created zos.dev-7923.json  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This command finally deploys your smart contract to the blockchain and it also creates a file called "zos.dev-&amp;lt;network_id&amp;gt;.json", where "&amp;lt;network_id&amp;gt;" is the id of your Ethereum network. This is where you can find important information about your project, such as the addresses of your deployed contracts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgradeability
&lt;/h3&gt;

&lt;p&gt;It is highly important to understand that ZeppelinOS, under the hood, works by creating two contracts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Proxy&lt;/li&gt;
&lt;li&gt;Logic&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The catch is that the Proxy redirects the end user to the Logic, but the Proxy "retains" the storage. That is, even if you update the Logic, the state of your smart contracts stays the same.&lt;/p&gt;

&lt;p&gt;Previously, you created and deployed a Logic contract. Let's create an instance of a Proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;zos create Note &lt;span class="nt"&gt;--init&lt;/span&gt; initialize &lt;span class="nt"&gt;--args&lt;/span&gt; 64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This deploys and logs the address of the new Proxy contract. Open a new terminal window and initialise a Truffle console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;truffle console &lt;span class="nt"&gt;--network&lt;/span&gt; development
&lt;span class="nb"&gt;let &lt;/span&gt;abi &lt;span class="o"&gt;=&lt;/span&gt; require&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"./build/contracts/Note.json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.abi
&lt;span class="nb"&gt;let &lt;/span&gt;contract &lt;span class="o"&gt;=&lt;/span&gt; new web3.eth.Contract&lt;span class="o"&gt;(&lt;/span&gt;abi, &lt;span class="s2"&gt;"your-proxy-address"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
contract.methods.getNumber&lt;span class="o"&gt;()&lt;/span&gt;.call&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should print "64".&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Head to the web3 ^1.0 &lt;a href="https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt; for more information on how to work with the new Contract API.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What if you want to change the number? Fortunately, you can make an upgrade to the logic of the contract, while preserving the storage.&lt;/p&gt;

&lt;p&gt;Firstly, update the contract by adding a new function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Note.sol
pragma solidity ^0.4.25;

import "zos-lib/contracts/Initializable.sol";

contract Note is Initializable {
  uint256 private number;

  function initialize(uint256 _number) public initializer {
    number = _number;
  }

  function getNumber() public view returns (uint256 _number) {
    return number;
  }

  function setNumber(uint256 _number) public {
    number = _number;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;zos push
&lt;span class="nv"&gt;$ &lt;/span&gt;zos update Note
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logs should look like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using session with network development, sender address 0xd833B5fa468A5a430a890390D8Ec652142836019&lt;br&gt;&lt;br&gt;
Upgrading proxy to logic contract 0xe6d6d1cd339f129275e5b5e7ab39d85bc5642010&lt;br&gt;&lt;br&gt;
Instance at 0x746bb4a872bdfd861c4af5dd9391b3fb5b22fb7a upgraded&lt;br&gt;&lt;br&gt;
0x746bb4a872bdfd861c4af5dd9391b3fb5b22fb7a&lt;br&gt;&lt;br&gt;
Updated zos.dev-7923.json&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, start a new Truffle console and call your new "setNumber" function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;truffle console &lt;span class="nt"&gt;--network&lt;/span&gt; development
&lt;span class="nb"&gt;let &lt;/span&gt;abi &lt;span class="o"&gt;=&lt;/span&gt; require&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"./build/contracts/Note.json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.abi&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;let &lt;/span&gt;contract &lt;span class="o"&gt;=&lt;/span&gt; new web3.eth.Contract&lt;span class="o"&gt;(&lt;/span&gt;abi, &lt;span class="s2"&gt;"your-proxy-address"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
contract.methods.getNumber&lt;span class="o"&gt;()&lt;/span&gt;.call&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
contract.methods.setNumber&lt;span class="o"&gt;(&lt;/span&gt;65&lt;span class="o"&gt;)&lt;/span&gt;.send&lt;span class="o"&gt;({&lt;/span&gt; from: YOUR_OTHER_ACCOUNT &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
contract.methods.getNumber&lt;span class="o"&gt;()&lt;/span&gt;.call&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should print "65".&lt;/p&gt;

&lt;p&gt;Voilà! You just wrote, deployed and upgraded an Ethereum smart contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveats
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"YOUR_DEPLOYMENT_ACCOUNT" must only be used when setting up a session, for any other interaction with the contract, you have to use other account.&lt;/li&gt;
&lt;li&gt;If you got a &lt;code&gt;A network name must be provided to execute the requested action&lt;/code&gt; error, just start a new session, the old one expired.&lt;/li&gt;
&lt;li&gt;You might've noticed that we didn't use TruffleContract to interact with the deployed contracts and instead relied on the web3 ^1.0 implementation. This is because I find the former confusing and, on many occasions[&lt;a href="https://github.com/trufflesuite/truffle/issues/1455" rel="noopener noreferrer"&gt;1&lt;/a&gt;][&lt;a href="https://github.com/trufflesuite/truffle/issues/1601" rel="noopener noreferrer"&gt;2&lt;/a&gt;], not even functional.&lt;/li&gt;
&lt;li&gt;There is more to upgradeable smart contracts than what we discussed here. Head to Zeppelin's awesome &lt;a href="https://docs.zeppelinos.org/docs/start.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to get the whole picture. In particular, I recommend looking over the &lt;a href="https://docs.zeppelinos.org/docs/start.html" rel="noopener noreferrer"&gt;limitations&lt;/a&gt; to upgrading storage variables.&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;If you're planning to migrate to Solidity ^0.5.0, I'm sorry to disappoint you that ZeppelinOS doesn't support it yet, as of Dec 2018. There is an option called "--skip-compile", but I felt that it added too much complexity to be worth it.&lt;/del&gt; Santiago Palladino from Zeppelin &lt;a href="https://twitter.com/smpalladino/status/1080460733333336065" rel="noopener noreferrer"&gt;reached out&lt;/a&gt; on Twitter and announced that they now do support the ^0.5.0 versions of Solidity. If you want to test it out, just do &lt;code&gt;npm install zos-lib@2.1.0-rc.0 --global&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this tutorial and you're as excited about blockchain development as I am, despite the occasional versioning and coordination issues. &lt;/p&gt;

&lt;p&gt;I compiled the code used throughout this article in this GitHub &lt;a href="https://github.com/PaulRBerg/truffle-zos-tutorial" rel="noopener noreferrer"&gt;repo&lt;/a&gt;. There are three branches (master, zos, zos-upgraded) with the correspondent code of the Note contract for every stage we've been through.&lt;/p&gt;

&lt;p&gt;Find me on &lt;a href="https://twitter.com/PaulRBerg" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://keybase.io/PaulRBerg" rel="noopener noreferrer"&gt;Keybase&lt;/a&gt; if you want to chat.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>howto</category>
      <category>blockchain</category>
      <category>tech</category>
    </item>
    <item>
      <title>How to Host a Static Website with S3, CloudFront and Route53</title>
      <dc:creator>Paul Berg</dc:creator>
      <pubDate>Thu, 27 Dec 2018 22:45:34 +0000</pubDate>
      <link>https://forem.com/prberg/how-to-host-a-static-website-with-s3-cloudfront-and-route53-1f1f</link>
      <guid>https://forem.com/prberg/how-to-host-a-static-website-with-s3-cloudfront-and-route53-1f1f</guid>
      <description>&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;I recently set-up my self-hosted personal &lt;a href="https://paulrberg.com" rel="noopener noreferrer"&gt;blog&lt;/a&gt; and I underestimated the effort I had to put in to make it exactly as I wanted to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pay-as-you-go hosting&lt;/li&gt;
&lt;li&gt;SSL certificate&lt;/li&gt;
&lt;li&gt;Functional www subdomain&lt;/li&gt;
&lt;li&gt;Highly customisable but minimalistic design&lt;/li&gt;
&lt;li&gt;Markdown-powered articles&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I decided to write a tutorial to help others do it with less overhead. This article will go into fine details on how to tick all the boxes above, with a focus on the back-end components. For 4 and 5, I used &lt;a href="https://gohugo.io" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt; with the &lt;a href="https://themes.gohugo.io/minimal/" rel="noopener noreferrer"&gt;Minimal&lt;/a&gt; theme.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Do note that this is a verbose tutorial, aimed at those who value flexibility and interoperability with other AWS services more than anything else. If you're just looking for something light and quick, you may want to use &lt;a href="https://netlify.com" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; or &lt;a href="https://aws-amplify.github.io" rel="noopener noreferrer"&gt;Amplify&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;I will further assume that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You designed and coded your website or at least have a mock-up.&lt;/li&gt;
&lt;li&gt;You have an AWS account (if not, go register one, first year has a free tier).&lt;/li&gt;
&lt;li&gt;You are familiar with DNS and &lt;a href="https://www.cloudflare.com/learning/dns/what-is-dns/" rel="noopener noreferrer"&gt;how it works&lt;/a&gt;, at least at a high level.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Regarding DNS, a quick explanation is that it's sort of the directory of the Internet and, just like Google owns "google.com", you can own "example.com" as well. To do it, you have to go a DNS registrar and purchase your the domain you want. I strongly recommend using &lt;a href="https://namecheap.pxf.io/c/1243704/386170/5618" rel="noopener noreferrer"&gt;Namecheap&lt;/a&gt; as your registrar, as they have an awesome UI and low prices. As an alternative, you could choose &lt;a href="https://godaddy.com" rel="noopener noreferrer"&gt;GoDaddy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In case your ".com" domain is taken and you want some clever mashups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://leandomainsearch.com" rel="noopener noreferrer"&gt;LeanDomainSearch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wordoid.com" rel="noopener noreferrer"&gt;Wordoid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://domainr.com" rel="noopener noreferrer"&gt;Domainr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you purchase it, don't set any DNS records yet. We'll do that later once we get to Route53.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting with Amazon
&lt;/h2&gt;

&lt;p&gt;As mentioned above, the goal is to use a pay-as-you-go service because it's by far the most cost-effective option out there. I used to pay a fixed cost in the range of tens of USD per month for a server even if I had periods when there was hardly any activity on it. Go modular, go with AWS!&lt;/p&gt;

&lt;p&gt;Before jumping in, it's important to grasp the nomenclature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS: Amazon Web Services&lt;/li&gt;
&lt;li&gt;S3: Simple Storage Service, for storing files&lt;/li&gt;
&lt;li&gt;Route53: a service for handling DNS records&lt;/li&gt;
&lt;li&gt;CloudFront: content delivery network (CDN) for speeding up your website, also required to generate the SSL certificate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a neat &lt;a href="https://cloudcraft.co/view/d2391653-9c67-4bcd-84f2-977b0e32ecfc?key=aoBnq-ksfVXmgA4yjWIWSQ" rel="noopener noreferrer"&gt;mindmap&lt;/a&gt; designed with &lt;a href="https://cloudcraft.co" rel="noopener noreferrer"&gt;Cloudcraft&lt;/a&gt; for what you're going to build:&lt;/p&gt;

&lt;p&gt;&lt;a href="/post/static-website-aws/mindmap.png" class="article-body-image-wrapper"&gt;&lt;img src="/post/static-website-aws/mindmap.png" alt="Mindmap"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll first focus on the path on the &lt;strong&gt;right-hand side&lt;/strong&gt;, so the normal configuration, not the one for the www subdomain. Importantly, using this modular configuration, you won't run any back-end Linux server at all, so you don't have mind updating or patching anything. How convenient is that?&lt;/p&gt;

&lt;h2&gt;
  
  
  S3
&lt;/h2&gt;

&lt;p&gt;&lt;a href="/post/static-website-aws/s3.png" class="article-body-image-wrapper"&gt;&lt;img src="/post/static-website-aws/s3.png" alt="S3 Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where you'll store your static files (HTML, CSS, JS). If you used Create React App or some other frontend development framework, look after your generated "build" or "public" folder.&lt;/p&gt;

&lt;p&gt;Here's what you have to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up an S3 bucket named "example.com". Notice that S3 bucket names are &lt;a href="https://stackoverflow.com/questions/24112647/why-are-s3-and-google-storage-bucket-names-a-global-namespace" rel="noopener noreferrer"&gt;global&lt;/a&gt; and, just like with domains, you have to find an alternative if someone reserved "example.com" before you. Based on your needs, you can enable or disable the options AWS provides you: versioning, server access logging, encryption etc.&lt;/li&gt;
&lt;li&gt;Make sure to uncheck the boxes that mention blocking and removing public access ACLs and policies. Many times, S3 buckets are used to store private data, so AWS optimises for highly secure configurations. In your case though, you want to have the bucket publicly accessible.&lt;/li&gt;
&lt;li&gt;Make sure to set a policy, here's an &lt;a href="https://gist.github.com/PaulRBerg/61e0c998f105fedb627fa66ff2c6aea6" rel="noopener noreferrer"&gt;example&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Activate "Static website hosting" for your bucket and check "Use this bucket to host a website"&lt;/li&gt;
&lt;li&gt;Upload your files, making sure "index.html" is at the root of your bucket&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All the operations above can be done using either the AWS &lt;a href="http://console.aws.amazon.com" rel="noopener noreferrer"&gt;administrator interface&lt;/a&gt; or the &lt;a href="https://github.com/aws/aws-cli" rel="noopener noreferrer"&gt;CLI&lt;/a&gt;. Specifically for step 4 though, I'd recommend doing it in the console so that you can get the endpoint for your new hosted website (I hid mine for privacy reasons):&lt;/p&gt;

&lt;p&gt;&lt;a href="/post/static-website-aws/static-website-hosting-s3.png" class="article-body-image-wrapper"&gt;&lt;img src="/post/static-website-aws/static-website-hosting-s3.png" alt="Static Website Hosting on S3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test it out in the browser to make sure you set up your S3 bucket correctly. It should like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;example.com.s3-website.your-region.amazonaws.com&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  CloudFront
&lt;/h2&gt;

&lt;p&gt;&lt;a href="/post/static-website-aws/cloudfront.png" class="article-body-image-wrapper"&gt;&lt;img src="/post/static-website-aws/cloudfront.png" alt="CloudFront Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To host a static website, you don't actually need CloudFront or any other CDN, because there's not much data to store and the gains in efficiency and UX are little. However, one of the original goals was to have a website secured by an SSL certificate.&lt;/p&gt;

&lt;p&gt;Now, you might've heard about CloudFlare, which is arguably the easiest way to get up and running with a CDN and also benefit of some SSL security. I say "some" because they have this misleading featurea called "Flexible SSL", which &lt;a href="http://disq.us/p/1ycwtny" rel="noopener noreferrer"&gt;doesn't have the security guarantees&lt;/a&gt; a self-signed SSL certificate has.&lt;/p&gt;

&lt;p&gt;Therefore, you're not going to use that, but instead make use of a similar service in AWS called CloudFront. You can think of it as having your own content distribution servers, as data is cached in multiple locations on Earth to provide your users fast response times. More important for the static website, it also makes possible using an SSL certificate.&lt;/p&gt;

&lt;p&gt;Again, you can create your CloudFront distribution using the AWS administrator interface or the CLI tool. Here's an example &lt;a href="https://gist.github.com/PaulRBerg/7d946e54c8f5cfc22f514855c6b6e864" rel="noopener noreferrer"&gt;configuration&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Caveats:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The origin name should be the endpoint you got after activating "Static website hosting" on your S3 bucket.&lt;/li&gt;
&lt;li&gt;Do NOT set any "DefaultRootObject". Leave it empty.&lt;/li&gt;
&lt;li&gt;Allow both HTTP and HTTPS. You'll be able to automatically redirect users from HTTP to HTTPS after the certificate is signed and installed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Make sure to wait a while for the distribution to properly boot (can take up to 15 minutes). Test it by opening the endpoint you receive, your S3 static website should pop. The endpoint should look like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;13fb4knzujxq0b.cloudfront.net&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note it somewhere because we'll use it with Route53 in a sec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route53
&lt;/h2&gt;

&lt;p&gt;&lt;a href="/post/static-website-aws/route53.png" class="article-body-image-wrapper"&gt;&lt;img src="/post/static-website-aws/route53.png" alt="Route53 Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's time to connect the domain you bought on your DNS registrar with CloudFront and S3. Route53 acts as the bridge for that.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Route53 hosted zone and set your domain. Make it public.&lt;/li&gt;
&lt;li&gt;You'll be given 4 NS records. Copy and paste the nameservers in your external domain administration page. If you're using &lt;a href="https://namecheap.pxf.io/c/1243704/386170/5618" rel="noopener noreferrer"&gt;Namecheap&lt;/a&gt;, here's how you can update your nameservers. Go to Account -&amp;gt; Dashboard -&amp;gt; Manage -&amp;gt; Nameservers -&amp;gt; Custom DNS and put your 4 nameservers in there: &lt;img src="/post/static-website-aws/namecheap-nameservers.png" alt="Namecheap Nameservers"&gt;
&lt;/li&gt;
&lt;li&gt;Create a record set and leave the name empty (it will default to example.com). Then:

&lt;ul&gt;
&lt;li&gt;Set the type to "A - IPv4 address"&lt;/li&gt;
&lt;li&gt;Respond with "Yes" to "Alias" and set the alias target to your CloudFront distribution url.&lt;/li&gt;
&lt;li&gt;Keep the routing policy as "Simple" and, based on your budget and needs, enable or disable "Evaluate Target Health".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Repeat step 3 for type "AAAA - IPv6 address" if you enabled your CloudFront distribution to be IPv6 compatible; if you followed this tutorial, IPv6 was enabled by default.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that DNS propagation can take up to &lt;a href="https://www.youtube.com/watch?v=Gr8RzCZWh5M" rel="noopener noreferrer"&gt;72 hours&lt;/a&gt;, although it should be normally updated within a few hours or faster. If you previously set any other DNS records (like MX for work emails), you'll have to reset them in Route53.&lt;/p&gt;

&lt;h2&gt;
  
  
  WWWhat now?
&lt;/h2&gt;

&lt;p&gt;Congrats for getting this far! I'm sorry to let you know that now you have to repeat all the previous three steps. Yes, you heard that right, because of the elusive way the Internet works, "www" is not something included as a holistic component of HTTP.&lt;/p&gt;

&lt;p&gt;It is important to point out that it's really not mandatory to add a www subdomain to your website and you can safely proceed to the next step &lt;em&gt;if&lt;/em&gt; you're fine with your end users not being able to access your website via "&lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;". I was a bit pedantic about it and I simply had to add the www subdomain.&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Redo only S3, CloudFront and Route53, you don't have to (and can't) go to &lt;a href="https://namecheap.pxf.io/c/1243704/386170/5618" rel="noopener noreferrer"&gt;Namecheap&lt;/a&gt; to buy "&lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;".&lt;/li&gt;
&lt;li&gt;For all the fields where you were asked to put "example.com", now put "&lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you wonder whether by creating S3 buckets means you are required to deploy your static files to both of them, the answer is no, you don't have to do that. When you activate "Static website hosting" for your second S3 bucket, select "Redirect requests" instead of "Use this bucket to host a website":&lt;/p&gt;

&lt;p&gt;&lt;a href="/post/static-website-aws/static-website-hosting-s3-www.png" class="article-body-image-wrapper"&gt;&lt;img src="/post/static-website-aws/static-website-hosting-s3-www.png" alt="Static Website Hosting on S3 WWWW"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SSL certificate
&lt;/h2&gt;

&lt;p&gt;Let's Encrypt (LE) is one of the best things that happened to the Internet in the last couple of years. They have democratised access to SSL certificates and this is a huge accomplishment, kudos to them! If LE was so helpful to you, consider making a &lt;a href="https://letsencrypt.org/donate/" rel="noopener noreferrer"&gt;donation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This step is crucial and also the hardest in the whole tutorial, so proceed carefully. You could use either your own machine or a Linux server to generate the certificate, but I chose the former option, it's simpler and less expensive.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Head to the &lt;a href="https://github.com/dlapiduz/certbot-s3front" rel="noopener noreferrer"&gt;certbot-s3front&lt;/a&gt; repo and install the tool. You need to have Python and pip installed.&lt;/li&gt;
&lt;li&gt;Follow their instructions, but:

&lt;ul&gt;
&lt;li&gt;Skip the S3 and CloudFront parts, you had already done that.&lt;/li&gt;
&lt;li&gt;Set "example.com,&lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;" as the value for the "-d" (domain) parameter. Read more about this on the LE &lt;a href="https://community.letsencrypt.org/t/certification-is-not-working-in-firefox-your-connection-is-not-secure/43090/6?u=paulrberg" rel="noopener noreferrer"&gt;forum&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After you successfully generate your SSL certificate, you could optionally enable "Redirect HTTP to HTTPS" on your naked domain (that is, "example.com") CloudFront distribution. Don't do this for "www", as it'll redirect to your naked domain anyway.&lt;/li&gt;
&lt;li&gt;Make sure to backup your &lt;code&gt;/etc/letsencrypt/live/example.com&lt;/code&gt; certificate(s).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Due to &lt;a href="https://github.com/dlapiduz/certbot-s3front/issues/70" rel="noopener noreferrer"&gt;mysterious reasons&lt;/a&gt;, I couldn't make certbot's authentication work by setting the "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY" environment variables. This might be caused by the fact that I have several different profiles in my &lt;code&gt;~/.aws/credentials&lt;/code&gt;, but I'm not sure. To avoid a "NoCredentialsError", just temporarily set a "default" profile and certbot will pick that up.&lt;/li&gt;
&lt;li&gt;If you're unlucky like me and you get a further "IAMCertificateId" error, check out &lt;a href="https://github.com/dlapiduz/certbot-s3front/issues/76" rel="noopener noreferrer"&gt;this solution&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ACM
&lt;/h3&gt;

&lt;p&gt;Optionally, you could use the AWS Certificate Manager (ACM). Shortly after this article was published, a lot of people jumped in to say that it'd be much easier to use ACM for generating certificates. No need to think about renewals, but it means you're locked in with AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottlenecks
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;No server logic: This tutorial is only applicable to static websites, so you cannot run any back-end logic using a node.js module like &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;express&lt;/a&gt;. For that, you can either spin up an EC2 instance, write Lambda functions or use Docker via ECS/ Kubernetes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LE certificates expire in 90 days: You can solve this in two ways. Firstly, you could set a reminder in your calendar, which I admit it's suboptimal, but I'm in an experimentation phase so I'm not bothered by a bit of manual work. Secondly, you could set a cron job, but you need a Linux server and use the "--renew-by-default --text" options when interacting with certbot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rich link previews can be a mess: This could be a problem specific to my Hugo theme, but I also think everyone wants to have a proper preview image and description when sharing their website links. &lt;a href="https://github.com/calintat/minimal/issues/61#issuecomment-449999181" rel="noopener noreferrer"&gt;Here's&lt;/a&gt; how I managed to do it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;Congrats, you now have a really cheap but still highly flexible static website! Billing stats for 100-1000 monthly active visitors and fairly frequent S3 deployments are between $1 and $2, so this is a steal! For usage way beyond that, you may need to upgrade your AWS components, but this is outside the scope of this tutorial.&lt;/p&gt;

&lt;p&gt;If you're an experienced developer interested to replicate this tutorial on multiple AWS accounts, you may want to check out &lt;a href="https://terraform.io" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;. It's a super duper cool Infrastructure-as-a-Service tool which you can use to define your S3, CloudFront and Route53 as code snippets. Isn't technology so dang amazing?&lt;/p&gt;

&lt;p&gt;Hope you find this tutorial helpful! Find me on &lt;a href="https://twitter.com/PaulRBerg" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://keybase.io/PaulRBerg" rel="noopener noreferrer"&gt;Keybase&lt;/a&gt; if you want to chat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://amazon.com" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt; for the AWS, S3, CloudFront and Route53 logos&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>howto</category>
      <category>tech</category>
    </item>
  </channel>
</rss>
