Skip to content

Commit

Permalink
Merge pull request #8 from dephy-io/feat/factory-upgradeable
Browse files Browse the repository at this point in the history
feat: factory upgradeable, device simulator
  • Loading branch information
Kabie authored Jul 24, 2024
2 parents a6fa8db + 018ac59 commit 0a3b0a0
Show file tree
Hide file tree
Showing 76 changed files with 5,430 additions and 1,940 deletions.
2 changes: 1 addition & 1 deletion addresses.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"BaseSepolia": {
"ProductFactory": "0x51FF9b79616973da54b68771099C7942519bC0BC",
"ProductFactory": "0xC487C07f0e31d63a840157cBcC316FBcBbFc6088",
"ProductImpl": "0x647d77324E241709BaF63D7f96F0C19ecA06E2e0"
}
}
32 changes: 21 additions & 11 deletions contracts/ProductFactory.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.24;

import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {IProductFactory} from "./IProductFactory.sol";
import {IProduct} from "./IProduct.sol";

contract ProductFactory is
IProductFactory,
Ownable,
EIP712,
ReentrancyGuard,
Pausable
OwnableUpgradeable,
EIP712Upgradeable,
ReentrancyGuardUpgradeable,
PausableUpgradeable,
UUPSUpgradeable
{
string public constant DEPHY_PREFIX = "DEPHY_ID_SIGNED_MESSAGE:";
bytes32 public constant ACTIVATE_DEVICE_TYPEHASH =
Expand All @@ -29,9 +31,13 @@ contract ProductFactory is
mapping(address => mapping(address => uint256))
internal _tokenIdByProductByDevice;

constructor(
address initialOwner
) EIP712("ProductFactory", "1") Ownable(initialOwner) {}
function initialize(address initialOwner) public virtual initializer {
__Ownable_init(initialOwner);
__EIP712_init("ProductFactory", "1");
__ReentrancyGuard_init();
__Pausable_init();
__UUPSUpgradeable_init();
}

modifier onlyVendor(address product) {
if (msg.sender != _vendorByProduct[product]) {
Expand Down Expand Up @@ -244,4 +250,8 @@ contract ProductFactory is
);
return recoveredAddress;
}

function _authorizeUpgrade(
address newImplementation
) internal virtual override onlyOwner {}
}
29 changes: 23 additions & 6 deletions e2e/testAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import {
createTestClient, getContract, Hash, http, publicActions, walletActions,
toBytes, encodePacked, keccak256, serializeSignature, parseSignature,
Address,
encodeFunctionData,
} from 'viem';
import { foundry } from 'viem/chains';
import { generatePrivateKey, privateKeyToAccount, sign } from 'viem/accounts';

import Product from '../out/Product.sol/Product.json';
import ProductFactory from '../out/ProductFactory.sol/ProductFactory.json';
import ERC1967Proxy from '../out/ERC1967Proxy.sol/ERC1967Proxy.json';

let anvil: ChildProcess | undefined;

