我們可以在solidity 庫中使用儲存關鍵字嗎?
我正在閱讀有關圖書館的文章,並看到文章說圖書館不能有儲存空間。
但我見過使用儲存關鍵字的庫。
範例:在 Aave 協議 v3 中
function calculateUserAccountData( address user, mapping(address => DataTypes.ReserveData) storage reservesData, DataTypes.UserConfigurationMap memory userConfig, mapping(uint256 => address) storage reserves, uint256 reservesCount, address oracle ) internal view returns ( uint256, uint256, uint256, uint256, uint256 ) { ........... DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
這是否意味著在內部函式儲存中可以用作從庫中導入的函式?
我錯過了什麼嗎?
並不是庫中禁止使用 storage 關鍵字,而是它們不能擁有自己的狀態變數,因為它們是無狀態的。
狀態變數在合約範圍級別聲明,因此它是合約全域狀態的一部分。
在函式作用域級別聲明了一個局部儲存變數,只要函式正在執行,它就是“函式狀態”的一部分,那麼這個變數就會被丟棄。重要的一點是,本地儲存變數本身很可能是一個引用,因此,丟棄它並不意味著它所引用的內容也被丟棄。
所以這是禁止的:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library TestLibrary { uint256 stateVariable; }
因為
stateVariable
很好……一個狀態變數,因為它是在契約/庫級別聲明的。TypeError: Library cannot have non-constant state variables
編譯按預期失敗。另一方面,您提供的程式碼不同,
storage
只有當該參數是呼叫合約的狀態變數時,接收參數才真正有意義。這是對呼叫者狀態變數的引用,允許庫函式讀取/寫入呼叫合約的儲存。如果庫被部署,這些庫呼叫實際上是編譯
delegatecall
的,如果庫被嵌入,它將簡單地包含在合約的程式碼中。如果我沒記錯的話,您的範例是一個嵌入式庫,但這並不重要。第二種用法:
DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
只需創建一個直接引用
reservesData[vars.currentReserveAddress]
.從文件中:
從儲存到本地儲存變數的分配也只分配一個引用。
現在我可能錯過了一些東西,但在我看來,這只是一種避免寫入
reservesData[vars.currentReserveAddress]
訪問該變數的方法。現在可以使用currentReserve
.關鍵是這也不是庫的狀態變數,它只是對屬於呼叫者儲存/狀態的儲存變數的引用。
也許一個更精確的讀/寫範例(例如這個)是一種更好的方式來完全回答您關於使用(連結)庫的儲存參數/變數的問題:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; struct Wrapper { uint256 value; } library TestLibrary { function testLocalStorageParameter(Wrapper storage wrapper) public { // wrapper is a reference to a storage variable from the calling contract // Modifying wrapper here modifies the state variable of the calling contract. wrapper.value = 10; } function testLocalStorageVariable(Wrapper storage wrapper) public { // wrapper is a reference to a storage variable from the calling contract // secondWrapper is also a reference to a storage variable from the the calling contract // "Assignments from storage to a local storage variable also only assign a reference." Wrapper storage secondWrapper = wrapper; // Modifying secondWrapper here also modifies the state variable of the calling contract. secondWrapper.value = 20; } } contract TestContract{ Wrapper wrapper; // wrapper.value = 0 by default function getValue() public view returns(uint256) { return wrapper.value; } function calltestLocalStorageParameter() public { // After this library call wrapper.value = 10 TestLibrary.testLocalStorageParameter(wrapper); } function calltestLocalStorageVariable() public { // After this library call wrapper.value = 20 TestLibrary.testLocalStorageVariable(wrapper); } }
合約將其自己的狀態變數的儲存引用提供給庫,以便庫可以對其進行操作。該庫從來沒有自己的狀態變數,但是如果將其作為參數引用,則允許它對呼叫它的合約的狀態變數進行操作。
我希望這能回答你的問題。