合約呼叫的輸出是如何編碼的?
嗨,我有一個代理合約 A,它使用標準 OpenZeppelin 程式碼將函式執行委託給實現合約 B:
assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } }
當我嘗試呼叫函式 getter 以獲得應該是
[10, 100]
我得到字元串的結果時0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000064
。這是什麼編碼以及我可以使用哪個庫來解碼它。起初我以為是 RLP 編碼,但我檢查了一些 RLP 解碼器,但沒有檢查出來。謝謝
這是 Solidity 使用的 ABI 編碼格式,記錄在Contract ABI Specification中。基本上,靜態值(例如,數字、布爾值、bytes1..32)被編碼為 32 個字節(64 個十六進製字元),而動態值在最後被編碼,其中指向位置的指針被編碼到位。
以您的結果為例,首先將其分成 32 個字節的組。
0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000002 000000000000000000000000000000000000000000000000000000000000000a 0000000000000000000000000000000000000000000000000000000000000064
由於輸出是一個數組,前 32 個字節
0x000...020
(0x20
這第二組 32 字節指定了數組的長度,在這種情況下0x2
或簡稱為 2,這意味著接下來的兩組 32 字節是數組的一部分。正如預期的那樣,最後兩組
0x0a
和0x64
分別為 10 和 100,因此解碼輸出結果[10, 100]
符合預期。當然,手動執行此操作效率不高,並且有一些庫可以自動為您解析輸出。假設您使用的是 JavaScript/TypeScript:
@ethersproject/abi
- https://github.com/ethers-io/ethers.js(Ethers.js的一部分)web3-eth-abi
- https://github.com/ChainSafe/web3.js/tree/1.x/packages/web3-eth-abi(Web3.js的一部分,但它@ethersproject/abi
在後台使用)。@findeth/abi
- https://github.com/findeth/abi還有一些線上工具可用於編碼和解碼: