Delegatecall

使用委託呼叫減少代幣轉移

  • December 27, 2021

我正在嘗試解決“玩具”應用程序中的循環依賴以測試可升級契約。

我有一份包含 ERC20 代幣的財政部合約和一組可升級的**Action合約。Action 合約與其他 DeFi 建構塊互動,例如在 Yearn 上進行質押、在 Uniswap 上進行交換、在 Olympus 上購買債券等,但合約本身並不擁有任何代幣。現在,為了節省燃料,我想避免將代幣從財政部轉移到 Action 合約,然後再轉移到外部 DeFi 協議,所以我想出了一個可能的解決方案。

在財政部有一個特殊功能,僅限於行動契約,它通過財政部的代表呼叫回調行動,從而完全控制資金。

一個方案 User -> Action -> Treasury -> (delegatecall) Action -> external DeFi contract

國庫內

function relayCall(address to, bytes calldata data) external onlyActions {
   require(isActionContract[to], "Err: can only call an action");
   (success,) = to.delegatecall(data);
   require(success);
}

行動內部

function makeCall(...) external {
   bytes memory data = abi.encodeWithSelector(Action.swap.selector, ...);
   ITreasury(treasury).relayCall(address(this), data);
}

function swap(address token0, address token1, address recipient, uint256 amount) external {
   uniRouter.swapExactTokensForTokens(...);
}

這種方法的優點是它與可升級的 Action 合約兼容,它非常安全,因為接收者被列入白名單並且委託呼叫範圍在 Action 程式碼中是固定的,最大的缺點是循環依賴Action -> Treasury -> Action

您描述的委託呼叫模式非常常見,並且被 Gnosis Safe、Gelato、DSProxy 和 InstaDapp 等合約使用。

Gnosis Safe 實際上與可以觸發的模組有一個非常相似的模式delegatecalls

通過將合約拆分為“觸發器”和“動作”,可以輕鬆解決循環依賴問題。但就我個人而言,我也不認為循環依賴會導致任何問題。

分離的意義在於避免潛在的不想要的狀態變化。例如,在“Action”中沒有任何狀態以避免調整“Treasury”狀態是有意義的。

參考:

您是否必須從 Action 啟動操作?為什麼不直接刪除makeCall,並做切入點Treasury’s relayCall

引用自:https://ethereum.stackexchange.com/questions/117364