雖然這篇latex換段鄉民發文沒有被收入到精華區:在latex換段這個話題中,我們另外找到其它相關的精選爆讚文章
在 latex換段產品中有7篇Facebook貼文,粉絲數超過10萬的網紅毛毛遊戲城堡,也在其Facebook貼文中提到, (開學好物團) MAGIC護眼LED檯燈+德國輝柏文具團+play bag抗菌袋 🔺下單網址→ https://gbf.tw/vbcx1 ✅圖文分享(文具)→ https://reurl.cc/WEYk0e ✅圖文分享(檯燈)→ https://reurl.cc/4RzQ6V 開學用品團>> Ma...
latex換段 在 毛毛遊戲城堡 Facebook 的最佳貼文
(開學好物團) MAGIC護眼LED檯燈+德國輝柏文具團+play bag抗菌袋
🔺下單網址→ https://gbf.tw/vbcx1
✅圖文分享(文具)→ https://reurl.cc/WEYk0e
✅圖文分享(檯燈)→ https://reurl.cc/4RzQ6V
開學用品團>> Magic護眼LED檯燈、德國輝柏文具、play bag抗菌收納袋同步開團囉!!!
在家待好久,這段時間用檯燈的時間也比以前多很多很多,接下來準備要開學了,無論是準備升小一的孩子,還是已經開始有大量閱讀需求、大量坐在書桌前面做勞作…等習慣的孩子,都必需要有一支好燈陪伴他們長大!
陪我超過10年的檯燈品牌,當然也是莫莉需要檯燈之後唯一首選, 圖文分享裡也寫得超級詳細,有需要的可以點進去看 → https://reurl.cc/4RzQ6V
🔶 MA1688本團是升級後的晶片,增加了可以三段調整亮度的全新升級版,團購價是$7999(原價要$12800 省超多的!),是目前莫莉寫作業及閱讀的主要檯燈,大桌面或手足共用很適合!
MA1688燈頭較長、照幅也很廣,色溫是4000K的暖白光 (白光微透黃) ,是很適合閱讀、寫作業、及工作的舒適色溫,長期近距離使用的讀寫讀寫,色溫控制在4000K左右是最為合適的,也是目前Magic所有檯燈中最頂級的一款,我們放在小妞每天放學回來的寫功課及複習書桌使用,非常適合。
‥
🔶MA1388是我們每次開團賣最好的一款,開價價$2690、使用日本日亞晶片、穩定度高,是很值得入手的單人檯燈。
MA1388 算是中等價位的一款檯燈,色溫是5000K的白光(像中午的陽光比較有精神),同樣適合畫畫 寫字及工作,光源感覺接近外面的自然光,5000K是自然明亮的白光,可以使精神集中、不容易睡著,所以非常適合用來寫作業、工作和需要集中精神的畫畫
照射範圍是100cm,是單人書桌、小朋友一個人寫作業看書的好選擇,演色性到達90的高顯色度,照度同樣有1250Lux以上
剛才1688的燈頭是60cm這麼長 照幅是150cm
這款1388的燈頭是38cm適合單人使用 照幅是100cm
這兩款外型雖然相似,但尺寸、色溫、演色性、照幅都有明顯不同,單價的部份也有明顯的差異,大家可以依照家中的需求做選購
‥
🔸MA328是開團唯一可以調整四段色溫的款式,以CP值來說是很高的,預算有限的話 這支也是絕佳選擇! 團購價是$2450
#本團限量_即將售完_下團要漲價了
MA328除了可以調整四種色溫(3000~5000K)、還可以無段式調整亮度,外型也簡約好看,觸控式面板頗有高級感!
色溫有工作模式5000K、閱讀模式4200K、螢幕模式3800K、休閒模式3000K,是一款屬於全家人,媽媽追劇、工作、小朋友看書寫作業都很便利的檯燈
當然相較於前面兩款的3D雙臂設計 可調的角度沒辦法這麼的大幅,但是以它的單價及CP值來說 可以說表現相當優秀了!!
‥
🔷MA1388與1688都是附桌夾,若需要放置桌面,就需要另外加購底座,我們家是都用夾的,比較不佔位。 而MA328是有底座的檯燈,無法換成夾式。
🔸常見Q&A在這裡
Q: 如果以後燈泡壞了怎麼辦? 能自己換嗎?
A: Magic檯燈是LED燈,使用的是LED晶片、並不是燈泡,一般LED壽命至少都有10年,未來若真的壞掉也可以聯繫原廠維修。目前我手邊最久的MAGIC已超過10年,還在持續使用中哦!
Q: 加購區的 #立燈組 和 #專用底座 有哪裡不一樣?
A: 立燈組是放在地上使用的,有70cm的一根長桿,可以放在沙發邊、或是當鋼琴燈…等。專用底座則是放在桌上使用的,只有底座 沒有延長桿。
Q: 一定要加購底座才能使用嗎?
A: MA1688出廠包裝是附「桌夾」,可以直接夾在桌板使用,若是必需要放在 #桌面上 使用才需加購底座哦! MA328本身就是桌上型,僅能放在桌上使用 無法更換桌夾,因此無需再加購其他配件囉!
/
⭐️ 德國百年品牌--輝伯文具系列
✅圖文分享→ https://reurl.cc/R1d37Z
#大班低年級必備
輝伯的三角防滑點點筆,正確名稱叫做 Jumbo握得住鉛筆,這款是比較粗的三角筆,它凸出的防滑顆粒可以讓正在學握筆的低年級生或大班孩子確實握緊 不易下滑,好寫好握好上手、小朋友握筆輕鬆不抗拒
#中高年級首推
三角筆同時還有另一款較細的,連筆尖都是比較細的→ #三角點鑽石墨鉛筆 這支適合已經會寫字、手部肌肉也發展較完整的中高級年生
#馬卡龍旋轉雙孔削鉛筆器
這個是鉛筆盒必備的削筆器,真心超推薦! 是方便又不佔空間的小物,小妞也放一個在筆袋裡,筆突然斷掉或不夠尖的時候可以隨時自己削、不用等到回家,而且即便小一新生也很安全,沒有露出刀頭、放在筆袋裡不怕手伸進去找筆的時候割到,這個我推薦一定要順手帶上幾個備用!
#安全筆套橡皮擦
可以搭配粗的三角筆 當三角筆的筆蓋、同時也可以當做橡皮擦用哦! (而且還擦得蠻乾淨),自動鉛筆也可以蓋哦! 放在筆袋裡也可以保護筆尖、同時不會讓筆袋都被畫得黑黑髒髒的,萬一忘記帶橡皮擦的時候還可以臨時拿來用一下!
#水性彩色鉛筆_棒棒筒裝
棒棒筒色鉛筆非常好用! 輝伯的色鉛筆優點就是顯色度很好,這個棒棒筒設計又很輕巧好攜帶,像小妞的已經是36色 還是非常小一筒,出門整個方便! 在家也很常看她拿出來在畫
/
#PLAY_BAG抗菌萬用環保袋
這應該是我目前為止看過最美的夾鍊袋了!!! 無論是小朋友上學,或是外出旅行都很方便,可以裝食物、尿布、換洗衣物、寶寶的奶嘴 固齒器、口罩等等
無添加BPA,PVC,Latex & Phthalates 成份安心 耐熱90度,食品級抗菌材質,使用來自日本進口的抗菌原料,經證實可以有效對抗一般細菌與大腸桿菌等細菌,經過多項菌種實驗以及第三方認證,都證實可以抑制細菌生長
非常適合拿來裝一些像是食物或者寶寶的奶嘴、大人小孩的口罩…等等需要抗菌的物品,袋子本身很厚實、可以清洗之後重覆使用,還可以放冷凍、甚至可以進洗碗機
更厲害的是,它不只有夾鍊款式,還出了魔鬼氈款!! 這個我大推給小朋友帶去學校的口罩或用品,因為魔鬼氈不用精準對齊就可以輕鬆封口,很適合小朋友使用,尺寸有分 迷你、小型、中型、大型 四種尺寸
✅圖文分享→ https://reurl.cc/WEYk0e
/
#本團出貨時間
預計8/17開始陸續出貨
貨提早到就會提早安排出貨,若有不方便收貨的時間請備註哦!
#本團運費
購買檯燈即享免運費
未買檯燈運費80元(外島100元)
#本團客服
客服專線 : 07-3626090
客服信箱 : go2buyservice@gamil.com
LINE ID : @ffw7750y (記得加前面的@)
/
8/3~8/9 MAGIC護眼LED檯燈+德國輝柏文具團+play bag抗菌袋
🔺下單網址→ https://gbf.tw/vbcx1
✅圖文分享(文具)→ https://reurl.cc/WEYk0e
✅圖文分享(檯燈)→ https://reurl.cc/4RzQ6V
latex換段 在 毛毛遊戲城堡 Facebook 的最佳貼文
((開學閃團來囉)) MoonRock護脊書包+Magic護眼檯燈+德國輝伯文具+Play bag萬用抗菌密實袋
🔺下單網址→ https://gbf.tw/r1nok
本團是為了8月底開學緊急加開的閃團,單買書包會在8/28前出貨完畢!
開學要用的書包、色鉛筆、鉛筆 文具等,還有帶口罩和換洗衣物用的抗菌袋、跟寫作業必備的護眼檯燈 通通都在這一團囉!
/
⭐️ MoonRock護脊書包
✅圖文分享→ https://reurl.cc/yZdZ96
小一新生首推SP1、中大班建議SS1
中年級MR3S 或MR1S、高年級MR6或MR7
還有! 學習袋必買 尤其有在補習或上安親的
🔥本團獨家優惠 SS1書包+便當袋優惠組合價3312元
🔥獨家優惠2 買SP1+SS1 加碼再送筆袋(隨機)
🔥本團優惠3 MoonRock系列購滿$4000即贈書架一個(其餘商品不列入滿額禮)
MoonRock是全球第一個通過美國脊椎神經科學會認證的護脊書包品牌!背起來很貼背、走路不會歪來歪去,而且非常透氣不悶熱,更有獨家的護脊背板結構 在包包內藏有脊骨形狀的鋁合金桿,能幫忙支撐背部 達到保護脊椎的功 是真正的護脊,不是喊喊而已
6階段書包的大致身高及年齡層如下:
#SS1 95~125cm 約中班~2年級
#SP1 95~140cm 約大班~4年級
#MR3S 120~140cm 約1~4年級
#MR1S 130~155cm 約3~6年級
#MR6 140~165cm 約4~8年級
#MR7 135~170cm 約4~8年級
/
⭐️ 德國百年品牌--輝伯文具系列
✅圖文分享→ https://reurl.cc/R1d37Z
#大班低年級必備
輝伯的三角防滑點點筆,正確名稱叫做 Jumbo握得住鉛筆,這款是比較粗的三角筆,它凸出的防滑顆粒可以讓正在學握筆的低年級生或大班孩子確實握緊 不易下滑,好寫好握好上手、小朋友握筆輕鬆不抗拒
#中高年級首推
三角筆同時還有另一款較細的,連筆尖都是比較細的→ #三角點鑽石墨鉛筆 這支適合已經會寫字、手部肌肉也發展較完整的中高級年生
#馬卡龍旋轉雙孔削鉛筆器
這個是鉛筆盒必備的削筆器,真心超推薦! 是方便又不佔空間的小物,小妞也放一個在筆袋裡,筆突然斷掉或不夠尖的時候可以隨時自己削、不用等到回家,而且即便小一新生也很安全,沒有露出刀頭、放在筆袋裡不怕手伸進去找筆的時候割到,這個我推薦一定要順手帶上幾個備用!
#安全筆套橡皮擦
可以搭配粗的三角筆 當三角筆的筆蓋、同時也可以當做橡皮擦用哦! (而且還擦得蠻乾淨),自動鉛筆也可以蓋哦! 放在筆袋裡也可以保護筆尖、同時不會讓筆袋都被畫得黑黑髒髒的哦!
#水性彩色鉛筆_棒棒筒裝
棒棒筒色鉛筆非常好用! 輝伯的色鉛筆優點就是顯色度很好,這個棒棒筒設計又很輕巧好攜帶,像小妞的已經是36色 還是非常小一筒,出門整個方便! 在家也很常看她拿出來在畫
/
⭐️ 眼科醫師推薦MAGIC專業護眼檯燈
✅圖文分享→ https://reurl.cc/4RzQ6V
Magic檯燈最大的精髓 就是獨家的LED模組,檯燈不僅僅是照明的功能、更是保護眼睛的關鍵,他們家先進的自然光LED技術 讓一切看起來都是那麼自然 而且舒服,無論工作、寫作業、閱讀通通都能擁有合乎需求的舒適明亮感
優質的LED模組系統 不會閃爍、無紅外線&紫外線的傷害,提供舒服而且優質的燈光、防眩光的設計 還有大範圍的照明!
這次幫大家特別挑出三款不同定位的檯燈,其中1688與1388兩款都是使用日本日亞化頂級晶片,1688的晶片等級再高於1388,這兩支都是100%台灣生產製造,目前市面上很難找到仍然堅持使用日本頂級晶片的檯燈了!
/
⭐️ PLAY BAG抗菌萬用環保袋
✅圖文分享→ https://reurl.cc/R1d37Z
PLAY BAG抗菌萬用環保袋應該是我目前為止看過最美的夾鍊袋了!!! 無論是小朋友上學,或是外出旅行都很方便,可以裝食物、尿布、換洗衣物、寶寶的奶嘴 固齒器、口罩等等
無添加BPA,PVC,Latex & Phthalates 成份安心 耐熱90度,食品級抗菌材質,使用來自日本進口的抗菌原料,經證實可以有效對抗一般細菌與大腸桿菌等細菌,經過多項菌種實驗以及第三方認證,都證實可以抑制細菌生長
非常適合拿來裝一些像是食物或者寶寶的奶嘴、大人小孩的口罩…等等需要抗菌的物品,袋子本身很厚實、可以清洗之後重覆使用,還可以放冷凍、甚至可以進洗碗機
更厲害的是,它不只有夾鍊款式,還出了魔鬼氈款!! 這個我大推給小朋友帶去學校的口罩或用品,因為魔鬼氈不用精準對齊就可以輕鬆封口,很適合小朋友使用,尺寸有分 迷你、小型、中型、大型 四種尺寸
顏色花色都很美,各尺寸可以裝些什麼 文章裡面都有哦!
/
#本團出貨時間
1. 單買MoonRock書包筆袋8/21~8/28出貨
2. 全團訂單9/2開始出貨
3. 書包建議單獨下單 才可以提早收到哦!
貨提早到就會提早安排出貨,若有不方便收貨的時間請備註哦!
#本團運費
購買檯燈即享免運費
未買檯燈運費80元(外島100元)
單筆滿3000免運
#本團客服
客服專線 : 07-3626090
客服信箱 : go2buyservice@gamil.com
LINE ID : @ffw7750y (記得加前面的@)
粉絲團私訊: Go2buy 親子生活館
/
8/17~8/23 MoonRock 護脊書包&MAGIC 護眼檯燈&輝柏文具&PLAY BAG抗菌萬用環保袋
🔺下單網址→ https://gbf.tw/r1nok
✅圖文分享(文具/抗菌袋)→ https://reurl.cc/R1d37Z
✅圖文分享(書包)→ https://reurl.cc/yZdZ96
✅圖文分享(檯燈)→ https://reurl.cc/4RzQ6V
latex換段 在 Taipei Ethereum Meetup Facebook 的最佳解答
📜 [專欄新文章] Uniswap 解析:恆定乘積做市商模型 Constant Product Market Maker Model 的 Vyper 實作
✍️ 田少谷 Shao
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
在 🦄 Uniswap v2 到來之前徹底了解 v1 的設計與演算法!
Image source: https://uniswap.org/
Outline
一. 前言二. 恆定乘積做市商模型 Constant Product Market Maker Model 1. 計入手續費 2. 程式碼結構 3. 演算法核心與實作 4. 段落小結三. 流動性 Liquidity 1. 第一筆流動性注入、決定k值 2. 除了第一筆以外的情況四. 結語
一. 前言
暨上一篇開始接觸了 Vyper 後,我找了 Uniswap 的程式碼來更加熟悉 Vyper 的實作方法,順便研究了其演算法,然後就又寫了一篇 xD
類 Python 的合約語言 Vyper 開發入門:與 Solidity 差異、用 Truffle 部署、ERC20 賣幣合約實做
Uniswap 是以太坊上非常成功的自動做市商 Automated Market Maker (AMM)。本次我將用的 Uniswap 的程式碼搭配由 Runtime Verification 這家審計公司對 Uniswap 所做的形式化驗證結果來解釋恆定乘積做市商模型的 Vyper 實作 (2018 審計時 Uniswap 就已經是用 Vyper 而非 Solidity 了):
智能合約程式碼:https://github.com/Uniswap/uniswap-v1/blob/master/contracts/uniswap_exchange.vy
合約審計結果:https://github.com/runtimeverification/verified-smart-contracts/blob/master/uniswap/x-y-k.pdf
本文將以講解實作概念及數學推導為重點,程式碼的部分只是輔助。審計結果將恆定乘積做市商模型演算法的數學推導寫得非常清楚而有趣(?),建議有興趣者可以整份看過一遍,相信得到很多收穫!
至於更多 Uniswap 的介紹有興趣者可以參考 吳冠融 Roger Wu 所撰寫的簡介與使用流程:
解析 DeFi 項目《Uniswap》(一)Uniswap 是什麼?
解析 DeFi 項目《Uniswap》(二)Uniswap 如何使用?
在開始前的最後,先預告本文頗長,所以來播個被 Youtube 推薦的歌吧:
二. 恆定乘積做市商模型 Constant Product Market Maker Model
交易所如果要去中心化、也不使用掛單 order book,就需要靠演算法自動算出交易標的的數量與價格,而 Uniswap 使用名為恆定乘積的演算法,其來源可追溯自 Vitalik 的這篇文章:點我。
公式非常的簡單:x * y = k。令交易的兩虛擬貨幣為 X 和 Y,各自數量為 x 和 y,兩貨幣數量的乘積 x * y 恆等於 k,k 值是由第一筆注入的流動性所決定 (於 三. 流動性 Liquidity 解釋)。
因此,用 ∆x 數量的 X 幣來購買 Y 幣所能得到的數量 ∆y、或是為了購買 ∆y 需要付出的 ∆x 數量,依照此公式進行計算:(x+∆x)(y-∆y) = k,而交易的價格就是兩幣量 ∆x 和 ∆y 的比。
以下公式用 α = ∆x / x 和 β = ∆y / y 來表示 ∆x 和 ∆y 及 X Y 兩幣在交易發生後的新均衡數量:
圖一
1. 計入手續費
在 Uniswap 進行的每一筆交易都會被收取 ρ = 0.003 / 0.3% 的手續費回饋給流動性提供者 liquidity provider ,因此要將手續費納入公式的考量:
圖二
上圖的公式或許不太直覺,我建議不要從 x’ρ 及 y’ρ 開始理解,而是從 ∆x 和 ∆y 兩值開始:手續費 ρ = 0.3% 的意思是會從付款中扣掉 0.3 %,也就是從 ∆x 扣。在有手續費的情況下 ∆x 就變成了 (1-ρ)∆x ,若令 γ = 1-ρ 則為 γ∆x。因此,將圖一中的 ∆x 換成 γ∆x,就會得到以下式子:
source: https://www.codecogs.com/latex/eqneditor.php
將等號左方的 γ 移到右方後就得到了圖二中的 ∆x。同理,由於 ∆y 中的 α = ∆x / x ,用 γ∆x 代換 ∆x 就會得到圖二中的 ∆y (有 α 的地方乘上 γ )。而 x’ 還有 y’ 就可以由 ∆x 和 ∆y 推出來了!
然而,將圖二中得到的 x’ 和 y’ 相乘,會得到:
source: https://www.codecogs.com/latex/eqneditor.php
也就是說,當有手續費使得 γ != 1 /ρ != 0,x’ρ * y’ρ 的值其實會稍微和 xy = k 不同:在實作上 γ = 0.997 / ρ = 0.003,因此 1/γ-1 ≒ 0.003。β = ∆y / y 代表的是換得的 Y 幣佔總量的比例,即使最大值為 1,誤差也只有 1 * 0.003,故可知手續費 = 0.3% 對於 k 值的影響極小。
2. 程式碼結構
了解了基本的公式後,就可以開始研究程式碼是怎麼撰寫的。首先來看各個函式的功能:
addLiquidity() 及 removeLiquidity():轉入與轉出資金,留到 三. 流動性 Liquidity 中說明
getInputPrice() 及 getOutputPrice():最主要的函式,用以計算給 ∆x 所能換得的 ∆y 數量、以及為了得到 ∆y 所要支付 ∆x 的數量。此兩函式會被其他負責進行交易、匯幣的函式使用
三組 (eth->Token, Token->eth, Token->Token) 的 swap() 及 transfer():swap() 的收幣人就是付款人、transfer() 的收幣人不是付款人而是指定的對象。基本上這兩函式就是呼叫 getInputPrice() 或是 getOutputPrice() 後進行匯幣的動作,因此不再多做解釋
3. 演算法核心與實作
在研讀程式碼前,先回顧一下 ∆x 和 ∆y 的公式:
首先我們考慮用 ∆x 所能購買到的 ∆y 的 getInputPrice():
什麼…就這幾行程式碼?是的。
以上的程式碼和公式表達方式不同,因此先將 α = ∆x / x 和 β = ∆y / y 代換回來並將上下同乘 x:
source: https://www.codecogs.com/latex/eqneditor.php
由於 γ = 0.003,可以將上下同乘 1000 後得到:
source: https://www.codecogs.com/latex/eqneditor.php
接著就能來對照程式碼了:
(109行) numerator: input_amount 是欲支付的 X 幣數量 ∆x、output_reserve 是 Y 幣數量 y,再乘上 997 後就是等式右邊的上方 (= 997∆xy)
(110行) denominator: input_reserve 是 X 幣的數量,乘上 1000 再加上剛剛算過的 997∆x,就得到了等式右邊的下方 (= 1000x + 997∆x)
此處要注意的是 Vyper 的除法是無條件捨去,等同於 floor() 函式。這會不會造成嚴重的影響呢?如果熟悉 ERC20 的人應該記得,在發幣時輸入的四個參數中有一個參數代表小數點的位數,如同下方程式碼中的 2 代表最後兩位在小數點後。舉例來說,當 getInputPrice() 收到 1234567 為這個幣的 input_amount 時,代表使用者擁有的幣的數目實際上是 12345.67。因此,即使將結果捨去 0.67 後的數字,影響真的不大,況且如果不捨去而選擇無條件進位,那代表交易所反而要虧損一點點啦,太佛心了吧 xD 有興趣者可以看看審計報告的內容,有更詳細地去定義這些誤差所影響的範圍!
再來我們看若要購買 ∆y 需要付出多少 ∆x 的 getOutputPrice()。
一樣先將 α = ∆x / x 、β = ∆y / y 和 γ = 0.003 代換並上下同乘 1000y 得到:
source: https://www.codecogs.com/latex/eqneditor.php
我們已經看過 getInputPrice() 一次了,所以應該能發現第 122–124 行得出的結果和上式相同。要注意的是這邊的結果反而是無條件捨去後直接 +1,因為這是在計算使用者要付多少 ∆x 才能購買到 ∆y,為了不讓交易所虧只能選擇請使用者多付一點點。
4. 段落小結
以上就是撇除匯幣等函示,恆定乘積做市商的 Vyper 實作,沒錯就這樣而已!Uniswap 之所以可以做到低 gas 消耗就是因為這個演算法本身就非常簡單,所需的運算也就是兩三次乘除法而已!
不過我們還沒結束,接下來要談談如何投入資金/注入流動性,而這部分也包含了決定 k 值的精妙機制!
三. 流動性 Liquidity
流動性指的是交易市場中能夠交易的資金/標的物的量。使用自動做市商 (AMM) 而非掛單的最大好處就是市場一定會有流動性,而缺點就是如果交易量越大就會造成越大的滑點 Slippage,意思就是交易價格變動會越大、得到的價格越差 。
source: https://ethresear.ch/t/improving-front-running-resistance-of-x-y-k-market-makers/1281
我們可以用上面提到的 V 文章中的圖片來迅速帶過,畢竟有關注 Uniswap 的讀者大概都已經看過這圖很多次了。
當要兌換的幣的數量越大/占比越重,例如:20% Y 幣的流動性,就會造成要付出比兌換少量時極為不對稱的高額 X 幣。
接著我們要來探討注入流動性的原則,依照市場是否已經有流動性而區分為兩種情形:
1. 第一筆流動性注入、決定 k 值
以下程式碼是 addLiquidity() 函式中 46-48, 51, 及 64-74 行。當市場上還沒有任何流動性時,不會滿足第 51 行而是進入 64 行的 else。
在第 65 行我們可以看到 msg.value ≥ 10¹⁰,以及在 67 行 token_amount 就是其中一個輸入值 max_tokens。這邊代表的是第一個注入流動性的使用者可以自行決定要注入多少 Ether (≥ 10¹⁰) (= x) 以及相應的幣的數量 (= y),也就是上方提到的 k 值 (= x* y),在本例的 X 幣就是 Ether。(本處先不解釋剩餘的程式碼,留到 2. 除了第一筆以外的情況)
那麼問題來了:第一個注入流動性的人要怎麼決定提供各自多少的兩種幣呢?最好的辦法是依照當時兩幣的市價比,讓兩者的價值 (數量 * 價格) 相同,例如:當 1 Ether 的價格為 100 Dai,注入 1 Ether 以及 100 Dai 是最好的,因為兩種幣的總價值是一樣的,以下舉例說明原因。
當 1 Ether 市價為 100 Dai 時,假設第一人決定注入 1 Ether 和 50 Dai (k = 50),總價值為 150 Dai,我們考慮兩種兌換方法:
Ether -> Dai:用 0.1 Ether 來購買 Dai,依照上方公式 (1+0.1)(50-y) = 50 可得 y ≒ 4.55,也就是說得到的價格是 0.1 Ether = 4.55 Dai,遠低於市價 0.1 Ether = 10 Dai,相信沒有人這麼傻~
Dai -> Ether:用 2 Dai 來購買 Ether,依照上方公式 (1-x)(50+2) = 50 可得 x ≒ 0.038,也就是說得到的價格是 2 Dai = 0.038 Ether,高於市價 2 Dai = 0.02 Ether,那麼眼尖的人就會立刻衝來套利了xD
那麼即使如此,第一人有所損失嗎?當然有!假設路人 A 手上有 30 Dai (= 0.3 Ether),A 看到機會後就把 30 Dai 全換成 Ether:(1-x)(50+30) = 50 可得 x = 0.375,大於原本持有的 Dai 的價值 0.3 Ether。此時,第一人即使立刻抽出現存的全部資金 Ether = 0.625 及 Dai = 80,總價值也只剩下 142.5 Dai,比起原本的 150 Dai 還少。以上的計算還有手續費沒有納入考量,但也只有 30 Dai 的 0.3% = 0.09 Dai。
由上例可知,第一位提供流動性的人為了避免自己的損失,確實得依照當時兩幣的市價比去提供相應的數量。傑克,這真是太神奇了0…0
2. 除了第一筆以外的情況
如果市場已經有流動性,使用 addLiquidity() 來注入流動性就會進入第 51 行的 if。
source: https://github.com/Uniswap/uniswap-v1/blob/master/contracts/uniswap_exchange.vy
(53行) eth_reserve: 由於使用者已經透過函式 addLiquidity() 將錢匯入了合約,因此將合約所擁有的 Ether 數量 self.balance (= x + ∆x) 減去使用者匯入的錢 msg.value (= ∆x),得到使用者匯錢之前合約內所擁有的 Ether 數量 (= x)
(54行) token_reserve: self.token 是一個餵入幣地址的 ERC20 instance;透過呼叫 ERC20 的函式 balanceOf() 即可查出合約所擁有的 Y 幣的數量 (= y)
(55行) token_amount: 透過將合約所擁有的 Y 幣的數量 token_reserve (= y) 乘上使用者匯入的錢 msg.value (= ∆x) 對合約原本擁有的Ether 數量 eth_reserve (= x) 的比例,代表使用者應該相應地注入多少 Y 幣 (∆y = y * ∆x / x)。除法一樣是無條件捨去
(56行) liquidity_minted: 將原本交易所中的總流動性 total_liquidity 乘上增加的比率 msg.value / eth_reserve (= ∆x / x) ,代表增加的流動性,隨後會在第 58 行記錄下來
(60行) transferFrom() 函式將使用者應付的 Y 幣數量 token_amount (= ∆y) 匯入當前合約,就完成了流動性的注入。小提示:智能合約中的 assert() 會確保函式內的條件如果失敗就整筆交易 transaction 直接取消,因此只要傳入的參數已經被計算好,於 60 行再進行 transferFrom() 其實與放在前面並沒有太大的差別
以上就是注入流動性的大致實作內容。取出資金 removeLiquidity() 其實與 addLiquidity() 的做法大同小異,因此就不再贅述。
四. 結語
呼,真的累。恆定乘積做市商模型的概念雖然簡單,但解釋起來還是挺複雜的!其實本文並未著墨於審計報告中的主要議題:評估因為整數除法 (不使用浮點數) 而造成的誤差範圍,因為講起來非常複雜、也不是真的這麼需要知道。不過,恰巧就是這些程式碼的細節有可能讓程式產生預期之外的結果!因此,對於有興趣了解該如何去分析智能合約整數除法的讀者,可以研究一下;而 Uniswap 的程式碼因為是用 Vyper 實作,可讀性非常高、同時也不難,因此也非常值得打開來看看、甚至動手實作自己的版本!
最後,如果本文有任何錯誤,請不吝提出,我會盡快做修正;而如果我的文章有幫助到你,可以看看我的其他文章,歡迎一起交流 :)
田少谷 Shao - Medium
Uniswap 解析:恆定乘積做市商模型 Constant Product Market Maker Model 的 Vyper 實作 was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