RefundEscrow.test.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. const { balance, constants, ether, expectEvent, shouldFail } = require('openzeppelin-test-helpers');
  2. const { ZERO_ADDRESS } = constants;
  3. const RefundEscrow = artifacts.require('RefundEscrow');
  4. contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee2]) {
  5. const amount = ether('54');
  6. const refundees = [refundee1, refundee2];
  7. it('requires a non-null beneficiary', async function () {
  8. await shouldFail.reverting.withMessage(
  9. RefundEscrow.new(ZERO_ADDRESS, { from: primary }), 'RefundEscrow: beneficiary is the zero address'
  10. );
  11. });
  12. context('once deployed', function () {
  13. beforeEach(async function () {
  14. this.escrow = await RefundEscrow.new(beneficiary, { from: primary });
  15. });
  16. context('active state', function () {
  17. it('has beneficiary and state', async function () {
  18. (await this.escrow.beneficiary()).should.be.equal(beneficiary);
  19. (await this.escrow.state()).should.be.bignumber.equal('0');
  20. });
  21. it('accepts deposits', async function () {
  22. await this.escrow.deposit(refundee1, { from: primary, value: amount });
  23. (await this.escrow.depositsOf(refundee1)).should.be.bignumber.equal(amount);
  24. });
  25. it('does not refund refundees', async function () {
  26. await this.escrow.deposit(refundee1, { from: primary, value: amount });
  27. await shouldFail.reverting.withMessage(this.escrow.withdraw(refundee1),
  28. 'ConditionalEscrow: payee is not allowed to withdraw'
  29. );
  30. });
  31. it('does not allow beneficiary withdrawal', async function () {
  32. await this.escrow.deposit(refundee1, { from: primary, value: amount });
  33. await shouldFail.reverting.withMessage(this.escrow.beneficiaryWithdraw(),
  34. 'RefundEscrow: beneficiary can only withdraw while closed'
  35. );
  36. });
  37. });
  38. it('only the primary account can enter closed state', async function () {
  39. await shouldFail.reverting.withMessage(this.escrow.close({ from: beneficiary }),
  40. 'Secondary: caller is not the primary account'
  41. );
  42. const { logs } = await this.escrow.close({ from: primary });
  43. expectEvent.inLogs(logs, 'RefundsClosed');
  44. });
  45. context('closed state', function () {
  46. beforeEach(async function () {
  47. await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: primary, value: amount })));
  48. await this.escrow.close({ from: primary });
  49. });
  50. it('rejects deposits', async function () {
  51. await shouldFail.reverting.withMessage(this.escrow.deposit(refundee1, { from: primary, value: amount }),
  52. 'RefundEscrow: can only deposit while active'
  53. );
  54. });
  55. it('does not refund refundees', async function () {
  56. await shouldFail.reverting.withMessage(this.escrow.withdraw(refundee1),
  57. 'ConditionalEscrow: payee is not allowed to withdraw'
  58. );
  59. });
  60. it('allows beneficiary withdrawal', async function () {
  61. const balanceTracker = await balance.tracker(beneficiary);
  62. await this.escrow.beneficiaryWithdraw();
  63. (await balanceTracker.delta()).should.be.bignumber.equal(amount.muln(refundees.length));
  64. });
  65. it('prevents entering the refund state', async function () {
  66. await shouldFail.reverting.withMessage(this.escrow.enableRefunds({ from: primary }),
  67. 'RefundEscrow: can only enable refunds while active'
  68. );
  69. });
  70. it('prevents re-entering the closed state', async function () {
  71. await shouldFail.reverting.withMessage(this.escrow.close({ from: primary }),
  72. 'RefundEscrow: can only close while active'
  73. );
  74. });
  75. });
  76. it('only the primary account can enter refund state', async function () {
  77. await shouldFail.reverting.withMessage(this.escrow.enableRefunds({ from: beneficiary }),
  78. 'Secondary: caller is not the primary account'
  79. );
  80. const { logs } = await this.escrow.enableRefunds({ from: primary });
  81. expectEvent.inLogs(logs, 'RefundsEnabled');
  82. });
  83. context('refund state', function () {
  84. beforeEach(async function () {
  85. await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: primary, value: amount })));
  86. await this.escrow.enableRefunds({ from: primary });
  87. });
  88. it('rejects deposits', async function () {
  89. await shouldFail.reverting.withMessage(this.escrow.deposit(refundee1, { from: primary, value: amount }),
  90. 'RefundEscrow: can only deposit while active'
  91. );
  92. });
  93. it('refunds refundees', async function () {
  94. for (const refundee of [refundee1, refundee2]) {
  95. const balanceTracker = await balance.tracker(refundee);
  96. await this.escrow.withdraw(refundee, { from: primary });
  97. (await balanceTracker.delta()).should.be.bignumber.equal(amount);
  98. }
  99. });
  100. it('does not allow beneficiary withdrawal', async function () {
  101. await shouldFail.reverting.withMessage(this.escrow.beneficiaryWithdraw(),
  102. 'RefundEscrow: beneficiary can only withdraw while closed'
  103. );
  104. });
  105. it('prevents entering the closed state', async function () {
  106. await shouldFail.reverting.withMessage(this.escrow.close({ from: primary }),
  107. 'RefundEscrow: can only close while active'
  108. );
  109. });
  110. it('prevents re-entering the refund state', async function () {
  111. await shouldFail.reverting.withMessage(this.escrow.enableRefunds({ from: primary }),
  112. 'RefundEscrow: can only enable refunds while active'
  113. );
  114. });
  115. });
  116. });
  117. });