2020-05-29 16:45:37 +00:00
|
|
|
// SPDX-License-Identifier: agpl-3.0
|
|
|
|
pragma solidity ^0.6.0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @title Proxy
|
|
|
|
* @dev Implements delegation of calls to other contracts, with proper
|
|
|
|
* forwarding of return values and bubbling of failures.
|
|
|
|
* It defines a fallback function that delegates all calls to the address
|
|
|
|
* returned by the abstract _implementation() internal function.
|
|
|
|
*/
|
|
|
|
abstract contract Proxy {
|
2020-07-13 08:54:08 +00:00
|
|
|
/**
|
2020-05-29 16:45:37 +00:00
|
|
|
* @dev Fallback function.
|
|
|
|
* Implemented entirely in `_fallback`.
|
|
|
|
*/
|
2020-07-13 08:54:08 +00:00
|
|
|
fallback() external payable {
|
|
|
|
_fallback();
|
|
|
|
}
|
2020-05-29 16:45:37 +00:00
|
|
|
|
2020-07-13 08:54:08 +00:00
|
|
|
/**
|
2020-05-29 16:45:37 +00:00
|
|
|
* @return The Address of the implementation.
|
|
|
|
*/
|
2020-07-13 08:54:08 +00:00
|
|
|
function _implementation() internal virtual view returns (address);
|
2020-05-29 16:45:37 +00:00
|
|
|
|
2020-07-13 08:54:08 +00:00
|
|
|
/**
|
2020-05-29 16:45:37 +00:00
|
|
|
* @dev Delegates execution to an implementation contract.
|
|
|
|
* This is a low level function that doesn't return to its internal call site.
|
|
|
|
* It will return to the external caller whatever the implementation returns.
|
|
|
|
* @param implementation Address to delegate.
|
|
|
|
*/
|
2020-07-13 08:54:08 +00:00
|
|
|
function _delegate(address implementation) internal {
|
|
|
|
//solium-disable-next-line
|
|
|
|
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())
|
2020-05-29 16:45:37 +00:00
|
|
|
|
2020-07-13 08:54:08 +00:00
|
|
|
// 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)
|
2020-05-29 16:45:37 +00:00
|
|
|
|
2020-07-13 08:54:08 +00:00
|
|
|
// Copy the returned data.
|
|
|
|
returndatacopy(0, 0, returndatasize())
|
2020-05-29 16:45:37 +00:00
|
|
|
|
2020-07-13 08:54:08 +00:00
|
|
|
switch result
|
|
|
|
// delegatecall returns 0 on error.
|
|
|
|
case 0 {
|
|
|
|
revert(0, returndatasize())
|
|
|
|
}
|
|
|
|
default {
|
|
|
|
return(0, returndatasize())
|
2020-05-29 16:45:37 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-13 08:54:08 +00:00
|
|
|
}
|
2020-05-29 16:45:37 +00:00
|
|
|
|
2020-07-13 08:54:08 +00:00
|
|
|
/**
|
2020-05-29 16:45:37 +00:00
|
|
|
* @dev Function that is run as the first thing in the fallback function.
|
|
|
|
* Can be redefined in derived contracts to add functionality.
|
|
|
|
* Redefinitions must call super._willFallback().
|
|
|
|
*/
|
2020-07-13 08:54:08 +00:00
|
|
|
function _willFallback() internal virtual {}
|
2020-05-29 16:45:37 +00:00
|
|
|
|
2020-07-13 08:54:08 +00:00
|
|
|
/**
|
2020-05-29 16:45:37 +00:00
|
|
|
* @dev fallback implementation.
|
|
|
|
* Extracted to enable manual triggering.
|
|
|
|
*/
|
2020-07-13 08:54:08 +00:00
|
|
|
function _fallback() internal {
|
|
|
|
_willFallback();
|
|
|
|
_delegate(_implementation());
|
|
|
|
}
|
2020-05-29 16:45:37 +00:00
|
|
|
}
|