Proxy.behaviour.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. const { ethers } = require('hardhat');
  2. const { expect } = require('chai');
  3. const { getAddressInSlot, ImplementationSlot } = require('../helpers/storage');
  4. module.exports = function shouldBehaveLikeProxy() {
  5. it('cannot be initialized with a non-contract address', async function () {
  6. const initializeData = '0x';
  7. await expect(this.createProxy(this.nonContractAddress, initializeData))
  8. .to.be.revertedWithCustomError(await ethers.getContractFactory('ERC1967Proxy'), 'ERC1967InvalidImplementation')
  9. .withArgs(this.nonContractAddress);
  10. });
  11. const assertProxyInitialization = function ({ value, balance }) {
  12. it('sets the implementation address', async function () {
  13. expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementation);
  14. });
  15. it('initializes the proxy', async function () {
  16. const dummy = this.implementation.attach(this.proxy);
  17. expect(await dummy.value()).to.equal(value);
  18. });
  19. it('has expected balance', async function () {
  20. expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance);
  21. });
  22. };
  23. describe('without initialization', function () {
  24. const initializeData = '0x';
  25. describe('when not sending balance', function () {
  26. beforeEach('creating proxy', async function () {
  27. this.proxy = await this.createProxy(this.implementation, initializeData);
  28. });
  29. assertProxyInitialization({ value: 0n, balance: 0n });
  30. });
  31. describe('when sending some balance', function () {
  32. const value = 10n ** 5n;
  33. it('reverts', async function () {
  34. await expect(this.createProxy(this.implementation, initializeData, { value })).to.be.reverted;
  35. });
  36. });
  37. });
  38. describe('initialization without parameters', function () {
  39. describe('non payable', function () {
  40. const expectedInitializedValue = 10n;
  41. beforeEach(function () {
  42. this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayable');
  43. });
  44. describe('when not sending balance', function () {
  45. beforeEach('creating proxy', async function () {
  46. this.proxy = await this.createProxy(this.implementation, this.initializeData);
  47. });
  48. assertProxyInitialization({
  49. value: expectedInitializedValue,
  50. balance: 0n,
  51. });
  52. });
  53. describe('when sending some balance', function () {
  54. const value = 10n ** 5n;
  55. it('reverts', async function () {
  56. await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted;
  57. });
  58. });
  59. });
  60. describe('payable', function () {
  61. const expectedInitializedValue = 100n;
  62. beforeEach(function () {
  63. this.initializeData = this.implementation.interface.encodeFunctionData('initializePayable');
  64. });
  65. describe('when not sending balance', function () {
  66. beforeEach('creating proxy', async function () {
  67. this.proxy = await this.createProxy(this.implementation, this.initializeData);
  68. });
  69. assertProxyInitialization({
  70. value: expectedInitializedValue,
  71. balance: 0n,
  72. });
  73. });
  74. describe('when sending some balance', function () {
  75. const value = 10e5;
  76. beforeEach('creating proxy', async function () {
  77. this.proxy = await this.createProxy(this.implementation, this.initializeData, { value });
  78. });
  79. assertProxyInitialization({
  80. value: expectedInitializedValue,
  81. balance: value,
  82. });
  83. });
  84. });
  85. });
  86. describe('initialization with parameters', function () {
  87. describe('non payable', function () {
  88. const expectedInitializedValue = 10n;
  89. beforeEach(function () {
  90. this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayableWithValue', [
  91. expectedInitializedValue,
  92. ]);
  93. });
  94. describe('when not sending balance', function () {
  95. beforeEach('creating proxy', async function () {
  96. this.proxy = await this.createProxy(this.implementation, this.initializeData);
  97. });
  98. assertProxyInitialization({
  99. value: expectedInitializedValue,
  100. balance: 0,
  101. });
  102. });
  103. describe('when sending some balance', function () {
  104. const value = 10e5;
  105. it('reverts', async function () {
  106. await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted;
  107. });
  108. });
  109. });
  110. describe('payable', function () {
  111. const expectedInitializedValue = 42n;
  112. beforeEach(function () {
  113. this.initializeData = this.implementation.interface.encodeFunctionData('initializePayableWithValue', [
  114. expectedInitializedValue,
  115. ]);
  116. });
  117. describe('when not sending balance', function () {
  118. beforeEach('creating proxy', async function () {
  119. this.proxy = await this.createProxy(this.implementation, this.initializeData);
  120. });
  121. assertProxyInitialization({
  122. value: expectedInitializedValue,
  123. balance: 0n,
  124. });
  125. });
  126. describe('when sending some balance', function () {
  127. const value = 10n ** 5n;
  128. beforeEach('creating proxy', async function () {
  129. this.proxy = await this.createProxy(this.implementation, this.initializeData, { value });
  130. });
  131. assertProxyInitialization({
  132. value: expectedInitializedValue,
  133. balance: value,
  134. });
  135. });
  136. });
  137. describe('reverting initialization', function () {
  138. beforeEach(function () {
  139. this.initializeData = this.implementation.interface.encodeFunctionData('reverts');
  140. });
  141. it('reverts', async function () {
  142. await expect(this.createProxy(this.implementation, this.initializeData)).to.be.reverted;
  143. });
  144. });
  145. });
  146. };