This is abstract contract in the context of Proxy pattern:
abstract contract Initializable {
bool private _initialized;
bool private _initializing;
modifier initializer() {
require(_initializing || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
}
contract UpgradebleTest1 is Initializable {
uint public x;
function initialize(uint _x) public initializer {
x = _x;
}
}
I don't understand the necessity of _initializing and isTopLevelCall. Is not enough doing control using only _initialized?
Thanks,
The _initializing
and isTopLevelCall
combination allow for chained calls with the initializer
modifier:
contract UpgradebleTest1 is Initializable {
uint public x;
function initialize(uint _x) public initializer {
internalInit(_x);
}
function internalInit(uint _x) internal initializer {
x = _x;
}
}
Without the _initializing
and isTopLevelCall
check, the initializer
modifier would pass on the first call (initialize()
) but fail on the second call (internalInit()
).
modifier initializer() {
require(!_initialized, "Initializable: contract is already initialized");
_initialized = true;
}