UpgradeableProxy.behaviour.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. const { contract, web3 } = require('@openzeppelin/test-environment');
  2. const { BN, expectRevert } = require('@openzeppelin/test-helpers');
  3. const { toChecksumAddress, keccak256 } = require('ethereumjs-util');
  4. const { expect } = require('chai');
  5. const DummyImplementation = contract.fromArtifact('DummyImplementation');
  6. const IMPLEMENTATION_LABEL = 'eip1967.proxy.implementation';
  7. module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAdminAddress, proxyCreator) {
  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, proxyAdminAddress, 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 slot = '0x' + new BN(keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16);
  23. const implementation = toChecksumAddress(await web3.eth.getStorageAt(this.proxy, slot));
  24. expect(implementation).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, proxyAdminAddress, 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. beforeEach('creating proxy', async function () {
  49. this.proxy = (
  50. await createProxy(this.implementation, proxyAdminAddress, initializeData, {
  51. from: proxyCreator,
  52. value,
  53. })
  54. ).address;
  55. });
  56. assertProxyInitialization({ value: 0, balance: value });
  57. });
  58. });
  59. describe('initialization without parameters', function () {
  60. describe('non payable', function () {
  61. const expectedInitializedValue = 10;
  62. const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI();
  63. describe('when not sending balance', function () {
  64. beforeEach('creating proxy', async function () {
  65. this.proxy = (
  66. await createProxy(this.implementation, proxyAdminAddress, initializeData, {
  67. from: proxyCreator,
  68. })
  69. ).address;
  70. });
  71. assertProxyInitialization({
  72. value: expectedInitializedValue,
  73. balance: 0,
  74. });
  75. });
  76. describe('when sending some balance', function () {
  77. const value = 10e5;
  78. it('reverts', async function () {
  79. await expectRevert.unspecified(
  80. createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator, value }),
  81. );
  82. });
  83. });
  84. });
  85. describe('payable', function () {
  86. const expectedInitializedValue = 100;
  87. const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI();
  88. describe('when not sending balance', function () {
  89. beforeEach('creating proxy', async function () {
  90. this.proxy = (
  91. await createProxy(this.implementation, proxyAdminAddress, initializeData, {
  92. from: proxyCreator,
  93. })
  94. ).address;
  95. });
  96. assertProxyInitialization({
  97. value: expectedInitializedValue,
  98. balance: 0,
  99. });
  100. });
  101. describe('when sending some balance', function () {
  102. const value = 10e5;
  103. beforeEach('creating proxy', async function () {
  104. this.proxy = (
  105. await createProxy(this.implementation, proxyAdminAddress, initializeData, {
  106. from: proxyCreator,
  107. value,
  108. })
  109. ).address;
  110. });
  111. assertProxyInitialization({
  112. value: expectedInitializedValue,
  113. balance: value,
  114. });
  115. });
  116. });
  117. });
  118. describe('initialization with parameters', function () {
  119. describe('non payable', function () {
  120. const expectedInitializedValue = 10;
  121. const initializeData = new DummyImplementation('').contract
  122. .methods['initializeNonPayable(uint256)'](expectedInitializedValue).encodeABI();
  123. describe('when not sending balance', function () {
  124. beforeEach('creating proxy', async function () {
  125. this.proxy = (
  126. await createProxy(this.implementation, proxyAdminAddress, initializeData, {
  127. from: proxyCreator,
  128. })
  129. ).address;
  130. });
  131. assertProxyInitialization({
  132. value: expectedInitializedValue,
  133. balance: 0,
  134. });
  135. });
  136. describe('when sending some balance', function () {
  137. const value = 10e5;
  138. it('reverts', async function () {
  139. await expectRevert.unspecified(
  140. createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator, value }),
  141. );
  142. });
  143. });
  144. });
  145. describe('payable', function () {
  146. const expectedInitializedValue = 42;
  147. const initializeData = new DummyImplementation('').contract
  148. .methods['initializePayable(uint256)'](expectedInitializedValue).encodeABI();
  149. describe('when not sending balance', function () {
  150. beforeEach('creating proxy', async function () {
  151. this.proxy = (
  152. await createProxy(this.implementation, proxyAdminAddress, initializeData, {
  153. from: proxyCreator,
  154. })
  155. ).address;
  156. });
  157. assertProxyInitialization({
  158. value: expectedInitializedValue,
  159. balance: 0,
  160. });
  161. });
  162. describe('when sending some balance', function () {
  163. const value = 10e5;
  164. beforeEach('creating proxy', async function () {
  165. this.proxy = (
  166. await createProxy(this.implementation, proxyAdminAddress, initializeData, {
  167. from: proxyCreator,
  168. value,
  169. })
  170. ).address;
  171. });
  172. assertProxyInitialization({
  173. value: expectedInitializedValue,
  174. balance: value,
  175. });
  176. });
  177. });
  178. });
  179. };