【以台積電為代表的「貨櫃車」問題】( 二之二)
我們都知道半導體業用電、用水多,到底有多麼多?
我是到最近才知道:台積電2019年的用電量相當於全台北市一年用電量的91%。並且,到2023年,也就是四年之內,台積電的用電量將再擴增一倍。
這還只是台積電的情況。
聯電呢?其他半導體大廠呢?其他電子業大廠呢?整體工業用電呢?
我們這些工業用電,在「缺電」陰影裡扮演什麼角色?
為什麼會出現這些狀況?
這是台電只知增加電力供給的思維和習慣能應對的嗎?
這是我第二篇文章要寫的重點。
-----貨車和貨櫃車激增,才是塞車的主因-----
繼續用高速公路的比喻。
高速公路上有大小不同的車子在跑。
住宅用電,我們來比喻為小客車,全台灣大約有1,300萬戶。
工業用電,我們來比喻為大貨車,全台灣大約2.5萬戶。
從1998到2017的二十年間,每年的住宅用電,也就是小客車流量,只增加了百分之五十,從每年大約300多億度增加到每年440億度。
而工業用電,大貨車流量則增加了一倍,從大約640億度增加到1200億度以上。這個數字是全部住宅用電的三倍。
把大貨車再細分來看。
2017年工業用電的前五名,排第一的就是半導體所在的電子零組件製造業,佔22.6%;其他四名加起來才17.5%。鋼鐵業只有7.1%;塑膠製品製造業只有3.3%等等。
半導體所在的產業用電不只佔比最高,增速也最快。1998年不到60億度,到2017年就達到346億度,增加了快6倍。
所以半導體所屬產業的用電,是大貨車裡的巨無霸,貨櫃車。
正因為這二十年裡高速公路上增加最多、最快,同時也佔位最大的,是大貨車和貨櫃車,他們才是造成塞車的最大風險。如果要管理用電需求,首先要注意的就是他們。
就好像年節假期間的高速公路塞車,如果我們只強調疏導小客車,但是卻放任大量大貨車和貨櫃車上路,合理嗎?
但是,你可能會問:為什麼要說這是放任呢?他們是經濟成長的動力啊?又怎麼管理他們?
--------便宜到鄭崇華說不合理的電價--------
今年3月20日台達電創辦人鄭崇華接受訪問,說了段話:「水電價格應合理反映成本,現在是納稅人補貼大戶,價格越便宜,大家拚命用,很不合理。」
同一報導中也提到:「去年全球電力消耗普遍減少,台灣的電力消耗則創歷史新高,比上年增加2.4%。」
而就在鄭崇華訪問刊出的6天後,經濟部宣布電費自2018年後連六次不調漲,還甚為得意地說台灣工業用電已成為全球第四低。
鄭崇華以身受其益的工業大戶身分,卻指出台灣政府水電價格便宜得不合理,這是很奇特的。但也因此可以想見這便宜到底是多便宜。
長期以來,大家都知道台灣的電,是名列世界上最便宜的前茅。但知不知道台灣的工業用電是比民生用電還便宜?工業用電不但比住宅用電便宜,平均漲幅也比住宅用電小?
我們看台灣上一次2018年調整電價的情況。
那次工業用電的平均漲幅在3.30%到 3.56%之間,用電最大的特高壓用戶(像台積電)則是3.41%,而細看台電的資料會發現,民生用電除了500度以下沒有調整之外,500度以上的調幅在3.96到4.14%之間。換句話說,用電最大的特高壓用戶的電費漲幅,比一般家庭的漲幅還小。
我們的電價真是非常獨厚工業用戶,尤其超級大戶。
所以,當今年3月經濟部再宣布電費不調整,創下2018年下半年至今「連6凍」紀錄的同時,2019年我國住宅電價為全球第4低,工業電價為全球第4低。
換句話說,經過電價的連六凍之後,我國住宅民生用電電價相對升高,從全球第2低退為全球第4低,而我國工業電價相對更降低,從全球第7低進而更成為全球第4低。
在去年全球電力消耗普遍減少的情況下,台灣的電力消耗則創歷史新高,真是在走逆世界的潮流。其主要原因顯然不是小客車用戶所導致,而是那些大貨車、貨櫃車。
台灣人民一直以為享受到很低的電價是惠民的福利,卻不知那是經濟部讓工商大老吃肉之後留下的湯。
上一篇文章提到台電對工業用電戶設計了24小時不同的分時電價,但25,000用戶中卻只推動了300戶試用。這一方面固然有台電的怠惰,另一方面也因而可以想像可能還有一個原因:工業用電本來就太便宜了,便宜到要不要接受分時電價都差別不大。
所以,鼓勵了這麼多大貨車、貨櫃車開上高速公路,電價又便宜到連尖峰時刻都沒有足以吸引他們的不同時段明顯價差,不塞車可能嗎?台電的時間管理性缺電會越來越嚴重,有什麼奇怪嗎?
但是,為什麼台電要持續以這麼便宜,便宜到連受益者都出面指出不合理的電價提供給工業用戶?
這幕荒謬劇是怎麼上演的?
這不能不說到台電的上司,經濟部。
--------主要服務工業大戶的經濟部和台電--------
經濟部主管國家產業政策,但台灣幾十年來的經濟發展接力賽,從加工出口開始,一路都是以製造業、工業為主,到培植出半導體產業。只是接力賽到半導體產業登場後,已經有三十多年沒看到下一棒了。
經濟部端不出新的產業牛肉,當然只能守成與守舊,只能傾全力服務過去到現在還一直在跑的產業明星。經濟部的政績,也就是出口成長率、經濟成長率等等,都要看這些工業用戶來達成,能不盡力討好他們嗎?
所以三十年來台灣沒有新的產業政策,也就不會有新的能源政策。有的,只是經濟部配合工業大老提供他們便宜用電的政策。而台電就是執行者。
本來,在包括半導體在內的許多產業在萌芽之初,國家有計劃地提供各種獎勵、補助、便宜的水電,讓他們茁壯。
並且,他們習以為常地對太多早已過了草創時期,早已茁壯成世界級的企業,仍然提供這些超級優惠。
這就是鄭崇華所說的「水電價格應合理反映成本,現在是納稅人補貼大戶,價格越便宜,大家拚命用,很不合理」的真相。
而許多工商大老,在享受電力的眾多好處之後,相對應的回報是很奇怪的。
以工業總會的領導成員來說,他們長期就是核電的堅定支持者,否定綠能的價值。2018年工總理事長,台塑集團總裁王文淵發布向政府建言的白皮書,甚至能說出台灣不適合發展觀光,因為台灣太髒了。
經濟部和台電一味只知道增加電力供給,不把環保放在心上、過去還偏向核電的思維,當然都不免相當程度是因為主要仰視這些工業用電大戶的鼻息,受他們的影響,甚至綁架。
--------台積電的指標--------
那數十年來都如此了,為什麼現在就不行?
很簡單,國際對台灣半導體業需求加大、對岸台商回流、全球氣候劇變這三個因素的影響下,經濟部及其屬下的台電如果仍然維持長期以來的思維和習慣,這個全球工業用電第四便宜的脫疆野馬,不知道會墬入哪個深淵。
「開放台電」研究期間,我們訪問台電的電力中控室的一位專家。他不無得意地說,以他的經驗,每天早上他看看情況,自己用筆先畫出一天整天的用電曲線,不會有什麼差錯。
但是最近的連續停電,我們連續看到台電承認「用電高於預期」、「因負載突升,供電能力不足」而出問題。今天世界的情勢變化,不再是你能用過去經驗畫出曲線來預測的了,電力管理當然更是如此。
台電不做電力需求的管理,而只想以便宜的電力供給工業用;對工業用電的詳細分配,又一向不肯說明,說是事涉客戶營業機密。
所以,我們要如何面對台積電,是一個關鍵指標。
如本文開頭所言,根據台積電2019社會責任報告,當年台積電全球用電量為143.27億度,相當於全台北市一年用電量的91%。並且,按照Bloomberg Intelligence的估計,到2023年,也就是四年之內,台積電的用電量將再擴增一倍。
要一年供應143.27億度的電,需要多大的發電機組呢?據我問台電的人,需要2GW的機組,相當於核二廠的全部兩個機組,或是中火的四部機組。
而台積電原來是歷經三十多年的發展,到2019年才出現這麼大用電的需求,接下來到2023年,四年之內卻就要加倍,再需要相當於核二廠的全部兩個機組,或是中火的四部機組。
大家都說台積電是護國神山,要繼續留在台灣,但是經濟部和台電應該要求台積電說明清楚其需電規劃。未來新增加這麼大的用電需求,到底有多少比例是要由台灣提供?台積電既然可以公布其全球用電量,顯然並不把這當作營業機密,因此對外說明其中屬於台灣的比例應該不是難題。
對於台積電,還應該𨤳清一件事情。
同樣在台積電2019社會責任報告裡可以看到:台積電全公司用電量只有7%是購買再生能源,但在海外據點是百分之百都使用再生能源。(第95頁)
世界頂級企業,都在推動百分百使用再生能源。台積電在台灣以外的據點,百分之百都使用再生能源,顯然是呼應這個趨勢。但是為什麼在台灣只這麼消極地購買7%的再生能源?那其他使用的能源都是如何構成?
「開放台電」的研究過程裡,我訪問當時董事長朱文成那天,他說有次張忠謀問過他是否能自建電廠。朱文成說只要台積電想,他一切都可以搞定。但是台積電最後還是沒有。
那台積電是為什麼放棄?
是因為政府法令不足?還是台電的配合無法令台積電放心?
不論如何,正因為台積電是「護國神山」,實際的需電量又如此之大,應該清楚地解釋他們為什麼只選擇當一個消極的消費者。
這是應該不只向政府和台電說明,也該公開向社會大眾說明的。
台積電有足夠實力扮演重新型塑台灣能源發展方向的領頭羊。
有台積電當範例,我相信政府和台電對其他工業用電戶都會有新的要求基礎。
反之,台積電也可能帶頭把政府和台電引向無底深淵。
從這裡延續,可以看出藻礁和三接在考驗我們的到底是什麼。
--------藻礁和三接的核心議題--------
民進黨政府所提出的「三接」計劃,當然比國民黨時代好了不知多少,確實把對藻礁造成的傷害降低太多。
也因此,很多人認為「三接」和「反核四」是兩難,是應該兩害相權取其輕。
但是,我認為這樣看的話,錯過兩個重點。
第一,這也落入了台電只知「增加電力供給」的思維。
經濟部和台電還是應該先𨤳清近二十年增加最大用電量的工業用電的電價是否合理、這樣一路增加的用電量是否合理、如何滿足台積電三年內就要倍增的用電需求,如何滿足其他半導體業者要擴增的需求、如何滿足回流台商的用電需求,並且推動分時電價,掌握調節工業用電的需求方法。
他們自己連這一切都沒搞清楚之前,就說「三接」增加總共才 2.24 GW的發電機組可以解決能源轉型危機,太沒有根據。
檢視「三接」,光是看經濟部和台電說這比以前國民黨執政時期的版本改善了多少,沒有意義。
我們應該跳開台電一切先考慮「增加電力供給」的思維,跳開經濟部服務工業用電大戶的思維,在一個劇變的年代,檢視整體產業和電力版圖的供需規劃,再來看現在這個「三接」版本到底有什麼作用,再來判斷是否值得大家冒一些風險。
否則,光是增加2.24 GW的機組有什麼用?不要忘了,光台積電未來三年就需要2G發電機組。
二,這也落入了經濟部和台電定下的遊戲規則,一切在他們掌控之下而不自覺。
現在就要「三接」,是因為台電說不然接下來電力的「備用容量率」就要達不到法定的百分之十五標準。
把「備用容量率」定成百分之十五,並不是什麼真理,也沒有什麼科學根據。過去國民黨執政時期,台電在「增加電力供給」無限上位時代,還曾經定到百分之二十五。講得像是不足百分之二十五就會缺電。後來這三十年來,「備用容量率」一路從百分之二十五降為百分之二十,再百分之十六,再百分之十五,也從來沒出現過結構性缺電。
所以,光只是主張「備用容量率」不到百分之十五就要惶惶然,是沒有根據的。
覺得「備用容量率」不到百分之十五就要惶惶然,其實主要是因為沒做需求管理。而不做需求管理,繼續任憑電價全球第四便宜的野馬暴走,不要說「備用容量率」百分之十五,只怕「備用容量率」百分之五十也應對不了頻頻出現「因負載突升,供電能力不足」、「用電高於預期」而導致的缺電危機。
我們只會一路快馬跳進無底洞。
--------
這兩篇文章,我已經把我從2016年「開放台電」以來,到現在看到的危機都寫出來了。
長短期問題如何應對,其實看了這兩篇文章的人,應該心裡都已經有數。
不過,明天我還是會再整理一些摘要和建議,提供給蔡英文總統,也提供給社會大眾一起參考。
白皮書範例 在 Facebook 的最讚貼文
#2021智慧城市轉型
#後疫情時代醫療科技思維
https://youtu.be/8vkhp_e80X0
(影片)
今天上午在智慧城市轉型與後疫情時代醫療科技思維記者會,除了向前線醫療專業人員道出感謝之外,也和現場的醫學先進們分享疫情發生以來北市府做了哪些措施。我當上副市長3個月後就成為防疫指揮官,其實當時內心相當惶恐,但也感謝許多市府同仁和市民的共同努力,讓疫情對城市的影響降到最低。
去年2月21日全台第一家防疫旅館在台北市上線,為了能夠提供更多有檢疫需求的民眾在隔離期有合適安心的住所,台北市整理了防疫照護的SOP,以設立更多合格的防疫旅館,也將旅館的資訊公開透明化,從國外回台的人都可以事先上網搜尋到資訊。另外也感謝救國團全力支援與市府協力設置了安心檢疫所,我之前也親自去探訪過,環境和人員都整理訓練的一絲不苟,名副其實讓人「安心」!
而面對後疫情時代的經濟轉型,台北市政府已經整理出《新常態新台北,台北市後疫情時代產業數位轉型政策白皮書》,去年也翻譯成全英文,分享給國際各城市我們的防疫經驗,接下來我們要學習如何調適與疫情共存,台北市已經開發數位基礎建設「台北通」APP,未來也會著重建立大數據中心、數位人才培育、產業轉型輔導,希望持續發展「宅經濟、零接觸」服務。
現在我們已經開始思考當未來疫苗量大時,該如何安排場地和動線讓民眾能夠安心的接種疫苗,台北市政府會配合中央的政策,秉持著理性務實的態度,用科學的方式應對,給市民們一個安全又現代的城市。
白皮書範例 在 Taipei Ethereum Meetup Facebook 的最佳解答
📜 [專欄新文章] Uniswap v2 實作 : 從創建交易對到Ether 換 Dai 投入 Compound
✍️ 田少谷 Shao
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
Uniswap v2 實作 : 從創建交易對到Ether 換 Dai 投入 Compound
V̶y̶p̶e̶r̶ Solidity coding time!
Image source: https://uniswap.org/
Outline
一. 前言二. 程式碼結構 1. Wrapped Ether(WETH)? 2. Impermanent Loss三. 創建交易對 - 準備 Interfaces四. 注入資金 - 注意事項五. 兌換虛擬貨幣六. 取得報價作為預言機七. 自行兌換 WETH八. 結語
一. 前言
暨上一篇解釋了 Uniswap 的演算法後,由於個人有使用 Uniswap v2 的需求,因此整理後寫成本篇,希望能幫助到其他也需要用 Uniswap 的讀者!(不熟 Uniswap 的人也可以參考區塊勢 許明恩 Astro Hsu 寫的介紹文:點我)
Uniswap 解析:恆定乘積做市商模型 Constant Product Market Maker Model 的 Vyper 實作
本文希望透過實際操作 Uniswap 我個人會用到、我認為大家比較常會用到的功能,來讓不熟悉的讀者快速了解其程式架構(v2 相較 v1 繁複)、熟悉實作方法,無法顧及全部還請見諒。
以下實作的測試環境為 Rinkeby 測試網,由於只是要講解使用方法,因此選擇在 Remix 上操作。
而 Uniswap v2 跟 v1 的差異,個人沒有很認真研究,大致列舉以下幾點,本文只會就其中幾點在後方進行較詳細的解釋:
使用 Wrapped Ether, WETH (於 二. 程式碼結構 解釋),讓 ERC20 交易對不再需要透過 Ether ,降低 gas 的消耗,但還是可以用 Ether 支付
加入時間權重的預言機,降低被操縱價格的風險,於 六. 取得報價作為預言機 中舉例說明,有興趣者可以看看 白皮書 有詳細介紹
閃電貸
使用 Solidity 而非 Vyper,因為 Solidity 功能上較齊全,於 五. 兌換虛擬貨幣 中舉例說明原因
在開始之前,本文超長,播個背景音樂吧:
二. 程式碼結構
本段落簡單描述 Uniswap 程式碼各部分的功能。若讀者要自己實作,可以參考此處得知該去哪一份程式碼找相應的功能:
Factory / UniswapV2Factory.sol : 創建交易對、查詢交易對的地址與總數;查詢、指定交易對手續費的收款地址
Pair(ERC-20) / UniswapV2ERC20.sol : Uniswap 流動性代幣 ERC20 的部分
Pair / UniswapV2Pair.sol : Uniswap 流動性代幣的其他部分;查詢交易對資訊
Router / UniswapV2Router01.sol : 注入、取出流動性/資金;兌換虛擬貨幣。此合約看似最複雜,其實只是因為收付款的單位可以是 Ether 或是 ERC20,所以有很多重複的函式
ExampleOracleSimple.sol, ExampleSlidingWindowOracle.sol : 預言機的範例程式碼
Library / UniswapV2OracleLibrary.sol : 供預言機調用的函式
Library / UniswapV2Library.sol : 供內部調用的函式
除了描述程式碼結構,為了以下的實作我們還需要知道 Wrapped Ether 是什麼,順便了解其使用原因:
1. Wrapped Ether (WETH) ?
從字面上來解釋,Wrapped Ether 是被包起來的 Ether。那為什麼好好的 Ether 不用還要創造出另一版本,嫌這小小世界的術語不夠多嗎 (ETH, WETH, Dai, aDai, cDai, sDai…)?xD
wETH | ERC20 tradable version of ETH
主因有兩個:廣泛地說,Ether 是以太坊上的原生虛擬貨幣,但它與廣為使用的 ERC20 標準並不相容( ERC20 有 approve(), transfer() 等等功能);而針對 Uniswap 的場景來說,v1 的交易對都一定有 Ether,而使用 Ether 可能會造成 Impermanent Loss,於下方解釋。
因此,就以上兩點的解決方法個別是:
部署一 ERC20 <-> Ether 的兌換合約:使用者將 Ether 付給 Wrapped Ether (ERC20) 的智能合約,合約就會給使用者同等數目的 WETH;拿回 Ether 則有點不太一樣,方法是告訴 WETH 的合約使用者要 withdraw(),WETH 的合約就會把使用者 WETH 擁有的額度設回 0 (或減少) 並返還 Ether,於 五. 兌換虛擬貨幣 中舉例說明
v2 交易對的建立不再只能是 (Ether, ERC20),可以是 (ERC20, ERC20)
2. Impermanent Loss
Impermanent loss 在 DeFi 指的是像 Uniswap 這類用演算法的去中心化交易所,如果交易對是兩幣價不相干的虛擬貨幣,例如:穩定幣 (Dai, USDC, etc) 和 Ether,流動性提供者 liquidity provider 會因為幣價的相對波動而比起直接持有兩幣還損失了一筆。
容我舉個例解釋清楚點,可以搭配我上一篇所寫的 Uniswap 的演算法 來理解:假設一開始 1 Ether 幣價為 100 Dai,只有一流動性提供者 LP 投入了 1 Ether 及 100 Dai (1 * 100 = 100 = k,k值要維持不變),總價值為 200 Dai。當 Ether 的幣價來到 200 Dai,眼尖者會發現資金池中的 Ether 價格低、有利可圖,因此會進行套利,例如:拿 33 Dai 約可以換到 0.25 Ether (0.75 * 133 ≒ 100),比起市場上要用 50 Dai 才能換到 0.25 Ether,套利者賺到了。此時,流動性提供者若將自己的資金提出,0.75 Ether 和 133 Dai 此時的總價值是 283 Dai,看似比當初的 200 Dai 還多,但其實將兩幣放著不動 1 Ether + 100 Dai 在此時就已經是 300 Dai 的價值了。於是,impermanent loss 就變成了 permanent loss :(
三. 創建交易對
- 準備 Interfaces
在開始之前,由於使用到的合約不少,所以我將全部所需整理在此:點我。其中,UniswapImplementation.sol 是本文實作的檔案。
若讀者在自己調用 Interface 時遇到版本問題,就依照 compiler 提供的指示稍作修改即可。我所整理的合約都修正過版本的差異、以下的實作也測試了可行,因此可以安心使用。
進入正題
通常大家使用的 Uniswap 資金池都是已經存在的,而如果想要上架自己的虛擬貨幣就要自己創建一組新的交易對,有兩種方式:在 Uniswap 官網上執行或是透過呼叫 Uniswap 的合約來建立,本文使用合約的方式。
首先,我們需要決定資金池為哪兩種虛擬貨幣,那就很普通地選 ETH 和 Dai 吧。雖然選了 ETH,但如同上方所述實際上必須使用 WETH,於是記下其在 Rinkeby 上的位置 。Dai 就使用 Compound 部署在 Rinkeby 上的版本,位置在 0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa。
接著,打開 IUniswapVFactory.sol,依照官方文件的指示將此合約部署在 Rinkeby 上的 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f。以下會有許多由 Uniswap 文件得知的合約地址及其他資訊等等,就不再一一附上來源或畫面截圖!
如上圖黑框所示,輸入了地址後按下藍色按鍵就完成部署了。接著,如下圖將 Dai 的地址 及 WETH 的地址輸入 createPair():
由於這個交易對我已經部署過了,因此讀者若想嘗試就麻煩去找別的 Rinkeby 上的測試幣了、或自己發一個! 完成後可以用 getPair() 輸入兩幣地址來確認交易對被建立成功:
如果想要進一步核對,可以先呼叫下圖紅框中的 allPairsLength(),得知當前總共有幾組交易對,再將 (交易對數 - 1) 輸入 allPairs(),就能得到和上圖一樣的地址。需要減 1 是因為陣列的 index 從 0 開始。
allPairsLength 的值會因為其他人的使用而增加,故日後可能會和本圖產出的 9 不同
四. 注入資金
看到標題的讀者可能會想:為何要把注入資金/流動性和上方的創建交易對分開呢?因為注入流動性這個功能被放在了 UniswapV2Router01.sol 中,所以就分開解釋。
雖然上一節只需要複製貼上按按鍵,但接下來要探討的注入資金 addLiquidity() 及虛擬貨幣的交換 swap()比起創建交易對 createPair() 是較有可能被融入到其他 DeFi 服務的功能(應該不太會有人會一直需要創建新的交易對),因此打開 UniswapImplementation.sol、要開始 Solidity coding!
如果不熟悉為何別的 DeFi 會需要在自己的服務中使用 Uniswap,可以搜尋 DeFi Money Lego/ DeFi 樂高,顧名思義就是在一個 DeFi 服務上使用另一個 DeFi 服務。實際的例子有:Aave 的新功能是可以拿往 Uniswap 注入流動性後得到的流動性代幣再投入 Aave 來賺取利息,以及下一節兌換虛擬貨幣的功能可以在 Pelith 的輕鬆貸 EasyDai、一站式 DeFi 組合工具 Furucombo 等場景中看到他們如何將 Uniswap 銜接上其他的 DeFi 服務。
回歸正題
在開始之前,先簡單提及一下有哪些變數、instance 需要初始化:
我們要呼叫 Uniswap 合約的 instance 來進行互動: IUniswapV2Router01
不只需要 Dai 的 instance,也需要 Dai 和 WETH 的地址;DaiAmount 和 ETHAmount 是為了稍後注入流動性所設置的,本文假設第一筆流動性我們使用 200 Dai + 1 Ether
immutable 是版本 0.6.5 加入的,用途是讓變數只能被讀取 read-only,但不同於 constant 的是能夠在 constructor() 中賦值。之所以各 instance 的地址不一起加上 immutable ,是因為若加上了,這些地址就不能在 constructor() 中被使用
p.s. 由於 gist 沒有 Solidity 的 syntax highlighting,所以隨便用了 .js 請忽略
看完了初始設定後,由於我們目前鎖定的資金池是 Dai 及 ETH,因此使用如下的 addLiquidityETH() 此函式,可以直接匯入 ETH 及 Dai。
本處我使用長度為 3 的陣列 addLiquidityResult 來記錄注入資金後的返回值:注入 Ether 的數量、Dai 的數量及返回的 Uniswap 流動性代幣的數量。實際上應該要依照不同使用者記錄的他們執行 addLiquidity() 後各自的返還值
第五行中的 approve() 是為了讓 UniswapV2Router01 的合約能夠從我們部署的合約 UniswapImplementation 取得 200 Dai 的使用權
於第六行 addLiquidityETH() 後方的大括號 {value: ETHAmount},這是 Solidity 0.6.0 後版本如果要在呼叫 function 的同時送入 Ether 的標準寫法,以前的寫法 .value() 目前也還能用但 compiler 會給提示
addLiquidityETH() 的第三、四個參數為最少要成功注入的數量。使用者能夠成功注入的數量取決於資金池中兩虛擬貨幣當下的數量,而本處直接給 0 比較方便
這邊非常重要的是上述程式碼還欠缺了一個無法被寫在合約內的步驟:使用者要同意這個被部署的合約 UniswapImplementation 可以從自己的帳戶中轉出 200 Dai。因此,將 ERC20 (Dai) 部署在 Rinkeby 上的位置,也就是0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa,接著輸入被部署合約的地址以及 200 Dai = 200000000000000000000、按下 approve() 後準備作業完成,如下圖。
終於可以呼叫 addLiquidity() 了! 如下圖,在紅框中以 1 Ether 呼叫黑框中的 addLiquidity() 後,就能成功將資金注入到 liquidity pool 了! 由於本文寫在測試後,因此沒有留下第一次 addLiquidity() 的結果 :(
此處被部署的合約位置跟上方截圖不同,因為其中測試了一些東西所以重新部署qq
接著,可以拿出 IUniswapV2Pair.sol,將其部署在 三. 創建交易對 中成功部署的位置 0x03E6c12eF405AC3F642B9184eDed8E1322de1a9e,使用黑框中的 getReserves() 就可以看到資金池中確實有匯入的資金! (本處依然沒有第一次使用後的截圖,因此截圖只是為了讓讀者看到 getReserves() 的結果)
此圖黑框中的值代表:在資金池中,Dai的數量、Ether的數量及上一次匯入資金的時間戳記
- 注意事項
使用 addLiquidity() 時需要小心的地方是:除了第一筆注入的資金可以自行決定兩虛擬貨幣的數量,第二筆開始就會依照其演算法算出兩幣可以投入的各自數量,因此使用者放入的兩幣中可能會有部分的其中一幣被 Uniswap 返回。
上方的程式碼只是為了第一筆流動性所寫,如果不是第一筆的情況就需要用成功注入流動性後的返回值(例如筆者的作法是用一陣列 addLiquidityResult 來存結果)來把沒有成功注入的資金返回給使用者。
五. 兌換虛擬貨幣
本節使用的兌換功能依舊是來自 IUniswapV2Router01.sol。
由於兌換虛擬貨幣實際上只有五行不到的程式碼,那麼就來把兌換 Ether 而得到的 Dai… 投到 Compound 來賺取放款利息吧! (雖然只是在測試網) 如果覺得這個場景似曾相識,沒錯,這就是上面提到的 輕鬆貸 EasyDai 的不專業版本!
首先將 Ether 和 Dai 互換的邏輯完成:
Ether 換 Dai : 使用 swapExactETHForTokens(),給某數量的 Ether 能換多少 Dai 是多少
Dai 換 Ether : 使用 swapExactTokensForETH(),作法只差在要把 Dai 轉到當前合約,再同意 UniswapV2Router01 可以從當前合約把 Dai 轉走
兩個做法的第二個參數都是可以自行指定兌換的路徑,此處就直接給 WETH 和 Dai 的地址即可(順序有差)。需要注意的是這個路徑要是動態陣列 dynamic array,而這就是 Vyper 所不支援的功能! 動態陣列跟靜態陣列宣告方式的差別我有註解在程式碼中
此處就先來試試 Dai 換 Ether 吧!和上方一樣,在使用時也要先 approve() 當前合約,當前合約才能轉走使用者的 Dai。
由上方的截圖可以很清楚的看到 Dai 換 Ether 這個動作牽涉到的資金轉移路徑:
Dai: 我的帳戶→當前合約→交易對所在合約
WETH: 交易對所在合約→UniswapV2Router01
Ether: WETH 合約→UniswapV2Router01→我的帳戶
以上的路徑有些人稍微思考後可能會納悶:為什麼上方沒有一筆 WETH 從 UniswapV2Router01 再轉到 WETH 合約的動作呢? 這就是在 Wrapped Ether (WETH) ? 中提到的案例。原因是:把 WETH 還回 WETH 的合約時實際上使用的函示是 withdraw() 而非 transfer(),而在 WETH 合約中發生的只是把使用者 WETH 擁有的額度歸零或減少而已。
接下來就是把 Dai 轉到 Compound 的部分。由於 Compound 不是本文重點,此處只求功能正常,因此比起真正的實作方法當然是簡化許多。
一如往常初始化 Compound 合約的 instance
ETH 換 Dai 後放入 Compound : 將用 ETH 換得的 Dai 的數量,也就是 swapExactETHForTokens() 返回的第二個值,approve() Compound 的合約後就可以用 mint() 匯入了! 要注意的是,ETH 換成 Dai 後的收款地址(第四個參數)是當前合約,才能從此合約轉 Dai 到 Compound
還款給使用者: 用 redeem() 取出 Dai,一如往常同意 UniswapV2Router01 使用 Dai 的權力
之所以說這個程式碼不能真的拿來用是因為:cDai 轉給使用者、讓使用者自己持有是比較安全的作法;即使選擇把 cDai 留在當前合約,以上程式碼檢查 cDai 數量是用當前合約 address(this) 去檢查,實際上應該要去記錄每個使用者所擁有的 cDai 數量
最後附上截圖,可以看一下資金的轉移路徑:
ETH -> WETH -> Dai -> cDai (Compound)
cDai -> Dai -> WETH -> ETH
六. 取得報價作為預言機
若使用 Uniswap v1的報價作為預言機,攻擊者可以利用其演算法造成的滑點來操控價格。為此,Uniswap v2 提供了兩個加入時間權重的合約範例:
ExampleOracleSimple.sol : 簡單版
ExampleSlidingWindowOracle.sol : 複雜版;Sliding Window 在此場景是指透過改變擷取資料(歷史價格)的片段,用該特定期間的價格來做成時間權重,讓使用上更靈活!
本處以簡單版為例。打開 ExampleOracleSimple.sol,由於一些匯入檔案的問題我將 UniswapV2OracleLibrary 也放在這份檔案中。
做法非常簡單:將 UniswapV2Factory、Dai 及 WETH 所在的地址作為部署合約 ExampleOracleSimple 時的輸入值就完成了。部署成功後會有個 24 小時的鎖 Time lock,因為這個預言機是有時間權重的,所以並不是一部署完就能立刻使用。若要體驗更新價格此功能可以使用我部署的兩個,其位置我寫在註解中。
將 WETH 或是 Dai 的地址和要查詢的數量輸入 consult() 就能查到兩虛擬貨幣的價格:
1 ETH 價格約為 97 Dai
1 Dai 價格約為 0.01 ETH
然而,在測試網上我們沒辦法拿著預言機查到的價格套入演算法來核對,因為測試網上的 Uniswap 沒有啟用收費機制,而 k 值要在收費機制啟動時才能被計算,欲知詳情者就麻煩去看官方文件了!
七. 自行兌換 WETH
上方雖然有提到 WETH 在 Uniswap 中的使用原因及場合,但或許有人想試著自己動手將 Ether 換成 WETH、把 WETH 換回 Ether。方法非常簡單,將 WETH.sol 部署到 0xc778417E063141139Fce010982780140Aa0cD5Ab 就能使用,如下圖:
按下綠框中的 At Address 後,使用下方黑框中的 deposit 搭配在中間的黑框輸入所要兌換 Ether 的量,就能成功換到 WETH。同理,圖中未顯示的 withdraw 功能就是讓人輸入 WETH 來換回等量的 Ether。
稍微提一下,如果是第一次兌換,將 WETH 所在的地址輸入 Metamask 就能在錢包中看到自己擁有的 WETH 的數量,如下兩圖:
Voila!
八. 結語
呼,雖然上述操作及程式碼的撰寫其實還蠻簡單的,但畢竟 Uniswap 的功能不少、我個人也希望能將小細節解釋清楚些,因此長度遠超過預期...有看到結尾處的讀者,辛苦了xD 希望大家現在對於 Uniswap v2 的內容跟實作方法都很清楚了!
最後,如果本文有任何錯誤,請不吝提出,我會盡快做修正;而如果我的文章有幫助到你,可以看看我的其他文章,歡迎一起交流 :)
田少谷 Shao - Medium
Uniswap v2 實作 : 從創建交易對到Ether 換 Dai 投入 Compound was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌
白皮書範例 在 白皮書範例在PTT/Dcard完整相關資訊 - 輕鬆健身去 的美食出口停車場
關於「白皮書範例」標籤,搜尋引擎有相關的訊息討論:. [PDF] 2016年能源產業技術白皮書- 國家發展委員會2016年12月1日· 「2016年能源產業技術白皮書」以經濟部能源局 ... ... <看更多>
白皮書範例 在 白皮書範例在PTT/Dcard完整相關資訊 - 輕鬆健身去 的美食出口停車場
關於「白皮書範例」標籤,搜尋引擎有相關的訊息討論:. [PDF] 2016年能源產業技術白皮書- 國家發展委員會2016年12月1日· 「2016年能源產業技術白皮書」以經濟部能源局 ... ... <看更多>