PullPayment.sol 2.5 KB

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