Solidity
如何將結構作為委託呼叫中的參數傳遞給代理庫?
我正在嘗試使用 delegatecall 呼叫庫
buyAssetsForEth
中的函式,OpenSeaMarketV2
如下所示:pragma solidity 0.8.4; contract Owned { address public owner; constructor(address _owner) public { owner = _owner; } modifier onlyOwner { require(msg.sender == owner); _; } } contract Router is Owned { struct OpenSeaBuy { address a; } address public openSeaMarketV2 = 0xd9145CCE52D386f254917e481eB44e9943F39138; constructor() Owned(msg.sender) public { } function buyAsset(OpenSeaBuy memory openSeaBuys, bool revertIfTrxFails) public payable { (bool success, bytes memory result)=openSeaMarketV2.delegatecall(abi.encodeWithSignature("buyAssetsForEth((address),bool)",openSeaBuys,revertIfTrxFails)); require(success, 'Delegate Call failed'); } receive() payable external {} function contractAddress() external view returns (address) { return address(this); } }
該
OpenSeaMarketV2
庫單獨部署到0xd9145CCE52D386f254917e481eB44e9943F39138
library OpenSeaMarketV2 { struct OpenSeaBuy { address a; } function buyAssetsForEth(OpenSeaBuy memory openSeaBuys, bool revertIfTrxFails) public { uint256 x = 3; } }
但執行
buyAsset
失敗並顯示消息:“委託呼叫失敗”關於它為什麼失敗的任何想法?
您剛剛遇到了庫 ABI 編碼的注意事項之一。你可以在這裡閱讀。本質上,與庫函式選擇器相關的這一行是解釋:
非儲存結構由它們的完全限定名稱引用,即契約 C { struct S { … } } 的 CS。
這意味著 OpenSeaMarketV2.buyAssetsForEth 的函式選擇器不是從以下計算得出的:
keccak256(buyAssetsForEth((address),bool))
: 0x443e309e而是來自:
keccak256(buyAssetsForEth(OpenSeaMarketV2.OpenSeaBuy,bool))
: 0x2baccc78這是一個庫特定的編碼方案。要解決您的問題,主要有兩種方法。更改您的簽名字元串以顯式使用編譯庫時使用的簽名字元串:
function buyAsset(OpenSeaBuy memory openSeaBuys, bool revertIfTrxFails) public payable { (bool success, bytes memory result)=openSeaMarketV2.delegatecall(abi.encodeWithSignature("buyAssetsForEth(OpenSeaMarketV2.OpenSeaBuy,bool)",openSeaBuys,revertIfTrxFails)); require(success, 'Delegate Call failed'); }
或者直接參考庫函式選擇器以獲得更簡潔的語法,但絕對不容易出錯:
function buyAsset(OpenSeaBuy memory openSeaBuys, bool revertIfTrxFails) public payable { (bool success, bytes memory result)= openSeaMarketV2.delegatecall(abi.encodeWithSelector(OpenSeaMarketV2.buyAssetsForEth.selector,openSeaBuys,revertIfTrxFails)); require(success, 'Delegate Call failed'); }
我希望這能回答你的問題。