diff --git a/.vscode/settings.json b/.vscode/settings.json index a2f9328f..744ac11d 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,5 +12,6 @@ ], "editor.codeActionsOnSave": { "source.fixAll.eslint": true - } + }, + "solidity.compileUsingRemoteVersion": "v0.8.9+commit.e5eed63a" } diff --git a/contracts/src/property/Property.sol b/contracts/src/property/Property.sol index 9b1ca0b9..105f10bc 100755 --- a/contracts/src/property/Property.sol +++ b/contracts/src/property/Property.sol @@ -1,20 +1,21 @@ // SPDX-License-Identifier: MPL-2.0 pragma solidity =0.8.9; +import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "../../interface/IWithdraw.sol"; import "../../interface/IProperty.sol"; import "../../interface/IPropertyFactory.sol"; import "../../interface/IPolicy.sol"; -import "../common/registry/UsingRegistry.sol"; +import "../common/registry/InitializableUsingRegistry.sol"; /** * A contract that represents the assets of the user and collects staking from the stakers. * Property contract inherits ERC20. * Holders of Property contracts(tokens) receive holder rewards according to their share. */ -contract Property is ERC20, UsingRegistry, IProperty { +contract Property is ERC20Upgradeable, InitializableUsingRegistry, IProperty { uint8 private constant PROPERTY_DECIMALS = 18; uint8 private __decimals; uint256 private constant SUPPLY = 10000000000000000000000000; @@ -32,12 +33,15 @@ contract Property is ERC20, UsingRegistry, IProperty { * @param _name The name of the new Property. * @param _symbol The symbol of the new Property. */ - constructor( + function initialize( address _registry, address _own, string memory _name, string memory _symbol - ) ERC20(_name, _symbol) UsingRegistry(_registry) { + ) public initializer { + __ERC20_init(_name, _symbol); + __UsingRegistry_init(_registry); + /** * Validates the sender is PropertyFactory contract. */ diff --git a/contracts/src/property/PropertyFactory.sol b/contracts/src/property/PropertyFactory.sol index 1ade91f3..dc3e5ad0 100644 --- a/contracts/src/property/PropertyFactory.sol +++ b/contracts/src/property/PropertyFactory.sol @@ -6,6 +6,7 @@ import "../../interface/IPropertyFactory.sol"; import "../../interface/IMarket.sol"; import "../common/registry/InitializableUsingRegistry.sol"; import "./Property.sol"; +import "@openzeppelin/contracts/proxy/Clones.sol"; /** * A factory contract that creates a new Property contract. @@ -77,13 +78,13 @@ contract PropertyFactory is InitializableUsingRegistry, IPropertyFactory { /** * Creates a new Property contract. */ - Property _property = new Property( + address propertyAddr = Clones.clone(registry().registries("Property")); + Property(propertyAddr).initialize( address(registry()), _author, _name, _symbol ); - address propertyAddr = address(_property); /** * Adds the new Property contract to the Property address set. diff --git a/migrations/update/1_update-property-factory-with-seed-property.ts b/migrations/update/1_update-property-factory-with-seed-property.ts new file mode 100644 index 00000000..df382ff0 --- /dev/null +++ b/migrations/update/1_update-property-factory-with-seed-property.ts @@ -0,0 +1,49 @@ +import { upgradeProxy, validateUpgrade } from '@openzeppelin/truffle-upgrades' +import { type ContractClass } from '@openzeppelin/truffle-upgrades/dist/utils' + +const PropertyFactory = artifacts.require('PropertyFactory') +const AddressRegistry = artifacts.require('AddressRegistry') + +const handler = async function (_, network) { + if (network === 'test') { + return + } + + const proxyAddress = process.env.PROPERTY_FACTORY_PROXY! + const proxyAddressAddressRegistry = process.env.ADDRESS_REGISTRY_PROXY! + + const newProperty = artifacts.require('Property') + _.deploy(newProperty) + const deployedNewProperty = await newProperty.deployed() + console.log(`[CONFIRMED] new seed Property: ${deployedNewProperty.address}`) + + const existingAddressRegistry = await AddressRegistry.deployed().catch(() => + AddressRegistry.at(proxyAddressAddressRegistry) + ) + + await existingAddressRegistry.setRegistry( + 'Property', + deployedNewProperty.address + ) + console.log('[CONFIRMED] set the seed Property to Registry') + + const existing = await PropertyFactory.deployed().catch(() => + PropertyFactory.at(proxyAddress) + ) + + console.log('proxy:', existing.address) + + await validateUpgrade( + existing.address, + PropertyFactory as unknown as ContractClass + ) + + console.log('New implementation is valid') + + await upgradeProxy( + existing.address, + PropertyFactory as unknown as ContractClass + ) +} as Truffle.Migration + +export = handler diff --git a/test/property/property.ts b/test/property/property.ts index e59acea4..07898099 100755 --- a/test/property/property.ts +++ b/test/property/property.ts @@ -130,11 +130,14 @@ contract( describe('Property; constructor', () => { it('Cannot be created from other than factory', async () => { - const result = await propertyContract - .new(dev.addressRegistry.address, author, 'sample', 'SAMPLE', { + const propertyInstance = await propertyContract.new() + + const result = await propertyInstance + .initialize(dev.addressRegistry.address, author, 'sample', 'SAMPLE', { from: deployer, }) .catch((err: Error) => err) + validateAddressErrorMessage(result) }) it('The author, decimal places, and number of issues are fixed values', async () => { @@ -142,7 +145,8 @@ contract( 'PropertyFactory', propertyFactory ) - const propertyInstance = await propertyContract.new( + const propertyInstance = await propertyContract.new() + await propertyInstance.initialize( dev.addressRegistry.address, author, 'sample', @@ -179,7 +183,8 @@ contract( 'PropertyFactory', propertyFactory ) - const propertyInstance = await propertyContract.new( + const propertyInstance = await propertyContract.new() + await propertyInstance.initialize( dev.addressRegistry.address, author, 'sample', @@ -214,7 +219,8 @@ contract( 'PropertyFactory', propertyFactory ) - const propertyInstance = await propertyContract.new( + const propertyInstance = await propertyContract.new() + await propertyInstance.initialize( dev.addressRegistry.address, author, 'sample', @@ -238,7 +244,8 @@ contract( 'PropertyFactory', propertyFactory ) - const propertyInstance = await propertyContract.new( + const propertyInstance = await propertyContract.new() + await propertyInstance.initialize( dev.addressRegistry.address, author, 'sample', @@ -273,7 +280,8 @@ contract( 'PropertyFactory', propertyFactory ) - const propertyInstance = await propertyContract.new( + const propertyInstance = await propertyContract.new() + await propertyInstance.initialize( dev.addressRegistry.address, author, 'sample', diff --git a/test/test-lib/instance.ts b/test/test-lib/instance.ts index cc140589..795b8fa3 100644 --- a/test/test-lib/instance.ts +++ b/test/test-lib/instance.ts @@ -19,6 +19,7 @@ import type { ArbSysTestInstance, DevPolygonInstance, TokenURIDescriptorTestInstance, + PropertyInstance, TokenURIDescriptorCopyTestInstance, TokenURIDescriptorLegacyTestInstance, } from '../../types/truffle-contracts' @@ -248,7 +249,20 @@ export class DevProtocolInstance { ) } + public async generateProperty(): Promise { + const Property = contract('Property') + const property = await Property.new(this.fromDeployer) + + await this.addressRegistry.setRegistry( + 'Property', + property.address, + this.fromDeployer + ) + } + public async generatePropertyFactory(): Promise { + await this.generateProperty() + const [proxfied] = await deployProxy( contract('PropertyFactory'), this._deployer