PullPayment.sol 2.8 KB

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