Expand Down Expand Up @@ -39,18 +41,33 @@ try {
const productImplAddress = productTx.contractAddress;
console.log('ProductImpl:', productImplAddress);

const productFactoryTx = await getReceipt(client.deployContract({
const productFactoryImplTx = await getReceipt(client.deployContract({
account: admin.address,
abi: ProductFactory.abi,
chain: foundry,
bytecode: ProductFactory.bytecode.object as `0x${string}`,
args: [admin.address],
args: [],
}));
const productFactoryAddress = productFactoryTx.contractAddress;
console.log('ProductFactory:', productFactoryAddress);
const productFactoryImplAddress = productFactoryImplTx.contractAddress;
console.log('ProductFactoryImpl:', productFactoryImplAddress);

const productFactoryProxyTx = await getReceipt(client.deployContract({
account: admin.address,
abi: ERC1967Proxy.abi,
chain: foundry,
bytecode: ERC1967Proxy.bytecode.object as `0x${string}`,
args: [productFactoryImplAddress, encodeFunctionData({
abi: ProductFactory.abi,
functionName: 'initialize',
args: [admin.address]
})],
}));

const productFactoryProxyAddress = productFactoryProxyTx.contractAddress;
console.log('ProductFactoryProxy:', productFactoryProxyAddress);

const productFactory = getContract({
address: productFactoryAddress!,
address: productFactoryProxyAddress!,
abi: ProductFactory.abi,
client,
});
Expand Down Expand Up @@ -138,7 +155,7 @@ try {
name: 'ProductFactory',
version: '1',
chainId: client.chain.id,
verifyingContract: productFactoryAddress!,
verifyingContract: productFactoryProxyAddress!,
},
message: {
product: productAddress,
Expand Down
48 changes: 46 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
packages:
- "."
- "tool"
- "tool/demo"
- "tool/**"
- "templates"
12 changes: 10 additions & 2 deletions script/DeployProductFactory.s.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {ProductFactory} from "../contracts/ProductFactory.sol";
import "forge-std/Script.sol";

contract DeployProductFactory is Script {
function run() public returns (address) {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
ProductFactory factory = new ProductFactory(vm.addr(deployerPrivateKey));
ProductFactory factoryImpl = new ProductFactory();
ERC1967Proxy factoryProxy = new ERC1967Proxy(
address(factoryImpl),
abi.encodeWithSelector(
ProductFactory.initialize.selector,
vm.addr(deployerPrivateKey)
)
);
vm.stopBroadcast();
return address(factory);
return address(factoryProxy);
}
}
2 changes: 1 addition & 1 deletion templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pnpm run cli --help
pnpm run cli deploy-vendor \
--rpc $BASE_SEPOLIA_RPC_URL \
--privatekey $PRIVATE_KEY \
--productFactory 0x51FF9b79616973da54b68771099C7942519bC0BC
--productFactory 0xC487C07f0e31d63a840157cBcC316FBcBbFc6088
```

Deployed Vendor address will store in `templates/tmp/address.json`.
Expand Down
37 changes: 30 additions & 7 deletions test/ProductFactory.t.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {IProductFactory} from "../contracts/IProductFactory.sol";
import {ProductFactory} from "../contracts/ProductFactory.sol";
import {Product} from "../contracts/Product.sol";
import {ProductFactoryV2} from "./mock/ProductFactoryV2.sol";
import "forge-std/Test.sol";

contract ProductFactoryTest is Test {
ProductFactory public factory;
Product public productImplementation;
Product public productImpl;
address public owner;
address public vendor;
address public user;
Expand All @@ -22,16 +24,37 @@ contract ProductFactoryTest is Test {
(user, userPK) = makeAddrAndKey("user");
(device, devicePK) = makeAddrAndKey("device");

productImplementation = new Product();
factory = new ProductFactory(owner);
productImpl = new Product();
ProductFactory factoryImpl = new ProductFactory();
ERC1967Proxy factoryProxy = new ERC1967Proxy(
address(factoryImpl),
abi.encodeWithSelector(ProductFactory.initialize.selector, owner)
);
factory = ProductFactory(address(factoryProxy));
}

function testUpgrade() public {
address newOwner = makeAddr("newOwner");
ProductFactoryV2 factoryImplV2 = new ProductFactoryV2();
vm.prank(owner);
factory.upgradeToAndCall(
address(factoryImplV2),
abi.encodeWithSelector(
ProductFactoryV2.initialize.selector,
newOwner
)
);
assertEq(factory.owner(), newOwner);
(, , string memory version, , , , ) = factory.eip712Domain();
assertEq(version, "2");
}

function testCreateProduct() public {
vm.prank(vendor);

IProductFactory.CreateProductArgs memory args = IProductFactory
.CreateProductArgs({
productImpl: address(productImplementation),
productImpl: address(productImpl),
name: "Test Product",
symbol: "TP",
baseTokenURI: "https://example.com/token/"
Expand All @@ -47,7 +70,7 @@ contract ProductFactoryTest is Test {

IProductFactory.CreateProductArgs memory args = IProductFactory
.CreateProductArgs({
productImpl: address(productImplementation),
productImpl: address(productImpl),
name: "Test Product",
symbol: "TP",
baseTokenURI: "https://example.com/token/"
Expand Down Expand Up @@ -82,7 +105,7 @@ contract ProductFactoryTest is Test {

IProductFactory.CreateProductArgs memory args = IProductFactory
.CreateProductArgs({
productImpl: address(productImplementation),
productImpl: address(productImpl),
name: "Test Product",
symbol: "TP",
baseTokenURI: "https://example.com/token/"
Expand Down Expand Up @@ -124,7 +147,7 @@ contract ProductFactoryTest is Test {

IProductFactory.CreateProductArgs memory args = IProductFactory
.CreateProductArgs({
productImpl: address(productImplementation),
productImpl: address(productImpl),
name: "Test Product",
symbol: "TP",
baseTokenURI: "https://example.com/token/"
Expand Down
14 changes: 14 additions & 0 deletions test/mock/ProductFactoryV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.24;

import {ProductFactory} from "../../contracts/ProductFactory.sol";

contract ProductFactoryV2 is ProductFactory {
function initialize(address initialOwner) public override reinitializer(2) {
__Ownable_init(initialOwner);
__EIP712_init("ProductFactory", "2");
__ReentrancyGuard_init();
__Pausable_init();
__UUPSUpgradeable_init();
}
}
56 changes: 0 additions & 56 deletions tool/demo/src/App.css

This file was deleted.

Loading

0 comments on commit 0a3b0a0

Please sign in to comment.