PullPayment.sol 2.6 KB

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