Proxy.sol 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.0;
  3. /**
  4. * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
  5. * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
  6. * be specified by overriding the virtual {_implementation} function.
  7. *
  8. * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
  9. * different contract through the {_delegate} function.
  10. *
  11. * The success and return data of the delegated call will be returned back to the caller of the proxy.
  12. */
  13. abstract contract Proxy {
  14. /**
  15. * @dev Delegates the current call to `implementation`.
  16. *
  17. * This function does not return to its internall call site, it will return directly to the external caller.
  18. */
  19. function _delegate(address implementation) internal virtual {
  20. // solhint-disable-next-line no-inline-assembly
  21. assembly {
  22. // Copy msg.data. We take full control of memory in this inline assembly
  23. // block because it will not return to Solidity code. We overwrite the
  24. // Solidity scratch pad at memory position 0.
  25. calldatacopy(0, 0, calldatasize())
  26. // Call the implementation.
  27. // out and outsize are 0 because we don't know the size yet.
  28. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
  29. // Copy the returned data.
  30. returndatacopy(0, 0, returndatasize())
  31. switch result
  32. // delegatecall returns 0 on error.
  33. case 0 { revert(0, returndatasize()) }
  34. default { return(0, returndatasize()) }
  35. }
  36. }
  37. /**
  38. * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
  39. * and {_fallback} should delegate.
  40. */
  41. function _implementation() internal view virtual returns (address);
  42. /**
  43. * @dev Delegates the current call to the address returned by `_implementation()`.
  44. *
  45. * This function does not return to its internall call site, it will return directly to the external caller.
  46. */
  47. function _fallback() internal virtual {
  48. _beforeFallback();
  49. _delegate(_implementation());
  50. }
  51. /**
  52. * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
  53. * function in the contract matches the call data.
  54. */
  55. fallback () external payable virtual {
  56. _fallback();
  57. }
  58. /**
  59. * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
  60. * is empty.
  61. */
  62. receive () external payable virtual {
  63. _fallback();
  64. }
  65. /**
  66. * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
  67. * call, or as part of the Solidity `fallback` or `receive` functions.
  68. *
  69. * If overriden should call `super._beforeFallback()`.
  70. */
  71. function _beforeFallback() internal virtual {
  72. }
  73. }