UpgradeableProxy.behaviour.js 6.8 KB

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