Proxy.behaviour.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. const { expectRevert } = require('@openzeppelin/test-helpers');
  2. const { getSlot, ImplementationSlot } = require('../helpers/erc1967');
  3. const { expect } = require('chai');
  4. const { expectRevertCustomError } = require('../helpers/customError');
  5. const DummyImplementation = artifacts.require('DummyImplementation');
  6. module.exports = function shouldBehaveLikeProxy(createProxy, accounts) {
  7. const [proxyCreator] = accounts;
  8. it('cannot be initialized with a non-contract address', async function () {
  9. const nonContractAddress = proxyCreator;
  10. const initializeData = Buffer.from('');
  11. await expectRevert.unspecified(
  12. createProxy(nonContractAddress, initializeData, {
  13. from: proxyCreator,
  14. }),
  15. );
  16. });
  17. before('deploy implementation', async function () {
  18. this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address);
  19. });
  20. const assertProxyInitialization = function ({ value, balance }) {
  21. it('sets the implementation address', async function () {
  22. const implementationSlot = await getSlot(this.proxy, ImplementationSlot);
  23. const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40));
  24. expect(implementationAddress).to.be.equal(this.implementation);
  25. });
  26. it('initializes the proxy', async function () {
  27. const dummy = new DummyImplementation(this.proxy);
  28. expect(await dummy.value()).to.be.bignumber.equal(value.toString());
  29. });
  30. it('has expected balance', async function () {
  31. expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString());
  32. });
  33. };
  34. describe('without initialization', function () {
  35. const initializeData = Buffer.from('');
  36. describe('when not sending balance', function () {
  37. beforeEach('creating proxy', async function () {
  38. this.proxy = (
  39. await createProxy(this.implementation, initializeData, {
  40. from: proxyCreator,
  41. })
  42. ).address;
  43. });
  44. assertProxyInitialization({ value: 0, balance: 0 });
  45. });
  46. describe('when sending some balance', function () {
  47. const value = 10e5;
  48. it('reverts', async function () {
  49. await expectRevertCustomError(
  50. createProxy(this.implementation, initializeData, {
  51. from: proxyCreator,
  52. value,
  53. }),
  54. 'ERC1967NonPayable',
  55. [],
  56. );
  57. });
  58. });
  59. });
  60. describe('initialization without parameters', function () {
  61. describe('non payable', function () {
  62. const expectedInitializedValue = 10;
  63. const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI();
  64. describe('when not sending balance', function () {
  65. beforeEach('creating proxy', async function () {
  66. this.proxy = (
  67. await createProxy(this.implementation, initializeData, {
  68. from: proxyCreator,
  69. })
  70. ).address;
  71. });
  72. assertProxyInitialization({
  73. value: expectedInitializedValue,
  74. balance: 0,
  75. });
  76. });
  77. describe('when sending some balance', function () {
  78. const value = 10e5;
  79. it('reverts', async function () {
  80. await expectRevert.unspecified(
  81. createProxy(this.implementation, initializeData, { from: proxyCreator, value }),
  82. );
  83. });
  84. });
  85. });
  86. describe('payable', function () {
  87. const expectedInitializedValue = 100;
  88. const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI();
  89. describe('when not sending balance', function () {
  90. beforeEach('creating proxy', async function () {
  91. this.proxy = (
  92. await createProxy(this.implementation, initializeData, {
  93. from: proxyCreator,
  94. })
  95. ).address;
  96. });
  97. assertProxyInitialization({
  98. value: expectedInitializedValue,
  99. balance: 0,
  100. });
  101. });
  102. describe('when sending some balance', function () {
  103. const value = 10e5;
  104. beforeEach('creating proxy', async function () {
  105. this.proxy = (
  106. await createProxy(this.implementation, initializeData, {
  107. from: proxyCreator,
  108. value,
  109. })
  110. ).address;
  111. });
  112. assertProxyInitialization({
  113. value: expectedInitializedValue,
  114. balance: value,
  115. });
  116. });
  117. });
  118. });
  119. describe('initialization with parameters', function () {
  120. describe('non payable', function () {
  121. const expectedInitializedValue = 10;
  122. const initializeData = new DummyImplementation('').contract.methods
  123. .initializeNonPayableWithValue(expectedInitializedValue)
  124. .encodeABI();
  125. describe('when not sending balance', function () {
  126. beforeEach('creating proxy', async function () {
  127. this.proxy = (
  128. await createProxy(this.implementation, initializeData, {
  129. from: proxyCreator,
  130. })
  131. ).address;
  132. });
  133. assertProxyInitialization({
  134. value: expectedInitializedValue,
  135. balance: 0,
  136. });
  137. });
  138. describe('when sending some balance', function () {
  139. const value = 10e5;
  140. it('reverts', async function () {
  141. await expectRevert.unspecified(
  142. createProxy(this.implementation, initializeData, { from: proxyCreator, value }),
  143. );
  144. });
  145. });
  146. });
  147. describe('payable', function () {
  148. const expectedInitializedValue = 42;
  149. const initializeData = new DummyImplementation('').contract.methods
  150. .initializePayableWithValue(expectedInitializedValue)
  151. .encodeABI();
  152. describe('when not sending balance', function () {
  153. beforeEach('creating proxy', async function () {
  154. this.proxy = (
  155. await createProxy(this.implementation, initializeData, {
  156. from: proxyCreator,
  157. })
  158. ).address;
  159. });
  160. assertProxyInitialization({
  161. value: expectedInitializedValue,
  162. balance: 0,
  163. });
  164. });
  165. describe('when sending some balance', function () {
  166. const value = 10e5;
  167. beforeEach('creating proxy', async function () {
  168. this.proxy = (
  169. await createProxy(this.implementation, initializeData, {
  170. from: proxyCreator,
  171. value,
  172. })
  173. ).address;
  174. });
  175. assertProxyInitialization({
  176. value: expectedInitializedValue,
  177. balance: value,
  178. });
  179. });
  180. });
  181. describe('reverting initialization', function () {
  182. const initializeData = new DummyImplementation('').contract.methods.reverts().encodeABI();
  183. it('reverts', async function () {
  184. await expectRevert(
  185. createProxy(this.implementation, initializeData, { from: proxyCreator }),
  186. 'DummyImplementation reverted',
  187. );
  188. });
  189. });
  190. });
  191. };