BeaconProxy.test.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. const { expectRevert } = require('@openzeppelin/test-helpers');
  2. const { getSlot, BeaconSlot } = require('../../helpers/erc1967');
  3. const { expect } = require('chai');
  4. const UpgradeableBeacon = artifacts.require('UpgradeableBeacon');
  5. const BeaconProxy = artifacts.require('BeaconProxy');
  6. const DummyImplementation = artifacts.require('DummyImplementation');
  7. const DummyImplementationV2 = artifacts.require('DummyImplementationV2');
  8. const BadBeaconNoImpl = artifacts.require('BadBeaconNoImpl');
  9. const BadBeaconNotContract = artifacts.require('BadBeaconNotContract');
  10. contract('BeaconProxy', function (accounts) {
  11. const [anotherAccount] = accounts;
  12. describe('bad beacon is not accepted', async function () {
  13. it('non-contract beacon', async function () {
  14. await expectRevert(
  15. BeaconProxy.new(anotherAccount, '0x'),
  16. 'ERC1967: new beacon is not a contract',
  17. );
  18. });
  19. it('non-compliant beacon', async function () {
  20. const beacon = await BadBeaconNoImpl.new();
  21. await expectRevert.unspecified(
  22. BeaconProxy.new(beacon.address, '0x'),
  23. );
  24. });
  25. it('non-contract implementation', async function () {
  26. const beacon = await BadBeaconNotContract.new();
  27. await expectRevert(
  28. BeaconProxy.new(beacon.address, '0x'),
  29. 'ERC1967: beacon implementation is not a contract',
  30. );
  31. });
  32. });
  33. before('deploy implementation', async function () {
  34. this.implementationV0 = await DummyImplementation.new();
  35. this.implementationV1 = await DummyImplementationV2.new();
  36. });
  37. describe('initialization', function () {
  38. before(function () {
  39. this.assertInitialized = async ({ value, balance }) => {
  40. const beaconSlot = await getSlot(this.proxy, BeaconSlot);
  41. const beaconAddress = web3.utils.toChecksumAddress(beaconSlot.substr(-40));
  42. expect(beaconAddress).to.equal(this.beacon.address);
  43. const dummy = new DummyImplementation(this.proxy.address);
  44. expect(await dummy.value()).to.bignumber.eq(value);
  45. expect(await web3.eth.getBalance(this.proxy.address)).to.bignumber.eq(balance);
  46. };
  47. });
  48. beforeEach('deploy beacon', async function () {
  49. this.beacon = await UpgradeableBeacon.new(this.implementationV0.address);
  50. });
  51. it('no initialization', async function () {
  52. const data = Buffer.from('');
  53. const balance = '10';
  54. this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance });
  55. await this.assertInitialized({ value: '0', balance });
  56. });
  57. it('non-payable initialization', async function () {
  58. const value = '55';
  59. const data = this.implementationV0.contract.methods
  60. .initializeNonPayableWithValue(value)
  61. .encodeABI();
  62. this.proxy = await BeaconProxy.new(this.beacon.address, data);
  63. await this.assertInitialized({ value, balance: '0' });
  64. });
  65. it('payable initialization', async function () {
  66. const value = '55';
  67. const data = this.implementationV0.contract.methods
  68. .initializePayableWithValue(value)
  69. .encodeABI();
  70. const balance = '100';
  71. this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance });
  72. await this.assertInitialized({ value, balance });
  73. });
  74. it('reverting initialization', async function () {
  75. const data = this.implementationV0.contract.methods.reverts().encodeABI();
  76. await expectRevert(
  77. BeaconProxy.new(this.beacon.address, data),
  78. 'DummyImplementation reverted',
  79. );
  80. });
  81. });
  82. it('upgrade a proxy by upgrading its beacon', async function () {
  83. const beacon = await UpgradeableBeacon.new(this.implementationV0.address);
  84. const value = '10';
  85. const data = this.implementationV0.contract.methods
  86. .initializeNonPayableWithValue(value)
  87. .encodeABI();
  88. const proxy = await BeaconProxy.new(beacon.address, data);
  89. const dummy = new DummyImplementation(proxy.address);
  90. // test initial values
  91. expect(await dummy.value()).to.bignumber.eq(value);
  92. // test initial version
  93. expect(await dummy.version()).to.eq('V1');
  94. // upgrade beacon
  95. await beacon.upgradeTo(this.implementationV1.address);
  96. // test upgraded version
  97. expect(await dummy.version()).to.eq('V2');
  98. });
  99. it('upgrade 2 proxies by upgrading shared beacon', async function () {
  100. const value1 = '10';
  101. const value2 = '42';
  102. const beacon = await UpgradeableBeacon.new(this.implementationV0.address);
  103. const proxy1InitializeData = this.implementationV0.contract.methods
  104. .initializeNonPayableWithValue(value1)
  105. .encodeABI();
  106. const proxy1 = await BeaconProxy.new(beacon.address, proxy1InitializeData);
  107. const proxy2InitializeData = this.implementationV0.contract.methods
  108. .initializeNonPayableWithValue(value2)
  109. .encodeABI();
  110. const proxy2 = await BeaconProxy.new(beacon.address, proxy2InitializeData);
  111. const dummy1 = new DummyImplementation(proxy1.address);
  112. const dummy2 = new DummyImplementation(proxy2.address);
  113. // test initial values
  114. expect(await dummy1.value()).to.bignumber.eq(value1);
  115. expect(await dummy2.value()).to.bignumber.eq(value2);
  116. // test initial version
  117. expect(await dummy1.version()).to.eq('V1');
  118. expect(await dummy2.version()).to.eq('V1');
  119. // upgrade beacon
  120. await beacon.upgradeTo(this.implementationV1.address);
  121. // test upgraded version
  122. expect(await dummy1.version()).to.eq('V2');
  123. expect(await dummy2.version()).to.eq('V2');
  124. });
  125. });