<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Regular Fascination]]></title><description><![CDATA[From macro to micro, the elements of technology and systems]]></description><link>https://liamz.co/blog/</link><image><url>https://liamz.co/blog/favicon.png</url><title>Regular Fascination</title><link>https://liamz.co/blog/</link></image><generator>Ghost 3.42</generator><lastBuildDate>Sat, 25 Oct 2025 08:37:14 GMT</lastBuildDate><atom:link href="https://liamz.co/blog/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[I only smoke cigarettes for the expressionism.]]></title><description><![CDATA[<p>He fell into the dirt. Scuffed, but unharmed, the kid observing nearby said "how do you get up??" in that annoying whiny voice. The question was irrelevant, and so was his statement. Neither of us had a cigarette, but both of us understood what he meant.</p><p>I never smoked a</p>]]></description><link>https://liamz.co/blog/smoking-as-expressionism/</link><guid isPermaLink="false">5ef4237d43252100014fa990</guid><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Sun, 04 Sep 2022 06:02:18 GMT</pubDate><content:encoded><![CDATA[<p>He fell into the dirt. Scuffed, but unharmed, the kid observing nearby said "how do you get up??" in that annoying whiny voice. The question was irrelevant, and so was his statement. Neither of us had a cigarette, but both of us understood what he meant.</p><p>I never smoked a cigarette until I hung out with Europeans. Those damned mantelpieces of culture. An Australian has no taste of what history looks like. Only the unspoken cultural traits of irreverence, like our <a href="https://www.theguardian.com/australia-news/2019/jun/14/bob-hawke-could-be-set-for-an-oxford-blue-plaque-for-beer-drinking-record">ex prime minister holding world records for chugging down a yard of beer</a>, or hosting <a href="https://en.wikipedia.org/wiki/Henley-on-Todd_Regatta">the only dry regatta event in the world</a>. The best part of our history – in between WW1 and WW2, we <a href="https://en.wikipedia.org/wiki/Emu_War">fought and lost a war with emus</a>. The worst part – well, there are many...</p><p>I smoked cigarettes, but I never was a smoker. Smokers debilitate themselves, smokers are addicted. Nah, I didn't crave cigarettes like I needed oxygen. But I sure loved smoking a cigarette and talking to a French girl. It feels exotic, it feels like an aside/refrain in my own life, which in a way, it is. Smoking always seemed to be a refrain from something else, you don't invite people around to smoke cigarettes, like you do coffee. Partying till 7am in the morning, inside a dark smokepit of Germanic techno, or outside in the misty forest, grooving to a digital melody – always, cigarettes were the currency, the propinquitous pasttime. </p><p>I smoked cigarettes for the expressionism, sometimes for the social contact. Being a smoker means a dirty thing, a person barred from the eating areas. Being a writer almost grants you license to smoke, at least it used to. Smoking is an activity of posture, of contemplating, but all the same, something that tradies do to get out of work. The very object itself will eventually kill you, and <a href="https://journals.plos.org/plosmedicine/article?id=10.1371/journal.pmed.1000316">so will loneliness</a>. </p><p></p><p> </p><p>Smoking will kill you, eventually. So will everything else. For some, cigarettes are domain of control I have over my life, a final <em>fuck you, </em>a comforting routine to get you up in the morning. You have your bean drip, I have my nicotine breathe. For others, it's almost like roasting </p><p></p><p></p><p></p><p>Why do you smoke cigarettes Liam?</p><p>Well, I know the disadvantages, naturally. But they're insignificant in small quantities. Almost the same callous disregard for inflation, I can apply to my respiratory health. Everyone used to smoke. I still have a newspaper clipping from 2014, about an American veteran who is 104 and smokes every day. A little smoking can't hurt, can it? </p><p>Smoking for me is more than a social event. It is what it is, I think. When I smoke a cigarette, I do it around people, I've done it alone only a few times. How does it feel? It feels calming, almost signatory as an extension of my own thoughts and movements. The headspin is never there, no. It's only the breathing. Just breathing. I think as a social signal, the externality of the exercise, as opposed to normal breathing, makes it something of an art, does it not? It aligns conversation, towards rhythms of boom and bust? Inhale and exhale?  </p><p></p><p></p><p>smoking first became a thing in my life <br>started working at palace<br>enjoy the experience<br>draw out draw out<br>expressing yourself in a way<br>gasps are enunciated <br>actively looking for a moment, need, look forward</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Cockatoos (short story)]]></title><description><![CDATA[<p></p><p>Easy. Relaxed. I perched myself on the bed. A chiptune of Aussie birds peckering in the background, punctured by the raunchous screams of a cockatoo. "AAARRGH AAAAARGH" barked the existentially tormented bird, as it hurled its body adamantly through time and space. Why is it that the cockatoo can scream,</p>]]></description><link>https://liamz.co/blog/cockatoos/</link><guid isPermaLink="false">624445a77803e40001c13506</guid><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Mon, 03 Jan 2022 12:46:00 GMT</pubDate><content:encoded><![CDATA[<p></p><p>Easy. Relaxed. I perched myself on the bed. A chiptune of Aussie birds peckering in the background, punctured by the raunchous screams of a cockatoo. "AAARRGH AAAAARGH" barked the existentially tormented bird, as it hurled its body adamantly through time and space. Why is it that the cockatoo can scream, but it's socially unacceptable for me, despite the fact I have to pay to live on this earth and they shit on my car for free. In fact, the only human that gets to shit and scream without consequence is the baby. Ah, the torment of lucidity.</p><p>From ages 17-&gt;20 you are either spending your time fucking everyone you can see or completely alone. There is no stop to this pendulum, eventually you meet someone worth fucking for a long time, that you can sit on the bed with and talk about all of the other people you've fucked, and how they were worse. Presumably, and I'm not religious, this would follow into the afterlife. When met at the gates by God, he explains to you how you were fucked by him too. </p>]]></content:encoded></item><item><title><![CDATA[Sublime Moodboards.]]></title><description><![CDATA[Some photos I've taken.]]></description><link>https://liamz.co/blog/fascinations-with-the-sublime/</link><guid isPermaLink="false">60b4dc08c0370e00016af0f0</guid><category><![CDATA[photoblog]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Sat, 03 Jul 2021 03:01:48 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2021/07/IMG_5210.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://liamz.co/blog/content/images/2021/07/IMG_5210.jpg" alt="Sublime Moodboards."><p>For a while, I've been fascinated by these types of photos. One that capture an essence of a situation in considerate depth.</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/A5A00EF2-BA1E-447C-B5B3-0FEFCAE6CF95_1_105_c.jpeg" width="768" height="1024" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/A5A00EF2-BA1E-447C-B5B3-0FEFCAE6CF95_1_105_c.jpeg 600w, https://liamz.co/blog/content/images/2021/05/A5A00EF2-BA1E-447C-B5B3-0FEFCAE6CF95_1_105_c.jpeg 768w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/4B98FDE8-1A10-40DD-AA81-29A0F6C45706_1_105_c-2.jpeg" width="768" height="1024" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/4B98FDE8-1A10-40DD-AA81-29A0F6C45706_1_105_c-2.jpeg 600w, https://liamz.co/blog/content/images/2021/05/4B98FDE8-1A10-40DD-AA81-29A0F6C45706_1_105_c-2.jpeg 768w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Country QLD</figcaption></figure><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/E93065B9-CD69-4C06-9E43-27EE9CA95000_1_105_c.jpeg" width="768" height="1024" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/E93065B9-CD69-4C06-9E43-27EE9CA95000_1_105_c.jpeg 600w, https://liamz.co/blog/content/images/2021/05/E93065B9-CD69-4C06-9E43-27EE9CA95000_1_105_c.jpeg 768w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/B5514A54-CC81-4617-9C23-3CE1244D1914_1_105_c.jpeg" width="768" height="1024" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/B5514A54-CC81-4617-9C23-3CE1244D1914_1_105_c.jpeg 600w, https://liamz.co/blog/content/images/2021/05/B5514A54-CC81-4617-9C23-3CE1244D1914_1_105_c.jpeg 768w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Cornwall (left), Rave (right)</figcaption></figure><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/9D0CFD94-990C-428B-B505-4960FF378588_1_105_c-1.jpeg" width="1024" height="768" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/9D0CFD94-990C-428B-B505-4960FF378588_1_105_c-1.jpeg 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/9D0CFD94-990C-428B-B505-4960FF378588_1_105_c-1.jpeg 1000w, https://liamz.co/blog/content/images/2021/05/9D0CFD94-990C-428B-B505-4960FF378588_1_105_c-1.jpeg 1024w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Sunshine Coast, QLD</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2021/05/6CF9671C-FCF1-4E61-961E-D766CC24AE90_1_105_c.jpeg" class="kg-image" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/6CF9671C-FCF1-4E61-961E-D766CC24AE90_1_105_c.jpeg 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/6CF9671C-FCF1-4E61-961E-D766CC24AE90_1_105_c.jpeg 1000w, https://liamz.co/blog/content/images/2021/05/6CF9671C-FCF1-4E61-961E-D766CC24AE90_1_105_c.jpeg 1182w"><figcaption>England, UK</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2021/05/image-3.png" class="kg-image" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/image-3.png 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/image-3.png 1000w, https://liamz.co/blog/content/images/2021/05/image-3.png 1182w"><figcaption>Wales, UK</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2021/05/IMG_0522.JPG" class="kg-image" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/IMG_0522.JPG 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/IMG_0522.JPG 1000w, https://liamz.co/blog/content/images/size/w1600/2021/05/IMG_0522.JPG 1600w, https://liamz.co/blog/content/images/size/w2400/2021/05/IMG_0522.JPG 2400w" sizes="(min-width: 1200px) 1200px"><figcaption>Fingal Bay, QLD</figcaption></figure><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/E361B422-1844-4A8D-9BD6-2CCB7316F566_1_105_c.jpeg" width="1291" height="610" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/E361B422-1844-4A8D-9BD6-2CCB7316F566_1_105_c.jpeg 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/E361B422-1844-4A8D-9BD6-2CCB7316F566_1_105_c.jpeg 1000w, https://liamz.co/blog/content/images/2021/05/E361B422-1844-4A8D-9BD6-2CCB7316F566_1_105_c.jpeg 1291w" sizes="(min-width: 1200px) 1200px"></div></div></div><figcaption>Amsterdam Centraal, The Netherlands</figcaption></figure><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/7DD305CE-0775-4430-BE9A-048FA8E819B8_1_105_c-2.jpeg" width="819" height="1024" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/7DD305CE-0775-4430-BE9A-048FA8E819B8_1_105_c-2.jpeg 600w, https://liamz.co/blog/content/images/2021/05/7DD305CE-0775-4430-BE9A-048FA8E819B8_1_105_c-2.jpeg 819w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2021/05/1093392C-74DB-4847-B2D8-69B3E996F24D_1_201_a.jpeg" width="2448" height="3264" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/1093392C-74DB-4847-B2D8-69B3E996F24D_1_201_a.jpeg 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/1093392C-74DB-4847-B2D8-69B3E996F24D_1_201_a.jpeg 1000w, https://liamz.co/blog/content/images/size/w1600/2021/05/1093392C-74DB-4847-B2D8-69B3E996F24D_1_201_a.jpeg 1600w, https://liamz.co/blog/content/images/size/w2400/2021/05/1093392C-74DB-4847-B2D8-69B3E996F24D_1_201_a.jpeg 2400w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Purling Brook Falls (left), Girl with Buzzsaw - Rotterdam Pride 2019 (right)</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2021/05/image-2.png" class="kg-image" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/image-2.png 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/image-2.png 1000w, https://liamz.co/blog/content/images/2021/05/image-2.png 1182w"><figcaption>Wales, UK</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2021/05/image-7.png" class="kg-image" alt="Sublime Moodboards." srcset="https://liamz.co/blog/content/images/size/w600/2021/05/image-7.png 600w, https://liamz.co/blog/content/images/size/w1000/2021/05/image-7.png 1000w, https://liamz.co/blog/content/images/2021/05/image-7.png 1024w"><figcaption>Northern NSW</figcaption></figure><p></p>]]></content:encoded></item><item><title><![CDATA[Man's Search for Meaning - Notes.]]></title><description><![CDATA[<p>Back in January I read a <a href="https://en.wikipedia.org/wiki/Lindy_effect">Lindy</a> book called "Man's Search for Meaning" by Viktor Frankl. It was during a period in which I was contemplating my own philosophy quite a lot. The last book on <em>philosophy</em> I read was Zen and the Art of Motorcycle maintenance, some 7 years</p>]]></description><link>https://liamz.co/blog/mans-search-for-meaning-notes/</link><guid isPermaLink="false">60064043c0370e00016aedf9</guid><category><![CDATA[books]]></category><category><![CDATA[analysis]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Tue, 25 May 2021 09:04:19 GMT</pubDate><content:encoded><![CDATA[<p>Back in January I read a <a href="https://en.wikipedia.org/wiki/Lindy_effect">Lindy</a> book called "Man's Search for Meaning" by Viktor Frankl. It was during a period in which I was contemplating my own philosophy quite a lot. The last book on <em>philosophy</em> I read was Zen and the Art of Motorcycle maintenance, some 7 years ago. </p><p>Reading philosophy books is an exercise in enjoying someone elses worldview, without making claims of scientific validity. When I read <em>Zen</em>, I learnt about the romantic and classical conceptions of the world – in Pirsig's worldview, the world can be understood through the lens of classical interpretation - understanding an object's fundamental properties, its constitution, its internal mechanics - and romantic interpretation - viewing things as they are, their form, their implicit relations to environment. And as I have just read Frankl's book, I have taken away a similar set of new concepts and insights into my worldview.</p><p>I thought of properly reviewing the book, but at the end of the day, unless you're using this material for trivia night, a summarisation will not be of <em>any value</em> whatsoever. So instead, here are my <strong>notes</strong> - things that I took away, quotes that I found interesting. Enjoy.</p><h2 id="notes">Notes</h2><p>What are some of the core ideas of Frankl's philosophy of logotherapy?</p><ul><li>Man's search for meaning is an innate driver of his existence, and not an emergent property of base needs and desires (food, sex). </li><li>Traditions are diminishing, from where man used to derive ordinary meaning. In their place, the vacuum is filled by doing what other people do (<strong>conformity</strong>) and doing what other people tell him to do (<strong>authority</strong>). Outside of this, a vacuum of meaning is sometimes substituted by the will to power (eg. authority, or its proxy, money) and the will to pleasure (food, sex).</li><li>Frankl' doesn't assert why the above meanings are less valid than pursuing an individual meaning to life. </li><li>Asking "what is the meaning of life" uncovers as uselessly abstract an answer as the question asks. “Life” does not mean something vague, but something very real and concrete, just as life’s tasks are also very real and concrete. Ultimately, the question is rendered tangible when asked in reverse - <strong>what does life mean to me</strong>?</li><li><strong>Retaliation against the abstract</strong>. Everyone has their own specific vocation or mission to carry out an assignment which demands fulfillment. He cannot be replaced, nor can his life be repeated. Thus, everyone's task is as unique as his specific opportunity to implement it. </li><li><strong>Facing towards the future</strong>. Meaning derives from an internal tension of what man is and what man has left to achieve. Like Camus' assertion of suicide being only the 'quick exit', there is potential within every man to define meaning, even in circumstances of suffering, up until the last moment of life. </li><li><strong>Meaning is transient</strong>. Just like in chess, asking what is the best chess move has no answer. It is dependent upon the circumstance - the state of gameplay, the personality of one's opponent. The meaning of life changes day by day, hour by hour, move by move. And so, asking the general meaning of the game is unimportant. </li></ul><h2 id="quotes">Quotes</h2><blockquote>Those who know how close the connection is between the state of mind of a man—his courage and hope, or lack of them—and the state of immunity of his body will understand that the sudden loss of hope and courage can have a deadly effect. The ultimate cause of my friend’s death was that the expected liberation did not come and he was severely disappointed. This suddenly lowered his body’s resistance against the latent typhus infection. His faith in the future and his will to live had become paralyzed and his body fell victim to illness—and thus the voice of his dream was right after all</blockquote><blockquote>The observations of this one case and the conclusion drawn from them are in accordance with something that was drawn to my attention by the chief doctor of our concentration camp. The death rate in the week between Christmas, 1944, and New Year’s, 1945, increased in camp beyond all previous experience. In his opinion, the explanation for this increase did not lie in the harder working conditions or the deterioration of our food supplies or a change of weather or new epidemics. It was simply that the majority of the prisoners had lived in the naïve hope that they would be home again by Christmas. As the time drew near and there was no encouraging news, the prisoners lost courage and disappointment overcame them. This had a dangerous influence on their powers of resistance and a great number of them died.</blockquote><blockquote>As we said before, any attempt to restore a man’s inner strength in the camp had first to succeed in showing him some future goal. Nietzsche’s words, “He who has a why to live for can bear with almost any how,” could be the guiding motto for all psychotherapeutic and psychohygienic efforts regarding prisoners. Whenever there was an opportunity for it, one had to give them a why—an aim—for their lives, in order to strengthen them to bear the terrible how of their existence. Woe to him who saw no more sense in his life, no aim, no purpose, and therefore no point in carrying on. He was soon lost. The typical reply with which such a man rejected all encouraging arguments was, “I have nothing to expect from life any more.” What sort of answer can one give to that?</blockquote><blockquote>What was really needed was a fundamental change in our attitude toward life. We had to learn ourselves and, furthermore, we had to teach the despairing men, that it did not really matter what we expected from life, but rather what life expected from us. We needed to stop asking about the meaning of life, and instead to think of ourselves as those who were being questioned by life—daily and hourly. Our answer must consist, not in talk and meditation, but in right action and in right conduct. Life ultimately means taking the responsibility to find the right answer to its problems and to fulfill the tasks which it constantly sets for each individual.</blockquote><blockquote>These tasks, and therefore the meaning of life, differ from man to man, and from moment to moment. Thus it is impossible to define the meaning of life in a general way. Questions about the meaning of life can never be answered by sweeping statements.<strong> “Life” does not mean something vague, but something very real and concrete, just as life’s tasks are also very real and concrete.</strong> They form man’s destiny, which is different and unique for each individual. No man and no destiny can be compared with any other man or any other destiny. No situation repeats itself, and each situation calls for a different response. Sometimes the situation in which a man finds himself may require him to shape his own fate by action. At other times it is more advantageous for him to make use of an opportunity for contemplation and to realize assets in this way. Sometimes man may be required simply to accept fate, to bear his cross. Every situation is distinguished by its uniqueness, and there is always only one right answer to the problem posed by the situation at hand.</blockquote><blockquote>To mourn for anything irrevocably lost must seem useless and foolish from the point of view of "sound common sense," and this holds also for repenting an irredeemable wrong. But for the inner biography of a man, grief and repentance do have meaning. Grieving for a person whom we have loved and lost in a sense continues his life, and repentance permits the culprit to rise again freed of guilt. The loved person whom we have grieved for has been lost objectively, in empirical time, but he is preserved subjectively, in inner time. Grief brings him into the mind's present. And repentance ... has the power to wipe out a wrong; though the wrong cannot be undone, the culprit himself undergoes a moral rebirth. This opportunity to make past events fruitful for one's inner history does not stand in opposition to man's responsibility, but in a dialectical relationship. For guilt presupposes responsibility. Man is responsible in view of the fact he cannot retrace a single step; the smallest as well as the biggest remains a final one. None of his acts of commission or omission can be wiped off the slate as if they had never been. Nevertheless, in repenting man may inwardly break with an act, and in living out this repentance—which is an inner event—he can undo the outer event on a spiritual, moral plane. <sup><a href="https://muse.jhu.edu/article/43137#FOOT79">79</a></sup></blockquote><blockquote>I consider it a dangerous misconception of mental hygiene to assume that what man needs in the first place is equilibrium or, as it is called in biology, “homeostasis,” i.e., a tensionless state. What man actually needs is not a tensionless state but rather the striving and struggling for a worthwhile goal, a freely chosen task.</blockquote><blockquote>Thus it can be seen that mental health is based on a certain degree of tension, the tension between what one has already achieved and what one still ought to accomplish, or the gap between what one is and what one should become. Such a tension is inherent in the human being and therefore is indispensable to mental well-being.</blockquote><blockquote>Man has suffered another loss in his more recent development inasmuch as the traditions which buttressed his behavior are now rapidly diminishing. <strong>No instinct tells him what he has to do, and no tradition tells him what he ought to do; sometimes he does not even know what he wishes to do. Instead, he either wishes to do what other people do (conformism) or he does what other people wish him to do (totalitarianism).</strong></blockquote><blockquote>Let us consider, for instance, “Sunday neurosis,” that kind of depression which afflicts people who become aware of the lack of content in their lives when the rush of the busy week is over and <em>the void within themselves becomes manifest</em></blockquote><blockquote>Sometimes the frustrated will to meaning is vicariously compensated for by a will to power, including the most primitive form of the will to power, the will to money. In other cases, the place of frustrated will to meaning is taken by the will to pleasure.</blockquote><blockquote>Thus it can be seen that mental health is based on a certain degree of tension, the tension between what one has already achieved and what one still ought to accomplish, or the gap between what one is and what one should become. Such a tension is inherent in the human being and therefore is indispensable to mental well-being.</blockquote><blockquote>the meaning of life, a naïve query which understands life as the attaining of some aim through the active creation of something of value. For us, the meaning of life embraced the wider cycles of life and death, of suffering and of dying.</blockquote><blockquote>There are some authors who contend that meanings and values are “nothing but defense mechanisms, reaction formations and sublimations.” But as for myself, I would not be willing to live merely for the sake of my “defense mechanisms,” nor would I be ready to die merely for the sake of my “reaction formations.” Man, however, is able to live and even to die for the sake of his ideals and values!</blockquote><blockquote>I would strictly deny that one’s search for a meaning to his existence, or even his doubt of it, in every case is derived from, or results in, any disease.</blockquote><blockquote>Sometimes the frustrated will to meaning is vicariously compensated for by a will to power, including the most primitive form of the will to power, the will to money. In other cases, the place of frustrated will to meaning is taken by the will to pleasure.</blockquote><blockquote><strong>For the meaning of life differs from man to man, from day to day and from hour to hour. What matters, therefore, is not the meaning of life in general but rather the specific meaning of a person’s life at a given moment</strong>. To put the question in general terms would be comparable to the question posed to a chess champion: “Tell me, Master, what is the best move in the world?” There simply is no such thing as the best or even a good move apart from a particular situation in a game and the particular personality of one’s opponent. The same holds for human existence. <strong>One should not search for an abstract meaning of life. Everyone has his own specific vocation or mission in life to carry out a concrete assignment which demands fulfillment. Therein he cannot be replaced, nor can his life be repeated. Thus, everyone’s task is as unique as is his specific opportunity to implement it.</strong></blockquote><blockquote>solve, the question of the meaning of life may actually be reversed. Ultimately, man should not ask what the meaning of his life is, but rather he must recognize that it is he who is asked. In a word, each man is questioned by life; and he can only answer to life by answering for his own life; to life he can only respond by being responsible. Thus, logotherapy sees in responsibleness the very essence of human existence.</blockquote><blockquote>I have termed this constitutive characteristic “the self-transcendence of human existence.” It denotes the fact that being human always points, and is directed, to something, or someone, other than oneself—be it a meaning to fulfill or another human being to encounter. The more one forgets himself—by giving himself to a cause to serve or another person to love—the more human he is and the more he actualizes himself.</blockquote><blockquote>According to logotherapy, we can discover this meaning in life in three different ways: (1) by creating a work or doing a deed; (2) by experiencing something or encountering someone; and (3) by the attitude we take toward unavoidable suffering.</blockquote><blockquote>But let me make it perfectly clear that in no way is suffering necessary to find meaning. I only insist that meaning is possible even in spite of suffering—provided, certainly, that the suffering is unavoidable. If it were avoidable, however, the meaningful thing to do would be to remove its cause, be it psychological, biological or political. To suffer unnecessarily is masochistic rather than heroic.</blockquote><blockquote>To be sure, man’s search for meaning may arouse inner tension rather than inner equilibrium. However, precisely such tension is an indispensable prerequisite of mental health. There is nothing in the world, I venture to say, that would so effectively help one to survive even the worst conditions as the knowledge that there is a meaning in one’s life. </blockquote><blockquote>When a man finds that it is his destiny to suffer, he will have to accept his suffering as his task; his single and unique task. He will have to acknowledge the fact that even in suffering he is unique and alone in the universe. No one can relieve him of his suffering or suffer in his place. His unique opportunity lies in the way in which he bears his burden.</blockquote><blockquote>When the impossibility of replacing a person is realized, it allows the responsibility which a man has for his existence and its continuance to appear in all its magnitude.</blockquote><blockquote>A man who becomes conscious of the responsibility he bears toward a human being who affectionately waits for him, or to an unfinished work, will never be able to throw away his life. He knows the “why” for his existence, and will be able to bear almost any “how.”</blockquote><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Analysing frontend data fetching patterns - MakerDAO dApp.]]></title><description><![CDATA[Frontend engineering is a minefield when it comes to learning about effective patterns. As part of my personal study, I'm reading real open-source codebases to understand the patterns in the wild. Today I've read the codebase for a decentralised finance (DeFi) dApp called MakerDAO. 
]]></description><link>https://liamz.co/blog/analysing-frontend-data-fetching-patterns-makerdao-dapp/</link><guid isPermaLink="false">5fd0a405f71aca00019cf0f6</guid><category><![CDATA[frontend]]></category><category><![CDATA[react]]></category><category><![CDATA[react.js]]></category><category><![CDATA[data fetching]]></category><category><![CDATA[state management]]></category><category><![CDATA[redux]]></category><category><![CDATA[react-hooks]]></category><category><![CDATA[single-page-apps]]></category><category><![CDATA[self-study]]></category><category><![CDATA[exploration]]></category><category><![CDATA[reading-code]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Wed, 09 Dec 2020 11:17:01 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Frontend engineering is a minefield when it comes to learning about effective patterns. As part of my personal study, I'm reading real open-source codebases to understand the patterns in the wild. Today I've read the codebase for a decentralised finance (DeFi) dApp called MakerDAO.</p>
<p>In my own personal project, T1 Gym, I just implemented React Router so I could link various day's worth of diabetic data. I'm interested in the areas of asynchronous data fetching, state management patterns (redux, hooks, contexts), routing frameworks, the different ways to check if data is loading and show a loading view. Overall, this is part of my larger goal of building great user experiences from good frontend engineering patterns.</p>
<p>This post is mostly an exploration, and is just verbatim pasted as I've done it.</p>
<p>NB: MakerDAO's engineers are sophisticated, though prioritise a functional programming style and composability. This may appear overengineered at first sight, though I assure you, probably only 20% ;).</p>
<h3 id="explorationlog">Exploration log.</h3>
<p>Codebase for frontend: <a href="https://sourcegraph.com/github.com/makerdao/mcd-cdp-portal">https://sourcegraph.com/github.com/makerdao/mcd-cdp-portal</a></p>
<p>When you load the Borrow route.<br>
<a href="https://oasis.app/borrow/owner/0x912fd21d7a69678227fe6d08c64222db41477ba0">https://oasis.app/borrow/owner/0x912fd21d7a69678227fe6d08c64222db41477ba0</a></p>
<p>The Borrow route calls the <code>VaultsProvider</code>, to get the state of <code>viewedAddressVaults</code>.</p>
<p>If <code>viewedAddressVaults.length === 0</code>, then the loading screen is rendered.</p>
<p>Where kicks off the loading of this state?</p>
<p>At a top-level, this is what the routes component tree looks like:</p>
<pre><code class="language-jsx">const dappProvidersView = async request =&gt; {
  const {
    network = networkNames[defaultNetwork],
    testchainId,
    backendEnv
  } = request.query;
  const { viewedAddress } = request.params;

  return (
    &lt;MakerProvider
      network={network}
      testchainId={testchainId}
      backendEnv={backendEnv}
      viewedAddress={viewedAddress}
    &gt;
      &lt;RouteEffects network={network} /&gt;
      &lt;TransactionManagerProvider&gt;
        &lt;NotificationProvider&gt;
          &lt;VaultsProvider viewedAddress={viewedAddress}&gt;
            &lt;ToggleProvider&gt;
              &lt;ModalProvider modals={modals} templates={templates}&gt;
                &lt;SidebarProvider&gt;
                  &lt;View /&gt;
                &lt;/SidebarProvider&gt;
              &lt;/ModalProvider&gt;
            &lt;/ToggleProvider&gt;
          &lt;/VaultsProvider&gt;
        &lt;/NotificationProvider&gt;
      &lt;/TransactionManagerProvider&gt;
    &lt;/MakerProvider&gt;
  );
};

