白皮書原版:https://uniswap.org/whitepaper.pdf
Uniswap v2 Core
Hayden Adams hayden@uniswap.org
Noah Zinsmeister noah@uniswap.org
Dan Robinsondan@paradigm.xyz
摘要
本技術(shù)白皮書說明了Uniswap v2核心合約的一些設計方案锤躁。涵蓋了合約的新特性---包括任意ERC20交易對盾鳞,一個硬化的價格oracle機制,允許其他合約在給定的時間間隔內(nèi)估算時間加權(quán)的平均價格壤巷,“flash swaps”允許交易者在付款之前收取資產(chǎn)并且把它們用在別的地方,還有可以在將來被打開的協(xié)議手續(xù)費開關俘闯。V2重構(gòu)了合約邀杏,減少了供給面。本白皮書描述了Uniswap v2核心合約的機制笤闯,包含存儲了LP資金的pair合約和用于實例化pair合約的factory合約。
1.介紹
Uniswap v1是一個基于以太坊的智能合約鏈上系統(tǒng)棍厂,實現(xiàn)了一個基于“常量乘積公式”的自動流動性協(xié)議颗味。每一對Uniswap v1都存儲了兩種資產(chǎn)的資金池,并且提供了這兩種資產(chǎn)的流動性牺弹,維持了這兩種資產(chǎn)池內(nèi)資金乘積保持不變浦马。交易者需要支付每筆交易0.3%的手續(xù)費,這些費用將會給流動性提供者(LP)张漂。這個合約是不可升級的晶默。
Uniswap v2是基于同一個公式的新實現(xiàn),具有幾個非常理想的新特性航攒。最重要的是荤胁,它允許創(chuàng)建任意的ERC20/ERC20交易對,而不是只支持ERC20和ETH之間的交易對屎债。它還提供了一個硬化了的價格oracle機制仅政,在每個區(qū)塊最開始累計兩種資產(chǎn)的相對價格。這鄖西以太坊上的其他合約在給定的時間間隔內(nèi)估算時間加權(quán)的平均價格盆驹。最后圆丹,它支持“flash swaps”,使交易者免費獲取資產(chǎn)并把它們用在鏈上的其他地方躯喇,只需要在交易的最后支付或返還資產(chǎn)辫封。
雖然合約使不可以被升級的硝枉,但是有一個私鑰可以更新factory合約內(nèi)的變量,打開1/6手續(xù)費的開關倦微。這個開關最開始是關閉的妻味,也許會在以后打開,屆時LP將只能收取0.25%的手續(xù)費欣福,而不是0.3%责球。
在第三章會討論到,Uniswap v2修復了Uniswap v1的很多小錯誤拓劝,同時重構(gòu)了整個實現(xiàn)雏逾,減少了Uniswap的供給面,并且通過最小化核心合約中存儲LP基金的邏輯郑临,使整個系統(tǒng)更容易升級栖博。
本白皮書描述了核心合約的機制,以及用于實例化合約的factory合約厢洞。實際上仇让,使用Uniswap v2需要通過一個路由合約調(diào)用pair合約,計算交易或存款金額躺翻,并將資金轉(zhuǎn)移到pair合約妹孙。
2.新特性
2.1 ERC-20對
Uniswap v1使用ETH作為資產(chǎn)之間的橋接。每一對pair都需要ETH作為其中一種資產(chǎn)获枝。這讓路由變得簡單,每一次ABC和XYZ之間的交易都要通過ETH/ABC和ETH/XYZ骇笔,減少了流動性的分散省店。
然而,這個規(guī)則給LP增加了大量的花費笨触。所有LP都必須接觸ETH懦傍,并且需要承受ETH價格相對其他資產(chǎn)變動時帶來的的無常形損失。當兩種資產(chǎn)ABC和XYZ相關時----比如芦劣,如果他們都是USD穩(wěn)定幣---那么ABC/XYZ的LP承受的損失會少于ABC/ETH或XYZ/ETH對粗俱。
使用ETH作為強制的橋接資產(chǎn)同時還會增加交易者的花費。相比ABC/XYZ交易對虚吟,使用ETH最為橋接寸认,交易者必須支付兩倍的手續(xù)費,同時承受兩次下滑串慰。
Uniswap v2允許LP創(chuàng)建任意ERC20pair合約偏塞。
對任意ERC20pair的擴散會讓找到最佳路徑交易特定pair變得更難,但是更高層的路由可以解決這一點(無論是鏈上還是鏈下)
2.2 價格Oracle
Uniswap在時間t內(nèi)提供的臨界價格(不包含手續(xù)費)可以用資產(chǎn)a的池內(nèi)資金除以資產(chǎn)b的池內(nèi)資金來計算邦鲫。
由于價格不正確時灸叼,套利者會在Uniswap上交易以此套利神汹。所以Uniswap提供的價會傾向相關市場里資產(chǎn)的價格,如Angeris et al [2]所示古今。這意味著它可以用作一個近似的價格oracle屁魏。
然而,Uniswap v1作為一個鏈上價格oracle并不安全捉腥,因為它很容易被操控氓拼。假設其他合約使用當前的ETH-DAI價格結(jié)算一個衍生品。一個希望操控價格的攻擊者可以從ETH-DAIpair購買ETH但狭,出發(fā)衍生品合約的結(jié)算(導致它用膨脹后的價格結(jié)算)披诗,然后再將ETH賣回ETH-DAI pair,讓ETH回到它真正的價格上立磁。這些操作甚至可以發(fā)生在原子操作中呈队,或者由一個控制了交易順序的礦工打包在一個區(qū)塊里。
Uniswap v2通過在每個區(qū)塊的第一筆交易(換句話說唱歧,就是在上一個區(qū)塊最后一筆交易以后)中計算和記錄價格宪摧,改進了這個oracle的功能。在同一個塊中颅崩,價格會變得難以操控几于。如果一個攻擊者提交了一筆交易,在區(qū)塊的最后嘗試去修改價格沿后,其他套利者可以在同一區(qū)塊提交另一筆交易將價格迅速修改回來沿彭。一個礦工(或者一個可以用足夠gas填充一整個區(qū)塊的攻擊者)還是可以操控一個block內(nèi)的價格,但是除非他們能繼續(xù)挖出下一個區(qū)塊尖滚,否則套利的結(jié)果并沒有優(yōu)勢喉刘。
特別地,Uniswap v2通過在每個區(qū)塊第一筆與該合約交互的交易中漆弄,追蹤該區(qū)塊開始時的累計價格來積累這個價格睦裳。每個價格都被上一次更新的區(qū)塊的時間間隔加權(quán)。這意味著任意時間點的累計價格(更新后)都是之前每一秒價格的總和撼唾。
為了估算從時間t1到時間t2的時間加權(quán)平均價格廉邑,一個外部調(diào)用者可以在t1和t2分別檢查累計價格,用t2的累計價格減去t1的累計價格倒谷,然后除以t2減去t1(注意合約本身并不會記錄歷史的累計值蛛蒙,調(diào)用者需要在周期開始時自己讀取和存儲這個值)
該oracle的用戶可以自己選擇何時開始和結(jié)束這個階段。選擇較長的時間間隔會讓攻擊者花費更大的代價操控價格渤愁,但是會使價格更新更不及時宇驾。
一個復雜的問題是:我們應該計算A相對B的價格兰迫,還是B相對A的價格稽莉?雖然在特定的時間點灰殴,A相對B的價格永遠是B相對A的價格的倒數(shù)谐宙,但是在一個期間的加權(quán)平均值卻不是這樣。比如筝尾,加入USD/ETH的價格在Block1時為100捡需,Block2時為200,那么USD/ETH的平均價格則是200筹淫,但是ETH/USD的平均價格確實1/150站辉。由于合約并不知道用戶會使用哪一個資產(chǎn)作為計算單位,Uniswap v2會同時追蹤這兩個價格损姜。
另一個復雜的問題是饰剥,有人可以將資產(chǎn)發(fā)送到pair合約,改變其余額和編輯價格摧阅,不需要與合約交互汰蓉,因此也不會觸發(fā)oracle價格的更新。如果合約只是簡單的檢查自己的余額并且基于當前價格更新oracle棒卷,那么一個攻擊者可以通過在一個區(qū)塊中第一次調(diào)用該合約之前迅速發(fā)送資產(chǎn)到合約地址來操控價格顾孽。如果上一筆交易是在X秒之前的去快速,那么該合約會錯誤的將新價格乘以X并累計它比规,雖然沒有人有機會用該價格交易若厚。為了防止這樣的事,核心合約會在每一次交互后緩存資金池的金額蜒什,用緩存中的數(shù)字更新oracle测秸,而不是使用當前的數(shù)字。除了保護oracle免受操縱之外灾常,此更改還支持下面章節(jié)3.2中描述的契約重新架構(gòu)霎冯。
2.2.1 精度
由于solidity對非整數(shù)數(shù)字數(shù)據(jù)類型沒有很好的支持,因此Uniswap v2使用簡單的二進制定點格式來編碼和操縱價格岗憋。具體地說,給定時刻的價格存儲為UQ112.112數(shù)字锚贱,這意味著在小數(shù)點的兩邊指定了112個小數(shù)位的精度仔戈,沒有符號。這些數(shù)字的范圍為[0,2的112次方?1]拧廊,精度為1/2的112次方监徘。
選擇UQ112.112格式是出于一個實用的原因-因為這些數(shù)字可以存儲在uint224中,這在uint256中留下了32位的存儲槽空閑吧碾。Reserve變量每個存儲在一個uint112凰盔,也留下32位在一個(打包)256位存儲槽空閑。特別的倦春,最近一次更新的區(qū)塊時間戳和reserve一次存儲户敬,會用2的32次方取膜讓它可以被房價32位的存儲中落剪。另外,盡管在任何給定時刻的價格(存儲為UQ112.112號)被保證適合224位尿庐,但這個價格在一個間隔內(nèi)的積累卻不是忠怖。存儲槽的末端額外的32位用于存儲A/B和B/A的累計價格,用于存儲重復累加價格導致的溢出位抄瑟。這種設計意味著oracle在每個區(qū)塊的第一次交易中只增加了額外的三個SSTORE操作(目前的成本約為1.5萬gas)凡泣。
主要的缺點是32位不足以存儲不會溢出的時間戳值。事實上皮假,Unix時間戳溢出一個uint32的日期是02/07/2106鞋拟。為了確保這個系統(tǒng)在這個日期之后繼續(xù)正常運行,并且在2的32次方 - 1秒之后惹资,oracle只需要在每個時間間隔(大約136年)至少檢查一次價格贺纲。這是因為累積的核心方法(以及時間戳的修改)實際上是溢出安全的,這意味著布轿,如果oracle使用適當?shù)?簡單的)溢出算法來計算增量哮笆,那么跨溢出區(qū)間的交易可以適當?shù)乜紤]。
2.3 Flash Swaps
在Uniswap v1中汰扭,用戶使用XYZ購買ABC需要將XYZ先發(fā)送給合約之后才可以收到ABC稠肘。如果用戶需要購買的ABC來獲得他們支付的XYZ,這是不方便的萝毛。比如项阴,用戶也許想在其他合約中用ABC去買XYZ來套利,或者他們可能通過出售抵押品來償還Uniswap來在Maker或Compound平倉笆包。
Uniswap v2增加了一個新特性环揽,使用戶可以在支付資產(chǎn)之前獲取并使用使用它,只要他們可以將支付操作包含在一個原子性交易中庵佣。swap函數(shù)在轉(zhuǎn)移用戶請求的token和執(zhí)行不變式之間調(diào)用一個可選的用戶指定的回調(diào)合約歉胶。一旦回調(diào)完成,合約會檢查新的余額并確定條件可以滿足(扣除手續(xù)費后)巴粪。如果該合約沒有足夠的資金通今,則整個交易都會被返回。
2.4 協(xié)議手續(xù)費
肛根。辫塌。∨烧埽看不懂公式了臼氨,反正有個開關打開以后就會把手續(xù)費的1/6給feeTo地址,現(xiàn)在還沒有打開芭届。然后因為每次有人交易都進行手續(xù)費階段的花會花很多gas储矩,所以只在池子金額變化時進行結(jié)算感耙。白皮書里給了計算累計手續(xù)費的公式但是我沒看明白,感興趣的自己去看吧椰苟。
可以再參考這個:https://blog.csdn.net/sanqima/article/details/109667469
2.5池股的元交易
由Uniswap v2對創(chuàng)建的池共享本身支持元事務抑月。這意味著用戶可以通過簽名授權(quán)池共享的轉(zhuǎn)讓,而不是通過他們的地址進行鏈上交易舆蝴。任何人都可以通過調(diào)用permit函數(shù)谦絮、支付gas費以及在同一事務中執(zhí)行其他操作來代表用戶提交這個簽名。