微討論 ethereum transactions

前情提要

transaction

  • from (address)
  • to (address)
  • value (amount of ETH)
  • data (optional)

➞ call 合約 function 的細節寫在這

前情提要

transaction lifecycle 簡化版

  1. broadcast to network
  2. included in a block by a miner/validator
  3. the chain includes the block becomes the longest chain

requested  ➟  included  ➟  recognized

ERC-20 的設計 有些問題

ERC20

function name() public view returns (string)

function symbol() public view returns (string)

function decimals() public view returns (uint8)

function totalSupply() public view returns (uint256)

function balanceOf(address _owner) public view returns (uint256 balance)

function transfer(address _to, uint256 _value) public returns (bool success)

function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)

function approve(address _spender, uint256 _value) public returns (bool success)

function allowance(address _owner, address _spender) public view returns (uint256 remaining)

例如

A 要給 B 10 個 token

A 執行 transfer(B, 10)

A 執行 approve(B, 10)

B 再執行 transferFrom(A, someAddress, 10)

問題會發生在想要改變 allowance 的時候

A 之前有 approve B 一些 token,假設 10 個

後來 A 發現需要 approve B 更多 token,假設需要 20 個

A 需要再 call approve(B, 20)

題外話

很多合約會直接讓你一開始就 approve 最大值

好處是之後不用再 approve 付 gas fee

壞處是如果那個合約被駭或是有 bug 你的 token 會全部被轉走

.

事情順利的話

allowance 10

allowance 20

allowance 0

A 給 B 20 個 token

A call approve(B, 20)

B call transferFrom(A, B, 20)

事情不順利的話

allowance 10

allowance 20

allowance 0

A 給 B 30 個 token

allowance 0

B call transferFrom(A, B, 10)

A call approve(B, 20)

B call transferFrom(A, B, 20)

B 怎麼知道有這個好機會

複習一下 transaction 的 lifecycle

requested  ➟  included  ➟  recognized

解決方案 1

增加 allowance 前要先改為 0

(弱弱的)

解決方案 2

加開 increaseAllowance 跟 decreaseAllowance 兩個 func

處理要增加或減少 allowance 的情形

approve 只用在 initial approve,或是都不要用

OpenZeppelin 的 ERC-20 實作

從另一個角度看

因為 approve 跟 transferFrom 是兩個 transaction

不是在同一個 transaction 內

所以有了趁虛而入的機會

一個 transaction

可以包含好幾個動作

某個人執行 某個 contract 的 某個 function

某個 function 改變了一些值之後 又執行另外一個 function

另外一個 function 也改變了一些值

然後又執行另外一個 contract 的某個 function

...

最後完成

一個 transaction

transaction 內的動作

會都有生效或是都沒生效

而且不必擔心做到一半被別人干擾

block 123

transaction 2345 success

transaction 2346 failed

transaction 2347 success

如果想要一次執行多個 function

又想要在同一個 transaction 內的話

可以透過合約來完成

contract A {
  function b() {
    c();
    d();
    e();
    ...
  }
}
  
  

舉個例

exactInput

exactOutput

 給定值的 ETH 看能換多少是多少

要換到定值的 token

假設要用 uniswap 的合約把 ETH 換成某 token

exactOutput

1 個 ETH 能換多少 token 不一定

要給多一些 ETH 才不會失敗

v2 會自動退 ETH

v3 不會 要再 call refundETH

他會把他所有剩的 ETH 給你

exactOutput

如果我先 exactOutput

再執行 refundETH

分 2 個 transaction 的話

中間可能會被別人先 call refundETH

該還我的 可能會被別人拿走

必須要透過合約寫在同一個 function 裡面

才會在同一個 transaction 執行這兩個動作

別人才沒有介入的機會

怎麼做

我們執行合約 A 的 function,把 ETH 附給他

合約 A 用他的名義去換 token 回來

然後再把 token 轉給我們

退我們 ETH 

題外話 解決方案 3

要獲得授權 不一定要 send transaction

只要有簽章就可以確認

好像不行?

因為 approve 還是要我們來 approve?

前面的 approve/transferFrom

授權 跟 讓別人轉走 兩個動作

可以透過合約 在同一個 transaction 完成嗎

對方有你的簽章,再一起拿去 send transaction 就好

Flash Loan

可以沒有抵押就借超多錢

只要在同一個 transaction 可以還回去

就不會被 revert

提供 flash loan 的 function 會做三件事

1. 轉錢給 receiver

2. 執行 receiver 準備好的 callback

3. 把錢轉回來

Flash Loan 的存在

是 DeFi 的最大特色 (之一)

也是 DeFi 的最大衝擊 (嗎)

Flash Loan Attack

操控價格不用本錢

騙 DeFi 合約當韭菜

Flash Loan Attack

參考資料

ethereum transactions

By luyunghsien

ethereum transactions

  • 698