const withDashboardLayout = childMatcher =&gt;
  compose(
    withView(dappProvidersView),
    // ...

export default mount({
  // basename ought to be set to '/borrow' and router will construct
  // these routes as basename+route

  '/': compose(
    withView(dappProvidersView),
    withView(() =&gt; &lt;Borrow /&gt;)
  ),

  '/owner/:viewedAddress': withDashboardLayout(
    route(request =&gt; {
      const { viewedAddress } = request.params;
      return {
        title: 'Overview',
        view: &lt;Overview viewedAddress={viewedAddress} /&gt;
      };
    })
  ),
  
  // ...other routes.
})
</code></pre>
<p>So for rendering the <code>/owner/:viewedAddress</code> route, a series of <code>*Provider</code> HOC's are loaded first. Let's examine the <code>VaultsProvider</code> HOC.</p>
<pre><code class="language-js">function VaultsProvider({ children, viewedAddress }) {
  const navigation = useNavigation();
  const { account, network } = useMaker();
  const { cdpTypesList } = useCdpTypes();

  const userProxy = watch.proxyAddress(account?.address);
  const viewedAddressProxy = watch.proxyAddress(viewedAddress);

  const rawUserVaultsList = watch.userVaultsList(account?.address);
  const rawViewedAddressVaultsList = watch.userVaultsList(viewedAddress);
</code></pre>
<p>The <code>VaultsProvider</code> HOC begins pretty plainly with importing some other hooks for navigation and domain-specific logic for MakerDAO smart contracts.</p>
<p>Looking for the state we are examining, <code>viewedAddressVaults</code>, it appears it is set after a chain of other variables are &quot;filled&quot; first - <code>viewedAddressProxy</code>, <code>viewedAddressVaultsList</code>, <code>viewedAddressVaultIds</code> and then finally <code>viewedAddressVaultsData</code>.</p>
<pre><code class="language-jsx">return (
    &lt;VaultsContext.Provider
      value={{
        userVaults:
          rawUserVaultsList !== undefined
            ? userVaultIds &amp;&amp; userVaultsData
              ? userVaultsData
              : []
            : userProxy
            ? undefined
            : [],
        viewedAddressVaults:
          viewedAddressProxy === undefined
            ? undefined
            : viewedAddressProxy === null
            ? []
            : viewedAddressVaultsList === undefined
            ? undefined
            : !viewedAddressVaultIds.length
            ? []
            : viewedAddressVaultsData
      }}
    &gt;
      {children}
    &lt;/VaultsContext.Provider&gt;
  );
</code></pre>
<p>Before we dig in further, let's get an understanding of what <code>watch</code> does. It looks like it's following the observable pattern of reactive state management.</p>
<p>Looking at the source, it's a fairly straightforward control flow:</p>
<pre><code class="language-js">function useObservable(key, ...args) {
  const { maker } = useMaker();
  const multicall = maker.service('multicall');
  const [value, setValue] = useState(undefined);

  useEffect(() =&gt; {
    if (!maker || !multicall.watcher) return;
    if (findIndex(args, arg =&gt; typeof arg === 'undefined') !== -1) return;

    log(`Subscribed to observable ${key}(${args &amp;&amp; args.join(',')})`);
    const sub = multicall.watch(key, ...args).subscribe({
      next: val =&gt; {
        log('Got value from observable ' + key + ':', val);
        setValue(val);
      },
      error: val =&gt; {
        log('Got error from observable ' + key + ':', val);
        setValue(null);
      }
    });

    // ...
</code></pre>
<p>Some notes:</p>
<ul>
<li>The multicall library is developed by makerdao for smart contract dApp frontends.</li>
<li>Multicall is in a sense a query library.</li>
<li>A query is identified by a key, which has a unique schema/model for its value. For example, <code>userVaultsList</code> is a query key.</li>
</ul>
<p>Digging further, I couldn't find any further mention of where <code>watch</code> was set, and hence, <code>userVaultsList</code>. So I decided to do my favourite thing and <a href="https://sourcegraph.com/search?q=repo:%5Egithub%5C.com/makerdao/+userVaultsList&amp;patternType=literal">search the makerdao Github organisation using Sourcegraph</a> instead. Voilà! It was defined in a package called <a href="https://sourcegraph.com/github.com/makerdao/dai.js/-/blob/packages/dai-plugin-mcd/src/schemas/_constants.js#L77:34">dai-plugin-mcd</a>. Here it is:</p>
<pre><code class="language-js">export const userVaultsList = {
  generate: address =&gt; ({
    dependencies: ({ get }) =&gt; {
      const cdpManagerAddress = get('smartContract').getContractAddress(
        'CDP_MANAGER'
      );
      return [
        [USER_VAULT_IDS, cdpManagerAddress, [PROXY_ADDRESS, address]],
        [USER_VAULT_ADDRESSES, cdpManagerAddress, [PROXY_ADDRESS, address]],
        [USER_VAULT_TYPES, cdpManagerAddress, [PROXY_ADDRESS, address]]
      ];
    },
    computed: (ids, addresses, types) =&gt;
      ids.reduce(
        (acc, id, idx) =&gt; [
          ...acc,
          {
            vaultId: id,
            vaultAddress: addresses[idx],
            vaultType: types[idx]
          }
        ],
        []
      )
  }),
  validate: {
    args: validateAddress`Invalid address for userVaultsList: ${'address'}`
  }
};
</code></pre>
<p>It looks like this query manager is a bit more sophisticated than I thought. Presumed operation:</p>
<ol>
<li><code>generate</code> takes the arguments we've given earlier in watch.userVaultsList(), so, the user's address.</li>
<li>it returns an object with a list of dependencies, themselves being queries that should be executed before the current query can resolve. These are <code>USER_VAULT_IDS</code>, <code>USER_VAULT_ADDRESSES</code> and <code>USER_VAULT_TYPES</code>.</li>
<li>Once these are fetched, <code>computed</code> will be called with the returning query values, and be used to compute the query data. Dependent queries are presumably cached by their key, and recomputed when dependencies change.</li>
</ol>
<h3 id="patterns">Patterns</h3>
<ul>
<li>Unique data queries that are cached by key (<code>USER_VAULT_IDS</code>, <code>USER_VAULT_ADDRESSES</code>, <code>viewedAddressVaults</code>).</li>
<li>Queries are bundled into the <code>useObservable</code> hook, which stores state using the <code>useState</code> hook and runs the query inside a <code>useEffect</code> block.</li>
<li>These queries are further abstracted away into a provider - <code>VaultProvider</code>. It seems a lot of the state management, including the Ethereum transaction flow, are also abstracted this way (<code>TransactionManagerProvider</code>).</li>
<li>Queries initially return <code>undefined</code>, which maps to a loading view in the respective page like <code>&lt;Overview/&gt;</code>.</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Observations on Lisp (pt. 1) - implementing a proof-of-work algorithm in Common Lisp.]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I've been reading the SICP classic and learning a <a href="https://twobithistory.org/2018/10/14/lisp.html">religious symbol of hacker culture – Lisp</a>. A quote to start us off-</p>
<blockquote>
<p>Lisp transcends the utilitarian criteria used to judge other languages, because the median programmer has never used Lisp to build anything practical and probably never will, yet the reverence</p></blockquote>]]></description><link>https://liamz.co/blog/observations-on-lisp-implementing-bitcoin-proof-of-work/</link><guid isPermaLink="false">5f63f5d2f71aca00019ced44</guid><category><![CDATA[lisp]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[computation]]></category><category><![CDATA[code]]></category><category><![CDATA[proof-of-work]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Fri, 18 Sep 2020 05:55:17 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I've been reading the SICP classic and learning a <a href="https://twobithistory.org/2018/10/14/lisp.html">religious symbol of hacker culture – Lisp</a>. A quote to start us off-</p>
<blockquote>
<p>Lisp transcends the utilitarian criteria used to judge other languages, because the median programmer has never used Lisp to build anything practical and probably never will, yet the reverence for Lisp runs so deep that Lisp is often ascribed mystical properties.</p>
</blockquote>
<p>What does this mean? What is it like using Lisp, what makes the experience so elegant and wholesome to some?</p>
<h4 id="thechallenge">The challenge.</h4>
<p>Let's implement a basic proof-of-work algorithm in Lisp. <a href="https://en.wikipedia.org/wiki/Proof_of_work">Proof-of-work</a> is a probabilistic algorithm to generate a proof of burning a certain amount of CPU power. It is based on hashcash, but with an adjustable difficulty. It underpins the Bitcoin network's consensus.</p>
<h4 id="gettingsetup">Getting setup.</h4>
<p>First of all, we'll need to compute hashes using SHA256. I found a package, <a href="https://github.com/sharplispers/ironclad">ironclad</a>, which does this. How do we install the package? There are a couple of package managers, I settle on one called QuickLisp for obvious reasons. This is how you import a package:</p>
<pre><code class="language-lisp">(load &quot;~/.quicklisp/setup.lisp&quot;)
(ql:quickload :ironclad)
</code></pre>
<p>Did I install it? Is this <code>package.json</code>? Nope, it's just a function call inside my Lisp script. The package is lazy-loaded <strong>at run time</strong> if it's not already downloaded. Code is data? Well, package management is code.</p>
<p>Okay, great, let's get to it. How do I compute the SHA256 digest? Reading <a href="https://github.com/sharplispers/ironclad#high-level-convenience-functions">the <code>ironclad</code> docs</a> and some StackOverflow posts, it looks like I can call <code>(ironclad:digest-sequence :sha256 *buffer*)</code> with a buffer object. Keep in mind, I know <em>nothing</em> of the Lisp type system beyond the basic types right now - numbers, symbols, lists and functions (fun fact: Lisp was the first language to have functions as <a href="https://en.wikipedia.org/wiki/First-class_function">first-class data types</a>).</p>
<p>What type is the <code>buffer</code>?</p>
<blockquote>
<p>If buffer is provided, it must be a <code>(simple-array (unsigned-byte 8) (*))</code></p>
</blockquote>
<p>Ah, a new type! I look quizically at the simple adjective...haven't arrays always been simple (conceptually speaking)? Secondly, how do we create a simple-array?</p>
<p>First thing you need to know about Lisp, is that the first item in a list is always a function application. So I try to call <code>simple-array</code> -</p>
<pre><code class="language-lisp">* (simple-array 2)

; in: SIMPLE-ARRAY 2
;     (SIMPLE-ARRAY 2)
;
; caught WARNING:
;   The function SIMPLE-ARRAY is undefined, and its name is reserved by ANSI CL so
;   that even if it were defined later, the code doing so would not be portable.
;
; compilation unit finished
;   Undefined function:
;     SIMPLE-ARRAY
;   caught 1 WARNING condition
</code></pre>
<h4 id="learningabouttypespecs">Learning about type specs.</h4>
<p>Hmm, undefined? Is <code>simple-array</code> not a function? Nope, it's a type. Here's what I've learnt so far:</p>
<ul>
<li>there are primitive types in Lisp: integers, symbols, functions, lists, arrays.</li>
<li>you can test the type using a type predicate, <code>(typep obj typespec)</code>.</li>
<li>users can define their own types using <code>deftype</code>. These are called composite types.</li>
</ul>
<p>So for example, I went off to define my own type: <code>millenial</code>. Millenials are roughly the age group born after 1997. Nowdays, we also have zoomers, but let's ignore them. This is our millenial type:</p>
<pre><code class="language-lisp">(defun age-test (yyyy) 
  (&gt; yyyy 1997))

(deftype millenial () 
  `(and 
        integer 
        (satisfies age-test)))
</code></pre>
<p>And this is testing the type predicate:</p>
<pre><code class="language-lisp">(typep  1990  'millenial) ; nil
(typep  2000  'millenial) ; T
(typep &quot;2000&quot; 'millenial) ; error, it's a string!
</code></pre>
<p>Woohoo! It runs our custom function <code>age-test</code> and fails for anything that isn't a number. But why does <code>millenial</code> not require any arguments, and why do we need to use <code>satisfies</code> to call <code>age-test</code>? The answer is, that we are defining <em>type specifications</em>, not the type predicates themselves. The specification is then transformed into predicate functions, according to the Lisp implementation. I found a great post on <a href="https://alhassy.github.io/TypedLisp.html">Typed Lisp</a> which explains this in greater detail. One other interesting thing to note - Lisp types are <a href="https://stackoverflow.com/questions/37301698/is-it-possible-to-define-a-recursive-type-in-common-lisp">not designed to support recursion</a>, which is at odds with its ubiquity elsewhere.</p>
<h3 id="discoveringlispstypehierarchy">Discovering Lisp's type hierarchy.</h3>
<p>We understand some aspects of how types are defined, now let's touch upon some more interesting aspects of the type hierarchy.</p>
<p>The type specifiers are great in Lisp. Let's examine the <code>integer</code> specifier for example:</p>
<blockquote>
<p>An integer is a mathematical integer. There is no limit on the magnitude of an integer.<br>
integer [lower-limit [upper-limit]]</p>
</blockquote>
<p>Very close to a formal definition, very far from an <a href="https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html">OO API</a>. How would we define an unsigned byte?  Remember, bytes are just numbers. A single byte digit represents $ 2^8 $ bits of information, or the numeric range, $0-255$. Representing this in code, it might look like <code>(deftype byte '(integer 0 255))</code>. And in fact, that's <a href="http://clhs.lisp.se/Body/t_unsgn_.htm">pretty close</a> to how Lisp defines it! Another elegant tidbit - the type <code>(integer 0 1)</code> is called a <a href="http://clhs.lisp.se/Body/t_bit.htm">bit</a>.</p>
<p>I remember this one profound realisation I had when I was studying RSA as a teenager, trying to understand how public-key encryption worked. At a certain point, realising that the payload was in fact, just a number, that could be multiplied like any other, blew my little adolescent mind. Lisp exposes this fact as a core axiom of its type system. Now, this appears as a beautiful syntactic expression, although doesn't necessarily reflect a performant implementation, does it?</p>
<h3 id="summary">Summary.</h3>
<p>This was part one of writing about playing with Lisp. Some things I discovered:</p>
<ul>
<li>A lazy-loading package manager that is defined all in code. Cool.</li>
<li>An expressive type system using <code>deftype</code> and typespecs.</li>
<li>An elegant type hierarchy for numbers and data.</li>
</ul>
<p>In the next post, I'll be implementing the proof-of-work algorithm. I'll also dig into some interesting elegance of composing Lisp arrays and how data type <a href="https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node49.html">specialization</a> works too.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Empathy.]]></title><description><![CDATA[The best conversation I had in 2020 was with an Uber driver for $15. He was a well-spoken man of Asiatic origin, perhaps Japanese, and spoke in those humble strokes of breath.]]></description><link>https://liamz.co/blog/empathy-1/</link><guid isPermaLink="false">5eea03b443252100014fa6cd</guid><category><![CDATA[empathy]]></category><category><![CDATA[psychology]]></category><category><![CDATA[travel]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Wed, 17 Jun 2020 14:35:22 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2020/06/uber-taxi-15---2.png" medium="image"/><content:encoded><![CDATA[<img src="https://liamz.co/blog/content/images/2020/06/uber-taxi-15---2.png" alt="Empathy."><p>The best conversation I had in 2020 was with an Uber driver for $15. He was a well-spoken man of Asiatic origin, perhaps Japanese, and spoke in those humble strokes of breath. It's odd to have such a strong connection with a total stranger, in such a timebox. And I forget how complex human beings are — a simple conversation about my diabetes device that later became a genuine empathetic connection.</p><p>Many people ask about my diabetes. I've always been open and jovial about it. Recently, I've been less inclined to explain it. Reducing your experiences down to caustic explanations for others is much easier when those experiences were positive. But the diabetes has been bad, terrible in fact.</p><p>So a simple enquiry, a touch on the nose, about my funny patch on my arm is interesting. I will show it to people because the technology is novel, and I'm happy with it.</p><p>The man responded with a precariously <em>serious</em> reaction. Which isn't to say others don't — when I tell people about this device, their reaction <em>feels</em> surface-level. This man reacted to the fact I wore these devices all the time with genuine earnest. At least, this was my impression.</p><p>"Woah." he exhaled a breath. His meter drew me in to share more — it was tranquil and thoughtful. He would interject and pose a question, and then sit and listen. At one point I believed to have overexplained myself, drowning in rhythms of my own logic-seeking, fumbling at metaphors to explain the daily experience. And he just listened, tempered in his own thought.</p><p>"You know, I cannot drink milk" he said. Something that brings my immediate reaction to say "oh yeah". I quickly retreated from my arrogance,</p><blockquote>"I have a friend who has this too, it's terrible".<br>"Yes you know, I would have terrible acidic refluxes in my stomach, for many months."</blockquote><p>At this point, I said something which triggered a genuine connection between the two of us, because his intensity of response immediately increased.</p><blockquote>“Wow, that must’ve caused you terrible anxiety.”<br>“Yes, yes! I had developed some terrible anxiety and depression from these things."</blockquote><p>The conversation continued, and I don't have to detail specifics of what he said any longer. From there, it was about my experience and his. My experience of health and individuality and eventual salience of how it's all fucking holistic. From when I would posture my leg and it would become numb, my muscles would start spasming, I wouldn't be able to sleep, and not have any libido. Going to doctors and having the same slightly jarring experience of not actually being understood. I got it. I've been slowly beginning to get it for weeks, but today it came from another person.</p><p>"I don't know why you're going to a dermatologist, you should have sorted this out months ago" says the GP. I can't explain to you that I booked the appointment before the diabetic one, because I'm an adult now, and don't have any idea how this works. I've been trying but this all seems too much. My mood, my energy, I haven't been supported in getting this through. Only after this fantastic cruise with a lot of friends do I feel somewhat myself again — after exercising every day for the past two weeks, do I finally have the energy to do things again. The lesions on my knee are about my esteem, my feeling of self. I want to feel normal, I want to feel <strong>understood</strong> or at least not be continually jarred with the experience of explaining myself. That is what I want.</p><p>This man understood. He'd been through the same. "At a certain point, I felt like I was on the precipus of death. [I mentioned libido] I lost all interest, I felt like a robot. My friend told me that I was not acting like this person I was anymore — and that is true."</p><p>He was struggling with depression and anxiety. The acid refluxes that could not be explained to him, but had suddenly become part of him, interjecting in <em>his identity</em>.</p><p>"At a certain point, I went to my doctor and I said — doctor, I cannot sleep. Every night I sleep maybe 2 or 3 hours. This pain that I feel in my stomach, it is unbearably painful. And the doctor told me, there is no cure for acid reflex. I thought to myself — after all of this time, there is no cure? How can this be."</p><p>And so he said, "I will go to research on the computer, for 10, maybe 12 hours, however long it takes. After 5 hours I sat there, and I came to the strong conclusion, that these issues were in my mind. I started practicing transcendental meditation." The terrible lethargy he experienced, gone. "It has been 6 years since I went in 2014. At one point, I thought, this is how it is now. It will never change".</p><p>It's hard to explain how such a short conversation with a stranger can mean so much. Or how it can elucidate feelings I never knew I needed, and reactions I never understood I had. I don't like talking about my health to my friends, as it feels like a dead end most the time — but more than a deadend, there's an impossibility of genuine empathy there. The things I've experienced, in terms of deteriorating function, age, whatever — these are things people cannot relate to. And the treatment I've gotten from Western healthcare has neither been useful — the body is a whole. Mental and physical are the same system, and we must treat them holistically. I feel better than ever this past two weeks, and it's because of the additional energy I get from exercising. Something about it jostles my system into action, and I can think clearly. This man finds it was meditation. In either case, we gotta do what works for us. And when it comes to other people, maybe you shouldn't tell them things about yourself. The fracturing, and further healing of one's physical and mental health, requires empathy. And the degree to which that empathy is present depends — though the power it has is insurmountably demonstrated to me today.</p><p>I gave the man the maximum tip I could. I'd never see him again, but the feeling he left me was lasting. Empathy is a powerful experience, being understood. If you think you understand yourself, try feeling understood to begin with, then observe. Likewise, all of this came about from the most infinitesimal of reactions. Something as nominal as the tone of earnestness fostered a connection I cannot forget. </p><h3 id="epilogue">Epilogue</h3><p>This is Article #5, and it's about empathy. This is, by far, the most personal thing I've ever published. It's actually something I wrote <em>way back</em> in January, pre-corona. It was such a powerful moment that I wrote about it as soon as I left the car. Now, practicing as a writer, I feel like it's worth publishing. Empathy, <em>real empathy</em>, is a powerful experience.</p>]]></content:encoded></item><item><title><![CDATA[Every Day. A Little More Dali.]]></title><description><![CDATA[I watched an interview of Dali yesterday and came across this beautiful quote. In response to "what did the famous painter enjoy doing every day?", his answer was simple.]]></description><link>https://liamz.co/blog/every-day-a-little-more-dali/</link><guid isPermaLink="false">5edb106e43252100014f9fcf</guid><category><![CDATA[culture]]></category><category><![CDATA[internet culture]]></category><category><![CDATA[identity]]></category><category><![CDATA[art]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Tue, 16 Jun 2020 05:49:16 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2020/06/every-day-a-little-bit-more-5.png" medium="image"/><content:encoded><![CDATA[<img src="https://liamz.co/blog/content/images/2020/06/every-day-a-little-bit-more-5.png" alt="Every Day. A Little More Dali."><p></p><p>How many friends would you say are healthy? I feel quite comfortable in a crowd, safe being around others. But in my day-to-day life, I only sustain deep connection with a few people. Perhaps a small entourage of 5 people, a closer friend group of 10, but beyond that, I don't feel like I have an identity.</p><p>I don't mean to say I lack identity. I quite enjoy coding, slacklining, coffee, people-watching and immersing myself in Wikipedia articles on topics I have no understanding in. But more recently I've been observing something - if I pull myself apart from the groups I'm in, a bright side of me is gone, and habits are all that remains. When I'm in real solitude, the only thing that inviscerates is the art gallery. Ordering coffee, people-watching, these experiences are as novel as grocery shopping. Interpreting art is pure in its subjectivity, the allure of slipping out of monotony and into your own individual viewpoint.</p><p><em>"What do you enjoy doing most?"</em> the interviewer asks to Salvador Dali. He responds — "<em>Becoming every day, a little more Dali. In the beginning of my life, I was a little more Napoleon. First I wanted to be a woman cooking. Second, like becoming Napeleon. Later, now like becoming Dali. Now, is every day more Dali." </em>How did this emerge?</p><blockquote>In 1955 Dalí drove a Rolls Royce Phantom packed with 500 kilograms of cauliflower from his home in Spain to the Sorbonne in Paris to deliver a lecture.<br><br>Dalí told journalist Mike Wallace he chose the cauliflower because he was fond of its relationship to the Fibonacci Sequence. Dalí loved cauliflowers and other vegetables that displayed the golden mean. </blockquote><p>Identity is a woven fabric, not a smoothly moulded metal. On it, each individual wears and bears the designs of the artifactor – on a platform, it is the feature. Where Instagram allows the artist, Facebook permits the writer. Twitter enjoys the shitstir, who fans the flame of fire. Only on our own do we own what we make. To Dali it wasn't just his paintings for painting's sake.</p><p>Dali made a name for himself. </p><p><em>"Not the painting, not the clowning. The painting, the clowning, the showmanship, the technique - everything is only one manner for expressing the total personality of Dali".</em></p><h3 id="epilogue">Epilogue</h3><p>This was a merger of two incomplete pieces on identity. The first was a foray into the internet as the new art gallery, where you can redefine yourself in the endless stream of groups, pages, and subreddits, as participant and viewer. The second was a pose on Dali's fetishisation of his own identity: the individual, self-defined, ever-evolving, handled only by name: Dali. I encourage you to watch <a href="https://www.youtube.com/watch?v=YwMs9HBFp_4">the original interview</a>. </p><p>This is article #4 in my habit to create more writing.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Anti-Social Social Media]]></title><description><![CDATA[The year is 2020. The president of the United States is posting the latest memes about politics and hiding in a bunker. The rest of the United States are posting the latest memes about politics and trying to destroy such bunker.]]></description><link>https://liamz.co/blog/anti-social-social-media/</link><guid isPermaLink="false">5edf854d43252100014fa251</guid><category><![CDATA[culture]]></category><category><![CDATA[analysis]]></category><category><![CDATA[poetry]]></category><category><![CDATA[reflection]]></category><category><![CDATA[internet culture]]></category><category><![CDATA[instagram]]></category><category><![CDATA[facebook]]></category><category><![CDATA[twitter]]></category><category><![CDATA[discord]]></category><category><![CDATA[telegram]]></category><category><![CDATA[memes]]></category><category><![CDATA[identity]]></category><category><![CDATA[newsletters]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Tue, 09 Jun 2020 23:00:00 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2020/06/antisocial-social-media.png" medium="image"/><content:encoded><![CDATA[<img src="https://liamz.co/blog/content/images/2020/06/antisocial-social-media.png" alt="Anti-Social Social Media"><p></p><p><strong>The year is 2020.</strong> Twitter mobs force brands to have political positions. You post something, it gets taken out of context, and a lynch mob is sent to get you. The president of the United States is posting the latest memes about politics and hiding in a bunker. The rest of the United States are posting the latest memes about politics and trying to destroy such bunker.</p><p>My roommate downloads Tinder. She gets 80 matches in the first night. Every man and his dog are there. They built the AI to find the best profile pic, but forgot the AI to find the best profile to pick. She filters through matches like they are job applicants. Meanwhile, the men shotgun the wall, mostly shooting themselves in the foot. Tinder is now the world's most played mobile game. </p><p>"Do it for the gram" crosses over from irony to self-fulfilling prophecy. I start doing new things for my new god, the <a href="https://www.instagram.com/">Gram</a>. Pride and Envy are celebrated here, and there are many followers. We all "love" each other here. Although ❤️ and 😘️ mean different things, HAHA. The people who are loved most are called "the influencers", although I've never met one. They must be busy influencing the others. My real name can only be changed every 14 days. Odd, but fair.</p><p>We meet a man on campus, he doesn't know his neighbours. He says he only chats with the checkout chicks. I know this feeling from Holland, except the Dutch checkout chicks didn't talk. Hahahah. This man comes from a Romanian village. I don't think they have checkouts there. He misses the local <em>grandma</em> who'd hold him accountable. Maybe he'll miss the checkout chicks when he's sent back?</p><hr><h3 id="epilogue">Epilogue</h3><p>There's no strong epilogue here, because this one was more just freeform absurdity. Some observations:</p><ul><li>The Internet is still such a weird and wacky place. I remember when memes were just a thing for nerds, now they're a cute way to get in touch with people (and voters! /s). </li><li>I miss <a href="https://www.ribbonfarm.com/2020/01/23/being-your-selves-identity-rd-on-alt-twitter/">pseudonymity</a>. It feels like social media is overcrowded with ego, especially Twitter and hot takes. </li><li>Facebook groups are especially cool nowadays. I'm part of some weird ones - "a group where we all pretend to be ants in an ant colony" which <a href="https://slate.com/culture/2020/05/facebook-ants-roleplay-coronavirus-biologist-interview.html">got famous</a>, "a group where you can only say Same" where you actually get banned for commenting anything but same,<strong> </strong>Aesthetic Function Graphposting (where I see cool maths art), Programmer NULLposting (where we talk shit about code, the most stupid ways to implement isEven), and a bunch of other X-posting varieties for TV shows. </li><li>Public Discord/Telegram's are still spammy hellholes.</li><li>Reddit has too much of a hivemind, Twitter is a wildcard echo chamber, sometimes amazing links, othertimes just a shouting match.</li><li>I miss blogs, although it appears more and more people are starting <a href="https://substack.com/">Substack newsletters</a> in their place. </li></ul><p>My birthday is this week. Social media is only 15 years young. I forget that only in 2005, it was blogs and comment systems. There will be better, less toxic, less ego-driven, more humanist platforms to come. And I cannot wait to build them. </p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Building Habits, Feedback Loops]]></title><description><![CDATA[<p>I always despised people that went to the gym. The idea of training inside a box, paying money to do so, instead of exercising outside just <em>baffled</em> me. Until I got a job. Then the gym became a product - walk in, walk out, same temperature, same weather. A homogenous</p>]]></description><link>https://liamz.co/blog/building-habits/</link><guid isPermaLink="false">5ed856a043252100014f9cfb</guid><category><![CDATA[habits]]></category><category><![CDATA[psychology]]></category><category><![CDATA[design]]></category><category><![CDATA[goals]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Fri, 05 Jun 2020 04:21:29 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2020/06/IMG_2679--1--1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://liamz.co/blog/content/images/2020/06/IMG_2679--1--1.jpg" alt="Building Habits, Feedback Loops"><p>I always despised people that went to the gym. The idea of training inside a box, paying money to do so, instead of exercising outside just <em>baffled</em> me. Until I got a job. Then the gym became a product - walk in, walk out, same temperature, same weather. A homogenous environment, in many locations, where I could just work on myself. </p><p>For the matter, I also disliked runners. Perhaps it's a trait of mine, but doing something as a means to an end just seems incredibly boring. I mentioned it to my grandmother one time, and she pointed out "When we were younger, you didn't see these people running about in their lycra. They didn't need to." They may have stronger working class roots than I do—as opposed to white collar workers, who just accrue sedentary debt. </p><p>Nonetheless, running outside is certainly less artificial than running inside. When the coronavirus hit, all the gyms shut down. After all these years of refusing this institution, having it forcibly removed from my life after 2 months was ironic. So, I began running, for real this time. That smacked me hard in the face; the treadmill has a linear difficulty curve, real terrain is bumpy. I couldn't run up the hill to save my life. Oddly enough, one of the first techniques that gave me an order-of-magnitude advantage was breathing properly – deep undulating breaths. </p><p>I've been running 3 days a week for 3 months now. Safe to say, this is now my longest <em>running</em> habit. This may seem ridiculous, how can you live so long without understanding how to do habitually do something, how to form a behaviour and change your life? Motivation is a funny thing. Americans have all sorts of products around this problem, so I know I'm not alone. </p><blockquote>We are what we repeatedly do. Excellence, then, is not an act, but a habit</blockquote><p>Most good adages seem to be cliché, which implies how useless they are without story. The above is a misquote of Artistotle, but I find the general idea repeated by everyone. <a href="https://www.newyorker.com/magazine/2011/07/25/mastering-the-machine">Hedge fund managers</a>, Aussie instagram artists <a href="https://www.youtube.com/watch?v=H8ih1_EkVOo">like Struthless</a> - they all repeat the same idea: if you want to get good at something, habits are key. </p><p>So what went into running that makes it something I'm more than motivated to do, every week?</p><hr><p>The most difficult part of forming a habit is everything. They say take little steps. </p><ul><li>I began going to the gym, <em>on a cruise</em>. It was 2mins walk from my room, and the rest of the day was spent drinking and hanging with friends. That's pretty easy if you ask me.</li><li>When we got off, I decided I'd join a gym. It took a bit of research to find one, before I just decided to do it. I selected Fitness First, on the basis they had a sauna - I love saunas, I can't have one at home, so I considered it a great reward as well as a connection to my family friends in Finland.</li><li>Going to Fitness First meant I was close to a shopping centre. Buying a gym bag that would always hold some spare jellybeans (diabetes), as well as extra gym clothes so I wasn't laundrying all the time - these things were essential.</li><li>Lastly, when FF shut down and we had to work from home, I had to scope out a running route. I had the other pieces to continue this valuable routine, now I had to replace the treadmill. The beauty of a treadmill is it <strong>closes</strong> the feedback loop - with the same settings, the same timer, you can be sure of your progress during and after every session. <em>Running in circles</em> is quite literally, demotivating. </li></ul><p>I don't like to underestimate the emotional quality of this habit. My running route takes me through <a href="https://en.wikipedia.org/wiki/Toowong_Cemetery">a cemetery</a> opened in 1871, which is <em>very</em> old for Australia. I overlook the city sunrise in the early mornings, and weave through ornate graves of governors and Greek orthography in the arvo's. Some days I will pass into the Brisbane Botanic Gardens, immersing into a rainforest climate of 18 degrees, or take a meditative pause inside the Japanese gardens. </p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2020/06/IMG_2679--1-.jpg" width="3024" height="4032" alt="Building Habits, Feedback Loops" srcset="https://liamz.co/blog/content/images/size/w600/2020/06/IMG_2679--1-.jpg 600w, https://liamz.co/blog/content/images/size/w1000/2020/06/IMG_2679--1-.jpg 1000w, https://liamz.co/blog/content/images/size/w1600/2020/06/IMG_2679--1-.jpg 1600w, https://liamz.co/blog/content/images/size/w2400/2020/06/IMG_2679--1-.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2020/06/8D152AB9-20EA-456E-B1F2-2DAB35F6CEEA--2-.jpg" width="1125" height="2000" alt="Building Habits, Feedback Loops" srcset="https://liamz.co/blog/content/images/size/w600/2020/06/8D152AB9-20EA-456E-B1F2-2DAB35F6CEEA--2-.jpg 600w, https://liamz.co/blog/content/images/size/w1000/2020/06/8D152AB9-20EA-456E-B1F2-2DAB35F6CEEA--2-.jpg 1000w, https://liamz.co/blog/content/images/2020/06/8D152AB9-20EA-456E-B1F2-2DAB35F6CEEA--2-.jpg 1125w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2020/06/IMG_2619--1-.jpg" width="3024" height="4032" alt="Building Habits, Feedback Loops" srcset="https://liamz.co/blog/content/images/size/w600/2020/06/IMG_2619--1-.jpg 600w, https://liamz.co/blog/content/images/size/w1000/2020/06/IMG_2619--1-.jpg 1000w, https://liamz.co/blog/content/images/size/w1600/2020/06/IMG_2619--1-.jpg 1600w, https://liamz.co/blog/content/images/size/w2400/2020/06/IMG_2619--1-.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2020/06/IMG_2743--1-.jpg" width="3024" height="4032" alt="Building Habits, Feedback Loops" srcset="https://liamz.co/blog/content/images/size/w600/2020/06/IMG_2743--1-.jpg 600w, https://liamz.co/blog/content/images/size/w1000/2020/06/IMG_2743--1-.jpg 1000w, https://liamz.co/blog/content/images/size/w1600/2020/06/IMG_2743--1-.jpg 1600w, https://liamz.co/blog/content/images/size/w2400/2020/06/IMG_2743--1-.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2020/06/IMG_2792--1-.jpg" width="3024" height="4032" alt="Building Habits, Feedback Loops" srcset="https://liamz.co/blog/content/images/size/w600/2020/06/IMG_2792--1-.jpg 600w, https://liamz.co/blog/content/images/size/w1000/2020/06/IMG_2792--1-.jpg 1000w, https://liamz.co/blog/content/images/size/w1600/2020/06/IMG_2792--1-.jpg 1600w, https://liamz.co/blog/content/images/size/w2400/2020/06/IMG_2792--1-.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://liamz.co/blog/content/images/2020/06/IMG_2620--1-.jpg" width="3024" height="4032" alt="Building Habits, Feedback Loops" srcset="https://liamz.co/blog/content/images/size/w600/2020/06/IMG_2620--1-.jpg 600w, https://liamz.co/blog/content/images/size/w1000/2020/06/IMG_2620--1-.jpg 1000w, https://liamz.co/blog/content/images/size/w1600/2020/06/IMG_2620--1-.jpg 1600w, https://liamz.co/blog/content/images/size/w2400/2020/06/IMG_2620--1-.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>I wouldn't enjoy running as much without this attachment, though I still did it. Analysing the above, the difficulty was getting into it. I needed good weather, I needed clean gym clothes, and most of all, I needed jellybeans. But more abstractly, I actually needed the gym.</p><p>What I didn't know about habits was the essence of the feedback loop. I was well-aware that exercise was <s>good</s> amazing—the rush of endorphins, dopamine, jumpstarting my day with energy and arousal. But I had no route. Albeit I wasn't running in circles, but there was no sense of progress. And frankly, I didn't have a clue of how to choose one.</p><p>Nowadays I run the same route, on Monday's, Wednesday's and Friday's. I'm experimenting with varying my pace, breathing, and learning how much the heat factors into exhaustion (hint: for this half-brit, a lot). I find improved stamina when I'm distracted by thoughts, and I don't know why. Some days I'm arduously occupied by the run. </p><p>So how did I form this habit?</p><ol><li>Decided I wanted something - running.</li><li>Started small - running at a gym on a cruise, 2mins from my room.</li><li>Feedback - endorphins, alertness.</li><li>Bought tools so I could do the thing more with less effort (leverage) - gym membership.</li><li>Iterated on that core idea - going to a gym every morning before work.</li><li>Feedback - feeling happier, fitter. Motivated.</li><li>Rewarding myself - sauna and iced coffee from supermarkets.</li><li>Bought leverage - gym clothes, bag.</li><li>Feedback - routine is now even easier.</li><li>Iterated on that core idea - ran a route around the neighbourhood one day.</li><li>Iterated further - decided on a home running route.</li><li>Reward - more beauty and novelty in my day-to-day.</li><li><strong>Kept running.</strong></li></ol><h3 id="final-thoughts">Final thoughts</h3><p>Feedback loops?</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2020/06/image.png" class="kg-image" alt="Building Habits, Feedback Loops"></figure><p></p><p><em>Thanks to <a href="https://owls.io/">Alec</a>, <a href="https://jmcph4.github.io/">Jack</a>, Bec, and Mum for reviewing the draft and feedback.</em></p><p></p>]]></content:encoded></item><item><title><![CDATA[How bZX got hacked for $330K (cc: flash loans and Kyber)]]></title><description><![CDATA[bZX was 'hacked' recently, and it's quite interesting as a milestone for decentralized finance. Featuring a $1M flash loan, price manipulation, and on-chain price oracles (Kyber). All on the week after "$1 billion dollars in decentralized finance". Let's dig in!]]></description><link>https://liamz.co/blog/how-bzx-got-hacked-for-330k-cc-flash-loans-and-kyber/</link><guid isPermaLink="false">5e48c7f243252100014f9a97</guid><category><![CDATA[defi]]></category><category><![CDATA[bzx]]></category><category><![CDATA[ethereum]]></category><category><![CDATA[blockchain]]></category><category><![CDATA[flash-loans]]></category><category><![CDATA[kyber-network]]></category><category><![CDATA[decentralised finance]]></category><category><![CDATA[price oracles]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Sun, 16 Feb 2020 14:08:22 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2020/02/EQ1r1erU8AEaG6W.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://liamz.co/blog/content/images/2020/02/EQ1r1erU8AEaG6W.jpeg" alt="How bZX got hacked for $330K (cc: flash loans and Kyber)"><p>bZX was 'hacked' recently, and it's quite interesting as a milestone for decentralized finance. Featuring a $1M flash loan, price manipulation, and on-chain price oracles (Kyber). All on the week after "$1 billion dollars in decentralized finance". Let's dig in!</p><h3 id="overview">Overview</h3><ul><li>What is bZX and margin lending</li><li>How does the price oracle work</li><li>Why is it bad to use Uniswap/on-chain feeds for this</li><li>How did flash loans make this happen?</li></ul><h3 id="what-is-bzx-and-margin-lending">What is bZX and margin lending</h3><p>bZX is a protocol for margin trading, a branch of trading. In normal trading, you try to make a profit/loss from the fluctuations in the price of an asset. Because this is DeFi, those assets are tokens. </p><p>If the token goes up in value, you might sell. If it goes down to 0, you've lost your money. A trader tries to predict the market.</p><p><a href="https://www.binance.vision/economics/what-is-margin-trading">Margin trading</a> is the same concept, with a multiplier. You might think ETH will go up (<em>long position</em>), but not have enough capital to invest. So you take out a <em>leveraged </em>position - where you invest 10 ETH with 10x leverage, and get an effective balance of 100 ETH. If the price goes up, you can close the position and make 10x what you normally would've without the leverage. However if the price goes down, your position becomes at risk of liquidation, since the collateral you've put down is worth less than the 10% of the original 100 ETH.</p><p>Margin trading requires that you have the asset you want to leverage, whereas <strong>margin lending</strong> means it's just borrowed for whatever you have. It's as simple as that.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2020/02/image.png" class="kg-image" alt="How bZX got hacked for $330K (cc: flash loans and Kyber)"><figcaption>A nice visual taken from bZX's Fulcrum trade dApp.</figcaption></figure><h3 id="the-need-for-price-oracles">The need for price oracles</h3><p>For these protocols to work, we need information about the price of the assets, so we can decide the value of the positions. This is commonly called a "price oracle", because when we first started doing this on the blockchain, getting external data felt like dark magic. Nowadays at tBTC, we call it a "price feed".</p><p>Price oracles are used everywhere in decentralized finance. The <a href="https://makerdao.com/">DAI stablecoin</a> is stable precisely because we can determine how much ether "is in" a US dollar, and establish a cryptoeconomic system of checks and balances around that. <a href="https://www.tokensets.com/">Set Protocol</a>, which tokenises a portfolio (eg. 50% ETH, 50% BTC), uses a price feed to determine when portfolios need rebalancing. </p><p>In both of Maker and TokenSets, their oracles are <em>off-chain</em>. Meaning, the price data is taken from an external set of sources like centralized exchanges (Coinbase, Binance, etc.), and <a href="https://community-development.makerdao.com/makerdao-mcd-faqs/faqs/oracles#what-is-a-medianizer">medianized and whatnot</a> into an on-chain value. </p><h3 id="bzx-relying-on-uniswap">bZX relying on Uniswap</h3><p>In contrast, bZX protocol relied on some on-chain price sources, through the Kyber Network of reserves. </p><p>A brief explainer: Uniswap is an automatic market maker (AMM), meaning trades are instant. When someone wants to trade a token for another, the price is determined automatically, and the tokens come out of a pool. Thus, you can get the price of a Uniswap trade in advance, and use it as a price reading for a token.</p><p>The danger of using <em>any </em>on-chain price feed, is attackers can manipulate the price (see <a href="https://twitter.com/uniswapexchange/status/1098295223480918023?lang=en">this Twitter thread with Uniswap</a> for more). Consider the scenario:</p><ol><li>Attacker takes out ETH position with 10x leverage, going short (believing ETH will decrease in price).</li><li>Attacker makes trade on Uniswap, selling ETH, reducing the ETH price by 2%.</li><li>Attacker's position is now stronger due to the price change. They close their position and receive 120% their collateral.</li><li>Attacker makes the reverse trade on Uniswap, buying their ETH back.</li><li>Attacker makes a profit of their 120% collateral, minus the Uniswap trading fees of 0.3%.</li></ol><p>Now there is one major impediment to this attack - it requires a very <strong>large</strong> trade to shift the price of the ETH pair on Uniswap. While that trade is recouped (save for the trading fee), it is spare capital that many don't have....unless?</p><h3 id="enter-flash-loans">Enter: flash loans</h3><p><strong>Flash loans</strong> are the <u>coolest</u> thing out there in decentralized finance. From the wonderful folks at <a href="https://aave.com/">Aave Protocol</a> (if you ever get a chance, say g'day to Jordan; great guy), flash loans are the key ingredient to the bZX hack. And they're so simple.</p><p><strong>Flash loans are loans, without collateral. </strong></p><p>A flash loan is requested, issued, and paid back, all in <u>one</u> transaction. There's no collateral requirement because the loan itself doesn't <em>really exist</em>. As soon as the tokens are loaned, they're used and then paid back. Otherwise the transaction fails and the loan was never created in the first place. The only requirement is payment of a very small fee, and you can lend insane amounts.</p><h3 id="the-steps-to-making-300-000-from-bzx">The steps to making $300,000 from bZX</h3><p>Getting a decentralised loan is cool, but you know what's cooler? Getting a decentralised loan of a million dollars.</p><!--kg-card-begin: markdown--><p>Transaction <a href="https://etherscan.io/tx/0xb5c8bd9430b6cc87a0e2fe110ece6bf527fa4f170a4bc8cd032f768fc5219838">0xb5c8bd9430b6cc87a0e2fe110ece6bf527fa4f170a4bc8cd032f768fc5219838</a>.</p>
<ol>
<li>Get a flashloan of 10,000 ETH ($1,000,000) from dYdX.</li>
<li>Lend 50% on Compound, 50% on bZX.</li>
<li>Borrow 112 WBTC from Compound, using the ETH collateral in #2.<br>
i. WBTC is a very low-liquidity coin, owing to its small supply. This means  it's very easy to manipulate in price.</li>
<li>Short WBTC on bZX with 2500 ETH, 5x leverage.</li>
<li>Sell 112 WBTC on Uniswap, push down the price.</li>
<li>Close position, make profit.</li>
<li>Withdraw ETH from Compound/bZX and repay loan.</li>
</ol>
<p><em>Copied from <a href="https://www.reddit.com/r/ethtrader/comments/f4bugn/hacker_makes_360000_eth_from_a_flash_loan_single/fhqo8ff/">@orm12345 in r/ethtrader</a></em></p>
<!--kg-card-end: markdown--><p>And that's how the hacker (in the ingenious sense of the word) made $300,000 for the sum total of $9 in tx fees.</p><h3 id="the-pending-investigation-from-bzx-">The pending investigation from bZX.</h3><p>So far, bZX are doing their own internal investigation. There are claims they aren't using Uniswap, which is true. They aren't using it <em>directly</em>. Instead, <a href="https://sourcegraph.com/github.com/bZxNetwork/bZx-monorepo/-/blob/packages/contracts/contracts/oracle/BZxOracle.sol#L1408:18">in BzxOracle</a>, they call the Kyber Network to get an expected rate (ie. price). </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2020/02/image-1.png" class="kg-image" alt="How bZX got hacked for $330K (cc: flash loans and Kyber)"><figcaption>"Various updates and improvements" is the new "oops I killed it"</figcaption></figure><p>Kyber is a liquidity network, which means it connects multiple sources of liquidity from 0x, <a href="https://blog.kyber.network/towards-the-single-liquidity-endpoint-for-defi-important-updates-for-kyber-bridge-reserves-91a95e626b2f">Uniswap</a>, etc.....oh.</p><p><code>getExpectedRate</code> likely calls into Uniswap. And because WBTC is such low liquidity, . You can't tell from Kyber's docs, or code, because their actual Uniswap integration is half-deployment half-approved-by-a-DAO-in-idk-when. So I'm going to leave it up to the sleuthers - their UniswapReserve bridge is deployed at <a href="https://etherscan.io/address/0x31e085afd48a1d6e51cc193153d625e8f0514c7f">0x31e085afd48a1d6e51cc193153d625e8f0514c7f</a>. </p><h2 id="conclusion">Conclusion</h2><p>I hope you enjoyed this as much as I did. For many of us, it's the first visceral introduction into a couple of things - trusting DeFi protocols blindly, the assumption-breaking power of flash loans (what, I can lend $1M??), and watching chaotic neutral hackers reap a real profit (that's more than a bug bounty). </p><p></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[How to design modular smart contracts in Solidity]]></title><description><![CDATA[In this article, I'll describe how you can modularise your smart contracts using something called the target pattern. Using standard Solidity, you will learn how to rewrite your brittle, tighly-coupled calls to clean modules and separation of concerns, using abi.encodeSelector and target.call(data)]]></description><link>https://liamz.co/blog/how-to-design-modular-smart-contracts-in-solidity-using-the-target-pattern/</link><guid isPermaLink="false">5d591c7a60535e000118b1d9</guid><category><![CDATA[solidity]]></category><category><![CDATA[daos]]></category><category><![CDATA[ethereum]]></category><category><![CDATA[analysis]]></category><category><![CDATA[architecture]]></category><category><![CDATA[token curated registries]]></category><category><![CDATA[patterns]]></category><category><![CDATA[tcrs]]></category><category><![CDATA[tutorials]]></category><category><![CDATA[evm]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Tue, 20 Aug 2019 12:19:05 GMT</pubDate><content:encoded><![CDATA[<p>In this article, I'll describe how you can modularise your smart contracts using something called the <strong>target pattern</strong>. Using standard Solidity, you will learn how to rewrite your brittle, tighly-coupled calls to clean modules and separation of concerns, using <code>abi.encodeSelector</code> and <code>target.call(data)</code>. To do this, we're going to look at HumanityDAO as an example - and how they separated governance from the registry, using the target pattern. Let's dig in!</p><!--kg-card-begin: markdown--><h3 id="humanitydaoanintroduction">HumanityDAO: an introduction</h3>
<p><a href="https://www.humanitydao.org/">HumanityDAO</a> is a DAO whose purpose is to certify humans - ie. maintain a registry that says &quot;you're real&quot;. It's existentially reassuring and also quite useful in combatting Sybil attacks. In my current work, I'm building something like decentralised reddit - using the registry, you can piggyback off of work done by other DAO's to combat spam (as a basic example). You can see how an entire ecosystem can flourish once we start adopting these patterns.</p>
<p>But aside from HumanityDAO being a great dapp, it is also the first example of modular Solidity design I've seen in the wild. But <em>what does modular refer to in this context</em>? And <em>how do we achieve it</em>?</p>
<h3 id="modulesinhumanitydao">Modules in HumanityDAO</h3>
<p>HumanityDAO maintains a <a href="https://github.com/marbleprotocol/humanity/blob/f58f173b13eda2fa952a5d0fd849942ba5653c7c/contracts/HumanityRegistry.sol"><strong>registry</strong></a> of humans which you add to and query, called <code>HumanityRegistry</code>. The registry itself only operates over a single mapping, <code>mapping (address =&gt; bool) public humans</code>. Here's the main function for adding entries:</p>
<pre><code class="language-js">function add(address who) public {
    require(msg.sender == governance, &quot;HumanityRegistry::add: Only governance can add an identity&quot;);
    require(humans[who] == false, &quot;HumanityRegistry::add: Address is already on the registry&quot;);

    _reward(who);
    humans[who] = true;
}
</code></pre>
<p>Governance is the next module we will look at, which deals with <strong>proposals</strong> and <strong>voting</strong>. This is the basic flow:</p>
<ol>
<li><code>propose(address target, bytes memory data)</code> begins a new proposal. It creates a <code>Proposal</code>, adds it to the list, and emits an event.</li>
<li>Users call <code>voteYes(uint proposalId)</code> and <code>voteNo(uint proposalId)</code> to stake their tokens in passing/failing the proposal</li>
<li>When the voting period has elapsed, <code>finalize(uint proposalId)</code> can be called. If <code>proposal.yesCount &gt; proposal.noCount</code>, then <code>target</code> is called with <code>data</code></li>
</ol>
<p>This last step I'm going to refer in this guide as the <strong>target pattern</strong> for simplicity. It's not a new paradigm of programming - but if we're going to engineer well, then we have to have common language.</p>
<h3 id="evmcallingcontractssendingmessages">EVM: calling contracts, sending messages</h3>
<p>To explain briefly - Ethereum contracts execute in the EVM, which is a <strong>message-passing</strong> execution environment. So when you send 10 wei to an address, you're sending a message that says <code>{ from: me, to: 0x123456789, value: 10 }</code>. And when we're executing a call on a contract, we're doing the same, except attaching <code>data</code> - so now the message looks like <code>{ from: me, to: 0x123456789, data: &quot;0xcafebabe&quot;, value: 10 }</code>. What is this data? Well, it's a call encoded according to the Solidity application binary interface (or ABI, for short).</p>
<p>The message construct is nice, because it means sending ether and calling a contract are no different. Sending money to a user's wallet address, and sending money to a contract, look the same - the only difference is, the contract's address isn't generated from a public key (rather from a nonce).</p>
<p>Because we're in blockchain, and we'd rather refer to things immutably, methods in contracts are referred to by their <em>selector</em>. The selector is just a portion of the hash of the function's signature.</p>
<h3 id="thetargetpattern">The <code>target</code> pattern</h3>
<p>The target pattern is quite simple, but hasn't been widely used because Solidity has these special names for things. It can also be called dynamic dispatch (Ruby, Obj-C), callbacks (JS), whatever you want ;P</p>
<p>It basically consists of:</p>
<ul>
<li>the module you're building on eg. governance</li>
<li>the thing you're implementing eg. a registry</li>
<li>the target integration point - ie. passing a proposal will add to the registry</li>
</ul>
<p>We're going to learn how to achieve this, from the example of HumanityDAO.</p>
<p>To recap, <strong>our goal</strong>: to add an entry to the registry, after it has been voted in by governance.</p>
<p>So here are the two pieces of the puzzle, the governance and registry modules, before we put them together:</p>
<pre><code class="language-js">contract Registry {
    mapping (address =&gt; bool) public humans

    function add(address who) public {
        require(msg.sender == governance, &quot;HumanityRegistry::add: Only governance can add an identity&quot;);
        humans[who] = true;
    }
}
</code></pre>
<pre><code class="language-js">contract Governance {
    function propose(address target, bytes memory data) public returns (uint) {
        uint proposalId = proposals.length;
        Proposal memory proposal;
        proposal.target = target;
        proposal.data = data;
        proposals.push(proposal);
    }
    
    function vote() public { /* ... */ }

    function finalize(uint proposalId) public {
        Proposal storage proposal = proposals[proposalId];
        require(proposal.result == Result.Pending, &quot;Governance::finalize: Proposal is already finalized&quot;);

        if (proposal.yesCount &gt; proposal.noCount) {
            // Call the target contract with the data
            proposal.target.call(proposal.data);
        }
    }
}
</code></pre>
<p>We can add to the registry using <code>Registry.add</code>. Governance is based on submitting a proposal with <code>propose</code>, voting on it, and then calling <code>finalise</code> and passing/failing it. <strong>If the proposal passes</strong>, we <code>call</code> the <code>target</code> contract with the calldata in <code>data</code>.</p>
<p>So how do we construct this calldata? You would think it's very complex, being Solidity, with maybe a sprinkle of assembly and some obscure errors.</p>
<p>Nope! We can do this <em>very</em> simply with something called <code>abi.encodeWithSelector</code>:</p>
<pre><code class="language-js">bytes memory data = abi.encodeWithSelector(registry.add.selector, who);
governance.propose(address(registry), data)
</code></pre>
<p>Just like that, the target is set to the <code>Registry</code> contract, and a call that looks like <code>Registry.add(who)</code> is encoded and stored in the proposal. It's really that simple.</p>
<h4 id="usingawrapper">Using a wrapper</h4>
<p>One more thing - since we're already talking about <strong>good design</strong> and <strong>composability</strong> - I would advise wrapping this call in a method in a separate contract. This wrapper contract is then a suitably simple method that can be called in the frontend.</p>
<p>What do we name the code flow that proposes and maybe adds someone to the registry? HumanityDAO calls it <a href="https://github.com/marbleprotocol/humanity/blob/f58f173b13eda2fa952a5d0fd849942ba5653c7c/contracts/HumanityApplicant.sol"><code>HumanityApplicant</code></a>:</p>
<pre><code class="language-js">contract HumanityApplicant {
    Governance governance;
    Registry registry;

    constructor(Governance _Governance, Registry _Registry) {
        governance = Governance(_Governance);
        registry = Registry(_Registry);
    }

    function addToRegistry(address who) {
        bytes memory data = abi.encodeWithSelector(registry.add.selector, who);
        return governance.propose(msg.sender, address(registry), data);
    }
}
</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>And that's it! Using this, you can take the Governance contract and use it in your own designs, with minimal effort.</p>
<p>ℹ️Questions/discussions? Please, leave a comment :)</p>
<p>👉Follow me on <a href="https://twitter.com/liamzebedee">Twitter</a> and <a href="https://github.com/liamzebedee">GitHub</a>.</p>
<p>👉Check out the <strong>HumanityDAO smart contracts</strong>: <a href="https://github.com/marbleprotocol/humanity">github.com/marbleprotocol/humanity</a></p>
<p>👉Take a read of <a href="https://github.com/liamzebedee/awesome-solidity-patterns">awesome-solidity-patterns</a> and <a href="https://docs.ethhub.io/">EthHub</a> for more high-quality information</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[I'm a cyborg now! (On Building My Own Artificial Pancreas)]]></title><description><![CDATA[Given the choice between a) changing my lifestyle to be boring and b) hacking my metabolism, I chose the easier option. B.]]></description><link>https://liamz.co/blog/im-a-cyborg-now-on-building-my-own-artificial-pancreas/</link><guid isPermaLink="false">5d459fd5ffa4de0001a50b66</guid><category><![CDATA[diabetes]]></category><category><![CDATA[openaps]]></category><category><![CDATA[story]]></category><category><![CDATA[projects]]></category><category><![CDATA[self-improvement]]></category><category><![CDATA[skin-in-the-game]]></category><category><![CDATA[fuck-you-energy]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Sat, 03 Aug 2019 18:07:49 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2019/08/72D616EE-72F8-421D-943C-36D7B2E412EA.JPG" medium="image"/><content:encoded><![CDATA[<img src="https://liamz.co/blog/content/images/2019/08/72D616EE-72F8-421D-943C-36D7B2E412EA.JPG" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><p>Given the choice between a) changing my lifestyle to be boring and b) hacking my metabolism, I chose the easier option. I built an artificial pancreas using <a href="https://openaps.org/">OpenAPS</a>! And it's changing my life. </p><p>What's an artificial pancreas?</p><ul><li>When your pancreas is not munted like mine, it produces insulin</li><li>But more importantly, it knows when and how much insulin to produce - in response to the amount of glucose in your blood</li><li>Everything affects this:<br>- <strong>Food</strong>. Diabetics have to give themselves insulin for carbohydrates, using personal ratios we guess and refine. Different foods have different amounts of carbohydrates, which release at different speeds (<a href="https://en.wikipedia.org/wiki/Glycemic_index">glycaemic index</a>). Companies are <strong>legally</strong> allowed to include an error margin of <strong>up to 10%</strong> on their nutritional information.<br>- <strong>When you wake up</strong> (<a href="https://en.wikipedia.org/wiki/Dawn_phenomenon">dawn phenoemenon</a> / <a href="https://www.ncbi.nlm.nih.gov/pubmed/2645185">residual insulin effects</a> - you need more insulin)<br>- <strong>Illness and stress</strong> (you need more insulin)<br>- <strong>Your current levels</strong>. Your body is more insulin resistant when your levels are higher than they should be. <br>- <strong>Alcohol</strong> (occupies the liver, but only after more than one beer - you need less insulin)<br>- <strong>Exercise</strong> (adrenaline makes it temporarily go up, and stabilises in the long run)<br>- <strong>Sleep quality</strong> (makes metabolism more or less volatile)</li><li>For diabetics, we are running mathematical optimizations of complex control systems, 24-7-365. Pulling levers, making guesses, trying to <a href="http://www.diabetes-book.com/laws-small-numbers/">reduce our margins of error</a>.</li><li>An artificial pancreas is just this - but <a href="https://en.wikipedia.org/wiki/Pareto_principle">80%</a> is automated.</li></ul><p>This post is a little blog of my experience building such a system. I've outlined the tech and costs of buying it, the research involved and assembly. And most of all - the actual human impact it is making on my life. Let's begin!</p><h3 id="the-tech-stack">The Tech Stack</h3><ul><li><a href="https://www.freestylelibre.co.uk/libre/">FreeStyle Libre CGM</a> - continuous glucose monitoring</li><li><a href="https://miaomiao.cool/">Miaomiao</a> transmitter - transmits the Libre (which is NFC-based) readings via Bluetooth to my phone</li><li><a href="http://www.nightscout.info/">Nightscout</a> deployment on Heroku - an open-source frontend/backend for T1 Diabetes data hosting and visualisation</li><li>self-signed <a href="https://github.com/liamzebedee/xdripswift">xDrip</a> app - an open-source app which receives readings via Bluetooth, and sends them to Nightscout</li><li>Medtronic Insulin Pump - to inject insulin</li><li><a href="https://www.sparkfun.com/products/retired/13024">Intel Edison</a> + <a href="https://www.enhancedradio.com/products/900mhz-explorer-hat?variant=1950212653065">Explorer HAT</a> - a Linux electronic board with WiFi and support for 900MhZ radio comms</li><li><a href="https://www.adafruit.com/product/354">4400mA Lithium Ion battery</a> - to power the "rig" on-the-go</li><li><a href="https://openaps.org/">OpenAPS</a> - the 'operating system' of the artificial pancreas rig. Downloads readings from Nightscout, dynamically predicts and adjusts background insulin delivery on the insulin pump via radio, uploads all of this data to Nightscout for continuous monitoring.</li></ul><h3 id="costs">Costs</h3><p>Costs are in AUD and EUR.</p><p><strong>Insulin pump</strong> - I already had this from years ago, but usually around €3100/$5000.</p><p><strong>FreeStyle Libre CGM</strong> - €70/$112 for the reader (one time cost), and €70/$112 per sensor (which lasts 14 days, so €140/$225/month)</p><p><strong>Miaomiao</strong> - this was €200/$322</p><p><strong>Hosting Nightscout on Heroku</strong>. Free.</p><p><strong>xDrip app</strong>. The app is open-source, but since Apple doesn't allow it in App Stores, I had to purchase a 1 year developer license to sign and install it on my phone. €93/$150</p><p><strong>Intel Edison</strong>. Even though these boards are no longer sold by Intel, it was still rather cheap. €57/$92 (including shipping of €12/$20).</p><p><strong>Explorer HAT</strong>. This piece is a bespoke product made by a company called Enhanced Radio in the US. €68/$109, although I had to pay Dutch import tax of like €20/$32 because I forgot this was outside the US.</p><p><strong>Lithium Ion battery</strong>. Opted for a battery twice the capacity as the docs, just to err on the side of caution. €50/$81 (including shipping of €22/$36, and taxes €8/$13).</p><p><strong>OpenAPS</strong>. Open-source ;)</p><p>Total fixed costs (excluding pump): <br>€608/$979</p><p>Total monthly costs (excluding insulin): <br>€140/$225</p><h2 id="the-timeline">The timeline</h2><h3 id="stage-1-research">Stage 1: Research</h3><p>There was quite a lot of research involved, and definitely more to come. Some things I had to understand:</p><ul><li>which insulin pump I had, and whether it could be hacked to run this system</li><li>comparing the different open-source systems. There's another called Loop, which is an iOS app, that uses a custom board called RileyLink. There's also an Android port, called AndroidAPS.</li><li>whether I could get this working with FreeStyle Libre - which is the <em>cheapest and most easily-purchasable</em> CGM (you can't just buy these things off Amazon) but definitely not the most ubiquitous.</li><li>after choosing to build on OpenAPS, having to decide which of the Intel Edison or Raspberry Pi I would choose. I ended up selecting the Edison, since it's got much better power efficiency than the Pi.</li></ul><p><em>Estimate:</em> 7 hours</p><h3 id="stage-2-ordering">Stage 2: Ordering</h3><p>All of these parts came from different places:</p><ul><li>The <strong>Edison</strong> has been out-of-production for 2 years now. I had to do a bit of sleuthing on Amazon and various other sites to find one. Eventually I found a <em>seller on eBay who shipped from the US</em>.</li><li>The <strong>Explorer HAT</strong> was ordered from the US, easily through the one supplier.</li><li>The <strong>Miaomiao</strong> took the longest out of all (2-3 weeks), coming from some dodgy place in China (despite being a Brazilian company). </li><li>The <strong>battery</strong> (and some extra assembly bits) was ordered from <a href="https://www.adafruit.com">Adafruit</a> (a very reputable online electronics company), again coming from the US, but different shipping company.</li></ul><p><em>Total time waiting</em>: 3 weeks</p><p>I spent my $1000, sent them to my business address, and then went to Sweden and Finland while I was waiting.</p><p>This also misses the part where I had to go to the Dutch post office to pickup one of the packages, because apparently I owed import taxes on it.</p><h3 id="stage-3-assembly">Stage 3: Assembly</h3><p>I was <strong>so excited</strong> to get this thing setup. </p><p><em>Estimated time</em>: 9 hours</p><p>This stage took the longest. Why?</p><ul><li><em>1 hour in total</em>. I had to read the OpenAPS documentation, which is <strong>long. Very long</strong>. </li><li><em>2 hours</em>. Downloading Jubilinux and properly flashing the Edison, over a microUSB cable. Fun fact - there are microUSBs cables that support data, and ones that don't!</li><li><em>2.5 hours</em>. Downloading packages/dependencies using APT and NPM on a microcomputer. Then downloading them again, because OpenAPS is just a collection of rudimentary Bash scripts.</li><li><em>1 hour</em>. I had to buy an Apple Developer License and learn how sign and install this xDrip app. </li><li><em>1 hour</em>. Getting Nightscout setup on Heroku, with proper authentication and specific plugins for the OpenAPS system. Then adding these credentials to xDrip on my phone, and to OpenAPS</li><li><em>2 hours</em>. Debugging why my loop was not running properly. For some reason, it couldn't get the levels from Nightscout. I spent some time, <code>cat</code> 'ing various logs, before I jumped into the <a href="https://gitter.im/nightscout/intend-to-bolus">nightscout/intend-to-bolus</a> channel on Gitter. Within an hour, the very friendly folks were able to help me - we found the source of the issue was with the Tomato uploader, and I swapped to using Xdrip. </li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/IMG_6698.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>All the pieces on my kitchen counter</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/IMG_5874.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>Mounting the Edison on the Explorer HAT</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/IMG_2512.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>Dodgy Chinese reader</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/IMG_4585.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>My insulin pumps, old and new (the old one is better)</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/IMG_0796-1.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>My lil' baby running!</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/IMG_1066.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>Next up was logging into the rig, via USB Serial! Never done this before. Used screen /dev/tty.usbserial-xyz 115200</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/IMG_0646.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>Flashing the rig with Jubilinux</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/Screen-Shot-2019-07-31-at-9.54.59-pm.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>SSHing into my rig - I called it diabeetus.local ;)</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://liamz.co/blog/content/images/2019/08/Screen-Shot-2019-08-01-at-12.14.47-am.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"><figcaption>Reading the live log of the OpenAPS system.</figcaption></figure><p>OpenAPS is remarkably simple for a large collection of Bash, Python and JS. Running <code>l</code> will tail the system log.</p><p>This is the point at which I noticed a familiarly <strong>dumb</strong> stack trace -</p><!--kg-card-begin: markdown--><p><code>myopenaps/monitor/glucose.json: Unexpected end of JSON input</code></p>
<!--kg-card-end: markdown--><p>I swapped from the app I was using, to signing and installing xDrip. You can <strong>clearly see</strong> that it's open-source software by the design flair. But it works - and that's the point.</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/IMG_7101.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><p> It was 2am before I figured this out, so I had to break and come back to it. The next day I got in touch over the Gitter channel, and within an hour, a mate called Jon had helped me solve it!</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/Screen-Shot-2019-08-02-at-12.35.06-am.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><p>Miraculously - <strong>my loop was running!</strong></p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/Screen-Shot-2019-08-02-at-12.36.32-am.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><h2 id="stage-4-usage">Stage 4: Usage</h2><p>Below is a picture of Nightgraph, the visual dashboard of my artificial pancreas.</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/Screen-Shot-2019-08-02-at-12.46.30-pm-1.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><p>This is overwhelming, and again, typical of open-source projects to not have the resources for good visual design. I've annotated the main parts so you can better understand what you're looking at -</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/annotated-nigthscout-1.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><p>This is <strong>the brains</strong> of the artificial pancreas. You can see how it sees my levels, how it understands how much insulin I have on board, what it predicts, and how it's going to <strong>dynamically adjust</strong> to make sure it stays in range.</p><p>The way OpenAPS works is that it is continually readjusting a temporary basal - a background level of insulin - every 5 minutes. If you're not a diabetic but you are a nerd, then take a read of <a href="https://openaps.readthedocs.io/en/latest/docs/While%20You%20Wait%20For%20Gear/Understand-determine-basal.html#basic-diabetes-math">How OpenAPS Makes Decisions</a> for a nice overview of the different maths involved. The core parameters it calculates are: </p><ul><li>the BG delta - the difference between current BG and an average of BG's over the past 5mins</li><li>the short/long <em>average</em> BG deltas - the average rate of change of the BG over the timespans of the past 15 and 45 minutes respectively</li><li>your insulin-on-board (IOB) - how much insulin is still on board. This is important because insulin doesn't get consumed like you would intuit - it stays in the body for X amount of time, rather than disappearing after X amount of carbohydrates have been processed</li><li>insulin sensitivity ratio (more on this below)</li></ul><p>This is basically real-world maths! The BG deltas are calculated as the <a href="https://simple.wikipedia.org/wiki/Derivative_(mathematics)">derivative</a> of BG levels. The insulin on board is calculated by modelling your type of insulin (there are different types) as an exponential curve. Here's a little picture I've pulled from the <a href="https://openaps.readthedocs.io/en/latest/docs/While%20You%20Wait%20For%20Gear/understanding-insulin-on-board-calculations.html#understanding-the-new-iob-curves-based-on-exponential-activity-curves">OpenAPS docs</a>:</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/image.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><p>Why is this important? Because the community is as much as part of this experience as the technology itself. Even with faster acting insulin being introduced, <strong>the community stays </strong><a href="https://github.com/LoopKit/Loop/issues/388#issuecomment-317938473"><strong>up-to-date</strong></a>. </p><p>The other thing to note is that <strong>OpenAPS takes care of you when you're sick</strong>. Up to 24h before I have any symptoms of illness, my levels usually start getting much higher. This is an interesting example of insulin resistance - due to my body releasing some stress hormones when fighting off illness, my levels go up, which in turn increases my resistance to insulin, which leads them to further highs and so on...Now where OpenAPS comes in - every 24h, it is estimating whether your insulin sensitivity has changed. And using this information, it automatically adjusts to give you more insulin.</p><p>There's a slew of other things I haven't yet checked out (this is only my 3rd day in), such as integrating with IFTT, and some really funky reports you can generate in Nighscout, like the one below:</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/Screen-Shot-2019-08-04-at-2.13.43-pm.png" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><p>An OpenAPS Loop is not a catch-all solution. You still need to remember to give yourself insulin for food. And this won't help you with alcohol, <em>probably</em>. But it's a hell of a lot better — an <strong>order of magnitude </strong>better - than what was happening before.</p><h2 id="philosophy-and-struggle">Philosophy and struggle</h2><p>In many ways, Diabetes is a confrontation with <a href="https://en.wikipedia.org/wiki/Absurdism">the absurd</a>. It's an affliction that just happens to you one day (no, you don't have to be born with it). It's not your fault that you have it, and it's also <em>sometimes</em> not your fault when things go wrong - there are some things we do not know about metabolism, and especially about the natural feedback loops of the body. But, it's your responsibility to deal with - you either make something of it, or you don't.</p><p>Sometimes I would get so angry at myself, so upset with what was happening to me, because it is <strong>my</strong> <strong>own</strong> <strong>body</strong>. And not feeling in control of basic sensations, it does fuck you up a bit, mentally. Annoyed that medical practition is more than ever, a matter of <a href="https://en.wikipedia.org/wiki/Skin_in_the_game_(phrase)"><em>skin in the game</em></a><em> </em>- made up of people that don't live with the disease, and don't have any large stakes either, and in Western medicine, prefer to prescribe rather than analyse. I started reading research from doctors who actually had T1 diabetes - the problem is <strong>not</strong> because <strong>you're</strong> <strong>failing</strong> to remember to give insulin - but <a href="https://www.andrewkoutnik.com/blog/2018/9/8/part-3-optimal-blood-glucose-control">the type of food you eat creates these volatile swings</a>. One doctor went so far as to <a href="http://www.diabetes-book.com/">eliminate carbohydrates</a> from his diet. These are not flat earthers - they are certified doctors, but unlike your typical Diabetes clinic, they have skin in the game.</p><p>So I know that it's pretty insane to run your basic metabolism on untyped JavaScript code. But if you were in my shoes, you'd realise it was safer than going to the hospital, intentionally or not. And anyways, the community is its own continuous integration, in a sense 😉</p><p>To conclude: building this system was the most self-actualizing thing I've done in a while. All of this planning — investment of money ($1000), thought (3 weeks waiting) and time (20hrs) – led up to a moment. When I finally got that rig running, I felt ecstasy. Not that the burden was entirely lifted - but I really felt like I was back in control. And that, that was empowering.</p><h4 id="addendum">Addendum</h4><p>This has been circulated quite a bit around the web:</p><ul><li><a href="https://interestingengineering.com/software-engineer-with-diabetes-incredibly-builds-his-very-own-artificial-pancreas">Interesting Engineering</a> - WOAH</li><li><a href="https://news.ycombinator.com/item?id=20606230">Discussion on Hacker News</a> - frontpage woohoo!</li><li>@Biohacker.pl commented below, that he discovered this in a big Polish tech site <a href="https://www.spidersweb.pl/2019/08/sztuczna-trzustka-cukrzyca-inteligentna-pompa-insulinowa.html">here</a></li><li><a href="https://vc.ru/dev/84930-razrabotchik-diabetik-sobral-iskusstvennuyu-podzheludochnuyu-zhelezu-rabotayushchuyu-na-javascript">Разработчик-диабетик собрал искусственную поджелудочную железу, работающую на JavaScript​</a> - something something hacker builds pancreas that runs on JavaScript</li></ul><p>Vladimir on HN asked: what do you actually wear everyday? So here are the pictures of the gear:</p><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/IMG_1894.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/IMG_5229.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure><figure class="kg-card kg-image-card"><img src="https://liamz.co/blog/content/images/2019/08/IMG_9841.jpeg" class="kg-image" alt="I'm a cyborg now! (On Building My Own Artificial Pancreas)"></figure>]]></content:encoded></item><item><title><![CDATA[Drugs and Inventing Currencies: Blockchain's Fiction]]></title><description><![CDATA[Blockchain is vacuous, messy and undefined. Here's a story that will make it simple to understand. ]]></description><link>https://liamz.co/blog/drugs-and-inventing-currencies-blockchains-fiction/</link><guid isPermaLink="false">5d34e9a22109b900012d4b3c</guid><category><![CDATA[blockchain]]></category><category><![CDATA[silk road]]></category><category><![CDATA[bitcoin]]></category><category><![CDATA[ethereum]]></category><category><![CDATA[dai]]></category><category><![CDATA[uniswap]]></category><category><![CDATA[products]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Sat, 03 Aug 2019 14:51:23 GMT</pubDate><content:encoded><![CDATA[<p>Blockchain is something so abstractly vacuous it's hard to pitch its values. Let's run down the history very quickly:</p><p><strong>2009</strong>: Bitcoin</p><p><strong>2014:</strong> Ethereum</p><p><strong>2017</strong>: DAI</p><p><strong>2019</strong>: Uniswap</p><p>These are your exponential use cases. These are things that <strong>aren't hype</strong>, but actually really in use.</p><p>But there's a lot of stuff between the lines. Bitcoin literally got started because you could buy drugs off of Silk Road. It took immediate use in international remittance, but as a <em>tall white dude </em>who only recently started being across jurisdictions (EU vs. US) - I can tell you, this isn't a <em>problem</em> many people relate to. Buying drugs with zero risk? Yeah, definitely.</p><p>Next example - Ethereum. Bitcoin just did transactions - I send you Bitcoins, you receive Bitcoins, <em>doneskis</em>. Bitcoin is a spreadsheet. A big dumb expensive spreadsheet, that no state can control or censor. Ethereum is pretty much the same, but the spreadsheet is infinite. And you can make whatever you want with it.</p><p>So what did people make? More cryptocurrencies, <em>duhhh!</em> That's when the ICO boom happened (late 2016). Every man and his dog were issuing a currency not controlled by a nation state, all under a guise of doing something revolutionary yada yada. <em>Not really</em>. </p><p>Although it is interesting to note - the token replaced the VC. Before, if you wanted money, you had to go through things like convertible notes and shares, and showing powerpoints to people. Now, you just create a token, and sell it to anyone. Seems pretty easy, almost like anyone could do it, and oh wait...that explains a lot.</p><p>We've gotten pretty far, but now you're getting lost. Welll haaaaave you met DAI? DAI is about as simple as it gets. It's the same as Bitcoin, except the price doesn't change. Reaaaaally disruptive innovation. You figured out a way to allow anyone to be a bank, you've just replaced fiat money, and you're waiting for everyone to get the idea...<a href="https://daistats.com/">$348 MILLION dollars later</a>, people are now just getting it.</p><p>So, what can we do now that we've got magic internet money that doesn't lose all of its value in your lunchbreak? Well - remember that part where we were all inventing our own tokens (cc: <a href="https://dogecoin.com/">dogecoin</a>) a while back as a bit of a side gig? Well, unlike visiting your cousin's wordpress blog, to actually load those tokens you're going to have to sit down with a cup of coffee. <strong>Still</strong> after all of this <strong>inNOvATION</strong>, we have to register for an exchange and because of terrorists, find <strong>where is my bloody passport</strong>. </p><p>Yeah so, imagine if you didn't have to do that? That's <a href="https://uniswap.exchange/">Uniswap</a>. If DAI is being your own bank, Uniswap is being your own exchange. Except, ew, other people do that for you, you just pay them 3% in fees. When this fanciful dapp came out, it took about 2 weeks for it to have 20,000 ETH in deposits. <a href="https://twitter.com/UniswapExchange/status/1102641259607441408">2 weeks</a>. The guy who built it? Doesn't even write clean code. The UX? <strong>Absolutely slick</strong>.</p><p>Oh, on the note of UX? It ALL SUCKS! All of it. Everything sucks. It sucks badly. Really really badly. You are inside twelve bubbles rotating around a trail of excrement. UX is so bad, <a href="https://decrypt.co/7970/user-friendly-gateway-causes-large-spike-in-makerdao-holdings">someone made an app that wraps your app</a> and it literally spiked usage 100x ($4.6 million to $40 million collateral) in 10 days. </p><h3 id="things-that-aren-t-there-yet">Things that aren't there yet</h3><p><u>TCR's</u>. Token Curated Registries. Their main issue? No-one cares. </p><p><u>DAO's</u>. Distributed Autonomous Organisations. Sounds really cool, but no-one has shown me an app that <em>just works</em>. Let me organise a meetup with it, then <em>hit me up</em>.</p><p><u>Augur</u>: Prediction Markets. Daily Active Users?<em> </em>You can count on two hands<em>.</em> Was one of the first projects to do this, so their app is very sluggish based on the tech at the time. <a href="https://veil.co/">Veil</a> fixed their UX, but still there's a big gaping void of user addiction/interest.</p><p><u>Scaling</u>. LOL. Give it time - meta transactions are the closest I've seen, Austin Griffith's <a href="https://github.com/austintgriffith/burner-wallet">Burner Wallet</a> being one.</p><p><u>Anonymous tx's.</u> Mixers are up-and-coming. <a href="https://www.aztecprotocol.com/">AZTEC</a> still working hard, cannot wait to slap on anonymity to all of my ERC20's.</p><p><u>Matter</u>(???): <a href="https://twitter.com/mattereum">Mattereum</a> is the weirdest, most dream-y project in the space. Basically let's make every barcode link to the blockchain, and then categorise and tag all the sizes/nutritional-info/which-artist-kissed-this-guitar-in-92 into a massive database, Wikipedia-style. <em>insert crazy segues here</em></p><h2 id="what-are-we-actually-trying-to-do">What are we actually trying to do?</h2><p>No-one knows. But I'll take a stab. Blockchain is a techno-economic innovation - it touches upon the core of human society, the abstract fuzzy-wuzzy of <em>what is valuable</em>. </p><p>Blockchains let us decide what is valuable, by giving us the right to just make up tokens like DOGE and Bitcoin, and then make memes or actually get <a href="https://www.coindesk.com/what-trumps-bitcoin-tweet-changes">world leaders to hate on you</a> (the difference nowadays is blurry).</p><p>They have leaders with their own values, like a Russian genius that believes in <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3243656">square-root oriented communism</a>. Or libertarians from the Bitcoin subcultures, who are fine with the idea of assassination. </p><p>They let us agree on rules at internet-speed. This is new for most people, because the last time you did this was probably as part of a school council, if anything. No-one knows what this means, <a href="https://en.wikipedia.org/wiki/The_DAO_(organization)">so naturally we the Internet made a venture capital fund overnight, and threw $160M at it</a>. </p><p>Mostly boring stuff is where everything is happening. Insurance, shipping, tracking. These are all problems that are, by-and-large, solved by a nicely packaged shared database. Believe it or not, but tokenising things isn't just about selling them. It's about <strong>ownership</strong>, it's about <strong>responsibility</strong>. </p><p>One peek into the future - blockchains will become jurisdictions. Just like how we have <a href="https://en.wikipedia.org/wiki/Common_law">common law</a> (the UK, built from cases) and <a href="https://en.wikipedia.org/wiki/Civil_law_(legal_system">civil law</a>, blockchains offer various security and ideological tradeoffs. Ethereum will always be open, but pragmatic. Bitcoin will be unwaveringly Wild West. </p><h2 id="summary">Summary</h2><p>Just saw this quote:</p><blockquote>Bitcoin broke the cartel of finance.<br>Internet broke the cartel of knowledge.</blockquote><p>and <a href="https://medium.com/metacartel/forking-moloch-dao-d140a37d6649">MetaCartel</a>... breaks the cartel of cartels</p><p></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Building the first-ever ZKDAO POC at #ETHParis]]></title><description><![CDATA[Two weekends ago in Paris, we built the first POC of a zero knowledge DAO. Since January I had a fascination with the idea, and after meeting Zac from AZTEC at EthCC, a key component of the solution crystalised. In this post, I'll explain the design considerations and potential implications. 
]]></description><link>https://liamz.co/blog/building-the-first-ever-zkdao-at-ethparis/</link><guid isPermaLink="false">5c9279aa592c3500010ef851</guid><category><![CDATA[projects]]></category><category><![CDATA[blockchain]]></category><category><![CDATA[zkdao]]></category><category><![CDATA[ethparis]]></category><category><![CDATA[hackathons]]></category><category><![CDATA[travel]]></category><category><![CDATA[paris]]></category><category><![CDATA[future]]></category><dc:creator><![CDATA[Liam Zebedee]]></dc:creator><pubDate>Sat, 06 Apr 2019 14:53:18 GMT</pubDate><media:content url="https://liamz.co/blog/content/images/2019/04/IMG_0817-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://liamz.co/blog/content/images/2019/04/IMG_0817-1.png" alt="Building the first-ever ZKDAO POC at #ETHParis"><p>Two weekends ago in Paris, we built the first POC of a zero knowledge DAO. Since January I had a fascination with the idea, and after meeting Zac from AZTEC at <a href="https://ethcc.io/">#EthCC</a>, a key component of the solution crystalised. In this post, I'll explain the design considerations and potential implications.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">I can&#39;t believe we actually did it - we implemented the ZKDAO at <a href="https://twitter.com/hashtag/ETHParis?src=hash&amp;ref_src=twsrc%5Etfw">#ETHParis</a> with <a href="https://twitter.com/aztecprotocol?ref_src=twsrc%5Etfw">@aztecprotocol</a>&#39;s dividend proofs <a href="https://t.co/5i3enHY4x3">pic.twitter.com/5i3enHY4x3</a></p>&mdash; Liam Zebedee (@liamzebedee) <a href="https://twitter.com/liamzebedee/status/1104598030907596801?ref_src=twsrc%5Etfw">March 10, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h1 id="idealogue">Idealogue</h1>
<p>One of my favourite thoughtpieces to explain blockchain is The DAO. The DAO in 2015 was a hallmark - a worldwide investment organisation that owned over $150M in ETH at the time, born independent of any nation and wasn't controlled by any single entity. Unfortunately, there was a bug in the code, and the experiment came to an end all too quickly. But the concept stood firmly into 2019, and now the theme of [blockchain] <strong>governance</strong> is as hot as scaling.</p>
<p>Since then, blockchain tech has evolved so rapidly, it's hard to keep up. <a href="https://en.wikipedia.org/wiki/Zero-knowledge_proof">Zero Knowledge Proofs</a> have been of particular interest - a tool of mathematics whereby <em>relationships are proven without revealing some information</em>, which has great utility in privacy and scaling protocols. Ever since <a href="https://gist.github.com/liamzebedee/6cfceaec3dc417cdae5ddc728e318fad">participating in</a> <a href="https://iden3.io/">Iden3</a>'s Zero Knowledge workshop at <a href="https://web3summit.com/">Web3 Summit</a>, I knew that Zero Knowledge tech was even closer and more tangible than I thought was possible. When the <a href="https://www.aztecprotocol.com/">AZTEC protocol</a> for ZK ERC20's was announced and started <a href="https://www.reddit.com/r/ethtrader/comments/a1uh8u/the_holy_grail_of_currencies_a_zero_knowledge_dai/?st=JP4Q3MTW&amp;sh=26e6bfed">gaining interest</a> with their ZK-DAI token, I began reading deeper. AZTEC has received a large degree of funding to date because they are not just building for ZK transfers - they are building <strong>an engine</strong> (see <a href="https://github.com/ethereum/EIPs/issues/1723">their EIP</a>).</p>
<p>Funnily enough, so were we, but for <a href="https://berse.io">cross-chain token derivatives</a> instead. And while we were pitching this idea to a friend, we were discussing cross-chain index funds and so on. <em>You know, it would be crazy if the index fund was zero knowledge</em>. <em>You would invest money and the fund would allocate according to a portfolio, but you would never know the weightings.</em> And so I got hooked on the concept of a ZK index fund. Further along the way, I realised that such a fund would take the structure of the original DAO anyways, and so we come to the ZKDAO.</p>
<h3 id="azeroknowledgedao">A Zero Knowledge DAO</h3>
<p>Recall a definition of what an organisation, decentralised or not, is in its simplest form:</p>
<blockquote>
<p>a set of <strong>property</strong>, and a <strong>protocol</strong> for a set of individuals, [...] to interact with each other including rules for under what circumstances the individuals may use certain parts of the property <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></p>
</blockquote>
<p>In the case of an index fund, the property involved is capital to buy the assets, shares that are issued by the fund in exchange for such capital, and dividends that are distributed to shareholders. In contrast, a DAO investment fund is a lot simpler. The only property in question is its capital (ETH) and the protocol is a simple model of <em>voting</em> on proposals, based on the number of shares you possess.</p>
<p>I've <a href="https://liamz.co/blog/making-trust-free-the-impact-of-blockchain-on-systems/">highlighted previously</a> that the core proposition of blockchain is trust for <strong>marginal cost</strong> -- you can setup a worldwide investment fund for the 30c it takes to deploy to mainnet. What happens when the protocol itself is anonymous?</p>
<h2 id="anonymousvotingusingaztecproofs">Anonymous voting using AZTEC proofs</h2>
<p>What is the simplest version of the protocol we are trying to implement?</p>
<ul>
<li>submitting a proposal</li>
<li>voting on a proposal</li>
<li>tallying votes and executing the proposal if they reach a threshold majority</li>
</ul>
<p>Submitting the proposal would be easy, but how can we keep voter anonymity while retaining the ability to calculate if there's been a majority? Since we would like everyone's balances to remain private, how could we do this?  Remember - the key of this exercise was not to produce a perfect design, but something better than what exists. And after researching into <a href="https://ethresear.ch/t/reducing-the-verification-cost-of-a-snark-through-hierarchical-aggregation/5128">aggregating ZK proofs</a>, I realised a more pragmatic approach would be to take a look at an existing ZK protocol - AZTEC. AZTEC</p>
<p>And then I met Zac, the founder, at EthCC, and from our conversation sprung the invaluable clarity - share balances can remain secret, and we know the fixed public <code>totalSupply</code> of all shares, we could calculate this majority <strong>if shareholders revealed some proportion of their shares</strong>. The problem here is that some information is leaked as to the balance with every vote, however this isn't a completely unbeatable issue. Obfuscating the balances by shuffling coins around, a mixer/tumbler scheme, a dual-key stealth address protocol (see the <a href="https://github.com/AztecProtocol/AZTEC/blob/master/AZTEC.pdf">AZTEC paper</a> appendix A) are all possible approaches. ZK <a href="https://ethresear.ch/t/plasma-cash-was-a-transaction-format/4261">Merkle Sum Trees</a> (as used in Plasma) are probably an interesting tool to explore in this case <sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>.</p>
<p>And so we (mis)used the AZTEC public dividend proof to prove a percentage of someone's shares were used to vote. At the hackathon, we spent the time reverse-engineering how it worked (since it's all quite undocumented for now). There were two additional constraints that arose during this design:</p>
<ol>
<li>votes can not be double-cast - ie. by transferring shares, and voting again.</li>
<li>votes can be submitted on multiple proposals</li>
</ol>
<h4 id="briefprimeronaztec">Brief primer on AZTEC</h4>
<p>AZTEC uses homeomorphic cryptography (meaning computation on encrypted data) and range proofs to build a primitive of a zero-knowledge <strong>note</strong>. The note is a representation of value that is only created and destroyed from transacting them - it is akin to the UXTO model of Bitcoin, with input value and output value, as opposed to Ethereum's account-based ledger.</p>
<p>A note is always associated with a public key, which is used to prove ownership of the tokens.</p>
<h4 id="dividendproofs">Dividend proofs</h4>
<p><a href="https://github.com/ethereum/EIPs/issues/1723">AZTEC's Cryptography Engine</a> (ACE) specifies a set of zero knowledge proofs that it can validate. The proofs use notes as their base data type, <strong>however</strong> they are not tightly coupled to a ZK ERC-20 token - the <a href="https://github.com/liamzebedee/ZKDAO/blob/ce7056f14e19ba08eb2c9c274da5ccc6d3d53ea3/packages/protocol/contracts/ACE/NoteRegistry.sol">NoteRegistry</a> handles the conversion of ERC20 into new ZK notes by validating a proof supplied with it (see <a href="https://github.com/liamzebedee/ZKDAO/blob/ce7056f14e19ba08eb2c9c274da5ccc6d3d53ea3/packages/protocol/contracts/ACE/NoteRegistry.sol#L169">publicValue</a>).</p>
<p>A dividend proof is for proving that an issued dividend note is a certain % of another note. In terms of its proof, it has one input and two outputs - the input note A, the output/dividend X and the residual value B. At ETHParis, we reverse-engineered how this very newly-written proof worked. Basically, you are satisfying this relationship:</p>
<p>$$ k_3 = k_1(z_b) - k_2(z_a) $$</p>
<p>Where \(k_i\) is the private values of a set of 3 notes (totalSupply, no. votes, zkShares), and \(z_a,z_b\) are the public factors of the dividend logic.</p>
<p>We <a href="https://github.com/simonDos/ZKDAO/blob/dfac3a1125fd8489a2277d4c15a1230affcbd649/packages/protocol/test/AnomVoting/AnomVoting.js#L84">use a dividend proof</a> to reveal the number of votes cast by a shareholder, whilst hiding their balances (principles of the proof relationship). Again - the ACE engine defines proofs, which typically relate to notes, but the value we're using here in terms of number of votes doesn't relate to an existing note in the note registry.</p>
<h4 id="zkdaoanonymousvotingmechanism">ZKDAO Anonymous Voting Mechanism</h4>
<p>We represent shares as ZK notes. Such notes can be the ERC20 tokens of a preexisting DAO, converted into zkshares by AZTEC's NoteRegistry (plug-n-play anonymity). The shares can be transferred in zero knowledge, meaning you can buy/sell without people knowing how much is transacted.</p>
<p>We represent votes using dividend proofs, wherein the input note is the totalSupply, the output notes are your zkShare and a fictitious note representing the votes you are casting. In this process, you are revealing the % of your voting power you are casting as a vote, as a % of the total supply of shares in existence. <strong>However</strong>, this is without revealing how many shares you own.</p>
<p>We can cast votes, but how do we mitigate people transferring their shares and thus casting two votes? Recall that if the number of the shares is unknown, then we can't do the simple accounting as a regular DAO does. To solve this, we designed a simple <em>commit-reveal</em> voting scheme. Users commit to their voting positions, and then only during the reveal phase can votes be tallied. The commit requires that the zk-note already exists, and such at the reveal stage you cannot double-vote as described above.</p>
<p>Maintaining perfect anonymity in the midst of voting on multiple proposals is difficult, since overlapping committal periods requires you keep the note in the same hands.</p>
<h2 id="implicationsandfurtherideas">Implications and further ideas.</h2>
<p>Again, blockchain tech moves and changes quicker than a plastic bag in a hurricane. Just in this past month, two new Ethereum smart-contract privacy technologies have been described - <a href="https://ethresear.ch/t/zether-the-first-privacy-mechanism-designed-for-ethereum/5029">Zether</a> and <a href="https://ethresear.ch/t/zeth-on-integrating-zerocash-on-ethereum/5246">ZEXE</a> (take a read from <a href="https://blockchainresearch.substack.com/p/blockchain-research-newsletter-2">the fantastic Blockchain Research Newsletter</a> for a good overview). They anonymise dApps at the blockchain's transaction level, which is clearly a big deal. I predict that it is <strong>highly</strong> likely we will see privacy-enabling tech like this at scale within 5 years, and not just specific to financial transfers.</p>
<p>In my mind, the most pertinent question is of <strong>the possibility of meritocracy</strong> - once you remove identity from the equation, what do people/agents base their decisions on?</p>
<p>The second implication is - <strong>can we prevent vote buying / collusion / bribery</strong>? In the current model, it is still possible to prove after-the-fact whether an address voted for a value. So while the actual addresses carry no identifying information in of themselves, if someone chooses to, they can still prove their ownership and thus be paid from it.</p>
<h3 id="conclusion">Conclusion</h3>
<p>I was initially skeptical to work on this problem, because I'm not a studied cryptographer. Even writing this post, I was a bit hesitant to make certain claims. A week before I went to the hackathon with this idea, I shared my other <a href="https://ethresear.ch/t/evidence-based-subjective-logic-and-sybil-resistance/5075">research on decentralised reputation on EthResearch</a>, which led to some really interesting conversations. From that, and continuing forth with ZKDAO, I'm learning it's good to get things out there. Even if they are imperfect, they exist, which is substantial on its own.</p>
<p>Reflecting on ETHParis, I couldn't have done it without my awesome teammates <em>Simon Dosch</em> and <em>Max Niemzik</em> - hacking with them was an absolute blast. Bizzarely but absolutely serendipitously, we gelled really well and progressed a series of small wins<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> in an area we are hugely inexperienced in, and built the thing we set out to build - ZKDAO.</p>
<p><video src="https://liamz.co/blog/static/videos/ethparis-2019.mp4" controls loop></video><br>
<em>tired out of our minds, 5am, Paris</em></p>
<p>Take a look at our <a href="https://github.com/simonDos/ZKDAO">Github repo</a> for the code. A massive shoutout and thank you to the AZTEC team who were there too, particularly Tom, whose brains we racked on Friday and was quite the help, and of course Zac, the man behind the magic. Lastly, thank you to the ETHParis organisers, it was a really enjoyable hackathon and fantastic venue at 42.</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>from <a href="https://blog.ethereum.org/2014/05/06/daos-dacs-das-and-more-an-incomplete-terminology-guide/">DAOs, DACs, DAs and More: An Incomplete Terminology Guide</a> <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>The development of authenticated data structures is fascinating. We've gone from the Merkle tree, to <a href="https://github.com/ethereum/wiki/wiki/Patricia-Tree">Merkle-Patricia</a> for key-value storage, to Sparse Merkle Trees which are an amazing simplification of the KV design. <a href="https://github.com/opentimestamps/opentimestamps-server/blob/4f5a3c6ae56be766cc6d83e31fb5341f78ecad7c/doc/merkle-mountain-range.md">Merkle Mountain Ranges</a> (used in Grin) are effectively an optimization of recomputation of Merkle trees.</p>
<p>Plasma <a href="https://plasma-core.readthedocs.io/en/latest/specs/sum-tree.html#parsing-transfers-as-leaves">has popularised Merkle Sum Trees</a> as an authenticated data structure for representing token value on a number line, where the leaves represent spans of 'balances'. It's not far fetched to imagine this implemented as a ZK circuit. I actually experimented with this using <a href="https://github.com/iden3/circomlib/tree/master/circuits">Circom Merkle circuits</a> - you could use these to prove an update to the vote tally, without revealing which account/note was used in the update. The only unsolved issue then is how to prevent double-voting (I learned it's called a <a href="https://crypto.stackexchange.com/questions/67247/can-we-build-a-zero-knowledge-mapping-using-public-key-encryption?stw=2">bijective mapping</a>). <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p>The <em>&quot;small wins&quot;</em> I'm describing here are closest to what I imagine is the iterative / lean canvas idea of development. I'm currently doing some <a href="https://github.com/liamzebedee/devkoans">meta-analysis on this style of dev</a> - during the hack, we basically wrote unit tests on generaing and validating dividend proofs in JS, our custom hook-in to the ACE in the ZKDAO contract, extracting the z_b and z_a parameters from the ACE ABI call (yay wrote our first Soli-dirty assembly). Max even wrote a Solidity function to leak the full balance of an AZTEC note from the spending key, which is crazy. All of our wins roughly were 1-2h apart, which was really motivating. I guess the attitude of &quot;maybe we can do this but surely not in a weekend&quot; meant we weren't prematurely optimizing or worrying about design. <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown--><h1></h1><h4></h4><p></p>]]></content:encoded></item></channel></rss>