BeaconProxy.test.js 5.3 KB

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