PullPaymentUpgradeable.sol 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts v4.4.1 (security/PullPayment.sol)
  3. pragma solidity ^0.8.0;
  4. import "../utils/escrow/EscrowUpgradeable.sol";
  5. import "../proxy/utils/Initializable.sol";
  6. /**
  7. * @dev Simple implementation of a
  8. * https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls[pull-payment]
  9. * strategy, where the paying contract doesn't interact directly with the
  10. * receiver account, which must withdraw its payments itself.
  11. *
  12. * Pull-payments are often considered the best practice when it comes to sending
  13. * Ether, security-wise. It prevents recipients from blocking execution, and
  14. * eliminates reentrancy concerns.
  15. *
  16. * TIP: If you would like to learn more about reentrancy and alternative ways
  17. * to protect against it, check out our blog post
  18. * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
  19. *
  20. * To use, derive from the `PullPayment` contract, and use {_asyncTransfer}
  21. * instead of Solidity's `transfer` function. Payees can query their due
  22. * payments with {payments}, and retrieve them with {withdrawPayments}.
  23. */
  24. abstract contract PullPaymentUpgradeable is Initializable {
  25. EscrowUpgradeable private _escrow;
  26. function __PullPayment_init() internal onlyInitializing {
  27. __PullPayment_init_unchained();
  28. }
  29. function __PullPayment_init_unchained() internal onlyInitializing {
  30. _escrow = new EscrowUpgradeable();
  31. _escrow.initialize();
  32. }
  33. /**
  34. * @dev Withdraw accumulated payments, forwarding all gas to the recipient.
  35. *
  36. * Note that _any_ account can call this function, not just the `payee`.
  37. * This means that contracts unaware of the `PullPayment` protocol can still
  38. * receive funds this way, by having a separate account call
  39. * {withdrawPayments}.
  40. *
  41. * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
  42. * Make sure you trust the recipient, or are either following the
  43. * checks-effects-interactions pattern or using {ReentrancyGuard}.
  44. *
  45. * @param payee Whose payments will be withdrawn.
  46. */
  47. function withdrawPayments(address payable payee) public virtual {
  48. _escrow.withdraw(payee);
  49. }
  50. /**
  51. * @dev Returns the payments owed to an address.
  52. * @param dest The creditor's address.
  53. */
  54. function payments(address dest) public view returns (uint256) {
  55. return _escrow.depositsOf(dest);
  56. }
  57. /**
  58. * @dev Called by the payer to store the sent amount as credit to be pulled.
  59. * Funds sent in this way are stored in an intermediate {Escrow} contract, so
  60. * there is no danger of them being spent before withdrawal.
  61. *
  62. * @param dest The destination address of the funds.
  63. * @param amount The amount to transfer.
  64. */
  65. function _asyncTransfer(address dest, uint256 amount) internal virtual {
  66. _escrow.deposit{value: amount}(dest);
  67. }
  68. /**
  69. * This empty reserved space is put in place to allow future versions to add new
  70. * variables without shifting down storage in the inheritance chain.
  71. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  72. */
  73. uint256[50] private __gap;
  74. }