Proxy.behaviour.js 5.8 KB

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