infinite-proxy/contracts/infiniteProxy/proxy.sol

343 lines
10 KiB
Solidity
Raw Normal View History

2022-04-14 12:41:37 +00:00
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./events.sol";
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`.
*/
contract Internals is Events {
struct AddressSlot {
address value;
}
struct SigsSlot {
bytes4[] value;
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT =
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Storage slot with the address of the current dummy-implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _DUMMY_IMPLEMENTATION_SLOT =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
2022-04-15 10:59:13 +00:00
2022-04-14 13:02:25 +00:00
/**
* @dev Returns the storage slot which stores the sigs array set for the implementation.
*/
2022-04-14 12:41:37 +00:00
function _getSlotImplSigsSlot(address implementation_)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encode("eip1967.proxy.implementation", implementation_)
);
}
2022-04-14 13:02:25 +00:00
/**
* @dev Returns the storage slot which stores the implementation address for the function sig.
*/
2022-04-14 12:41:37 +00:00
function _getSlotSigsImplSlot(bytes4 sig_) internal pure returns (bytes32) {
return keccak256(abi.encode("eip1967.proxy.implementation", sig_));
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot_)
internal
pure
returns (AddressSlot storage _r)
{
assembly {
_r.slot := slot_
}
}
/**
* @dev Returns an `SigsSlot` with member `value` located at `slot`.
*/
function getSigsSlot(bytes32 slot_)
internal
pure
returns (SigsSlot storage _r)
{
assembly {
_r.slot := slot_
}
}
/**
* @dev Sets new implementation and adds mapping from implementation to sigs and sig to implementation.
*/
function _setImplementationSigs(
address implementation_,
bytes4[] memory sigs_
) internal {
require(sigs_.length != 0, "no-sigs");
bytes32 slot_ = _getSlotImplSigsSlot(implementation_);
bytes4[] memory sigsCheck_ = getSigsSlot(slot_).value;
require(sigsCheck_.length == 0, "implementation-already-exist");
for (uint256 i = 0; i < sigs_.length; i++) {
bytes32 sigSlot_ = _getSlotSigsImplSlot(sigs_[i]);
require(
getAddressSlot(sigSlot_).value == address(0),
"sig-already-exist"
);
getAddressSlot(sigSlot_).value = implementation_;
}
getSigsSlot(slot_).value = sigs_;
emit setImplementationLog(implementation_, sigs_);
}
/**
2022-04-14 13:02:25 +00:00
* @dev Removes implementation and the mappings corresponding to it.
2022-04-14 12:41:37 +00:00
*/
function _removeImplementationSigs(address implementation_) internal {
bytes32 slot_ = _getSlotImplSigsSlot(implementation_);
bytes4[] memory sigs_ = getSigsSlot(slot_).value;
require(sigs_.length != 0, "implementation-not-exist");
for (uint256 i = 0; i < sigs_.length; i++) {
bytes32 sigSlot_ = _getSlotSigsImplSlot(sigs_[i]);
delete getAddressSlot(sigSlot_).value;
}
delete getSigsSlot(slot_).value;
emit removeImplementationLog(implementation_);
}
2022-04-14 13:02:25 +00:00
/**
* @dev Returns bytes4[] sigs from implementation address. If implemenatation is not registered then returns empty array.
*/
2022-04-14 12:41:37 +00:00
function _getImplementationSigs(address implementation_)
internal
view
returns (bytes4[] memory)
{
bytes32 slot_ = _getSlotImplSigsSlot(implementation_);
return getSigsSlot(slot_).value;
}
2022-04-14 13:02:25 +00:00
/**
* @dev Returns implementation address from bytes4 sig. If sig is not registered then returns address(0).
*/
2022-04-14 12:41:37 +00:00
function _getSigImplementation(bytes4 sig_)
internal
view
returns (address implementation_)
{
bytes32 slot_ = _getSlotSigsImplSlot(sig_);
return getAddressSlot(slot_).value;
}
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Returns the current dummy-implementation.
*/
function _getDummyImplementation() internal view returns (address) {
return getAddressSlot(_DUMMY_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin_) internal {
address oldAdmin_ = _getAdmin();
require(
newAdmin_ != address(0),
"ERC1967: new admin is the zero address"
);
getAddressSlot(_ADMIN_SLOT).value = newAdmin_;
emit setAdminLog(oldAdmin_, newAdmin_);
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setDummyImplementation(address newDummyImplementation_) internal {
address oldDummyImplementation_ = _getDummyImplementation();
getAddressSlot(_DUMMY_IMPLEMENTATION_SLOT)
.value = newDummyImplementation_;
emit setDummyImplementationLog(
oldDummyImplementation_,
newDummyImplementation_
);
}
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _delegate(address implementation_) internal {
// solhint-disable-next-line no-inline-assembly
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
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())
}
}
}
/**
* @dev Delegates the current call to the address returned by Implementations registry.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback(bytes4 sig_) internal {
address implementation_ = _getSigImplementation(sig_);
require(
implementation_ != address(0),
"Liquidity: Not able to find implementation_"
);
_delegate(implementation_);
}
}
contract AdminStuff is Internals {
2022-04-14 13:02:25 +00:00
/**
* @dev Only admin gaurd.
*/
2022-04-14 12:41:37 +00:00
modifier onlyAdmin() {
require(msg.sender == _getAdmin(), "not-the-admin");
_;
}
/**
2022-04-14 13:02:25 +00:00
* @dev Sets new admin.
2022-04-14 12:41:37 +00:00
*/
function setAdmin(address newAdmin_) external onlyAdmin {
_setAdmin(newAdmin_);
}
/**
2022-04-14 13:02:25 +00:00
* @dev Sets new dummy-implementation.
2022-04-14 12:41:37 +00:00
*/
function setDummyImplementation(address newDummyImplementation_)
external
onlyAdmin
{
_setDummyImplementation(newDummyImplementation_);
}
/**
2022-04-14 13:02:25 +00:00
* @dev Adds new implementation address.
2022-04-14 12:41:37 +00:00
*/
function addImplementation(address implementation_, bytes4[] calldata sigs_)
external
onlyAdmin
{
_setImplementationSigs(implementation_, sigs_);
}
/**
2022-04-14 13:02:25 +00:00
* @dev Removes an existing implementation address.
2022-04-14 12:41:37 +00:00
*/
function removeImplementation(address implementation_) external onlyAdmin {
_removeImplementationSigs(implementation_);
}
constructor(address admin_, address dummyImplementation_) {
_setAdmin(admin_);
_setDummyImplementation(dummyImplementation_);
}
}
abstract contract Proxy is AdminStuff {
constructor(address admin_, address dummyImplementation_)
AdminStuff(admin_, dummyImplementation_)
{}
/**
2022-04-14 13:02:25 +00:00
* @dev Returns admin's address.
2022-04-14 12:41:37 +00:00
*/
function getAdmin() external view returns (address) {
return _getAdmin();
}
/**
2022-04-14 13:02:25 +00:00
* @dev Returns dummy-implementations's address.
2022-04-14 12:41:37 +00:00
*/
function getDummyImplementation() external view returns (address) {
return _getDummyImplementation();
}
/**
2022-04-14 13:02:25 +00:00
* @dev Returns bytes4[] sigs from implementation address If not registered then returns empty array.
2022-04-14 12:41:37 +00:00
*/
function getImplementationSigs(address impl_)
external
view
returns (bytes4[] memory)
{
return _getImplementationSigs(impl_);
}
/**
2022-04-14 13:02:25 +00:00
* @dev Returns implementation address from bytes4 sig. If sig is not registered then returns address(0).
2022-04-14 12:41:37 +00:00
*/
function getSigsImplementation(bytes4 sig_)
external
view
returns (address)
{
return _getSigImplementation(sig_);
}
/**
* @dev Fallback function that delegates calls to the address returned by Implementations registry.
*/
fallback() external payable {
_fallback(msg.sig);
}
/**
* @dev Fallback function that delegates calls to the address returned by Implementations registry.
*/
receive() external payable {
if (msg.sig != 0x00000000) {
_fallback(msg.sig);
}
}
2022-04-15 10:59:13 +00:00
}