PullPayment.sol 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. pragma solidity ^0.5.0;
  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. * To use, derive from the `PullPayment` contract, and use {_asyncTransfer}
  14. * instead of Solidity's `transfer` function. Payees can query their due
  15. * payments with {payments}, and retrieve them with {withdrawPayments}.
  16. */
  17. contract PullPayment {
  18. Escrow private _escrow;
  19. constructor () internal {
  20. _escrow = new Escrow();
  21. }
  22. /**
  23. * @dev Withdraw accumulated payments.
  24. *
  25. * Note that _any_ account can call this function, not just the `payee`.
  26. * This means that contracts unaware of the `PullPayment` protocol can still
  27. * receive funds this way, by having a separate account call
  28. * {withdrawPayments}.
  29. *
  30. * NOTE: This function has been deprecated, use {withdrawPaymentsWithGas}
  31. * instead. Calling contracts with fixed gas limits is an anti-pattern and
  32. * may break contract interactions in network upgrades (hardforks).
  33. * https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more.]
  34. *
  35. * @param payee Whose payments will be withdrawn.
  36. */
  37. function withdrawPayments(address payable payee) public {
  38. _escrow.withdraw(payee);
  39. }
  40. /**
  41. * @dev Same as {withdrawPayments}, but forwarding all gas to the recipient.
  42. *
  43. * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
  44. * Make sure you trust the recipient, or are either following the
  45. * checks-effects-interactions pattern or using {ReentrancyGuard}.
  46. *
  47. * _Available since v2.4.0._
  48. */
  49. function withdrawPaymentsWithGas(address payable payee) external {
  50. _escrow.withdrawWithGas(payee);
  51. }
  52. /**
  53. * @dev Returns the payments owed to an address.
  54. * @param dest The creditor's address.
  55. */
  56. function payments(address dest) public view returns (uint256) {
  57. return _escrow.depositsOf(dest);
  58. }
  59. /**
  60. * @dev Called by the payer to store the sent amount as credit to be pulled.
  61. * Funds sent in this way are stored in an intermediate {Escrow} contract, so
  62. * there is no danger of them being spent before withdrawal.
  63. *
  64. * @param dest The destination address of the funds.
  65. * @param amount The amount to transfer.
  66. */
  67. function _asyncTransfer(address dest, uint256 amount) internal {
  68. _escrow.deposit.value(amount)(dest);
  69. }
  70. }