Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom factory #2

Merged
merged 11 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "packages/hardhat/lib/tokenbound"]
path = packages/hardhat/lib/tokenbound
url = https://github.com/tokenbound/contracts.git
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged --verbose
#yarn lint-staged --verbose
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,9 @@
},
"resolutions": {
"usehooks-ts@^2.7.2": "patch:usehooks-ts@npm:^2.7.2#./.yarn/patches/usehooks-ts-npm-2.7.2-fceffe0e43.patch"
},
"dependencies": {
"@openzeppelin/contracts": "^4.9.2",
"@openzeppelin/contracts-upgradeable": "^4.9.2"
}
}
5 changes: 0 additions & 5 deletions packages/hardhat/.env.example

This file was deleted.

75 changes: 75 additions & 0 deletions packages/hardhat/contracts/FinanceNFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";

interface IRegistry {
function createAccount(address implementation, uint256 chainId, address tokenContract, uint256 tokenId, uint256 salt, bytes calldata initData) external returns (address);
}

contract FinanceNFT is Initializable, ERC721Upgradeable, ERC721URIStorageUpgradeable, AccessControlUpgradeable {
using CountersUpgradeable for CountersUpgradeable.Counter;

bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
CountersUpgradeable.Counter public _tokenIdCounter;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function initialize(string calldata _name, string calldata _symbol, address _owner, string memory uri, address registry, address implementation) initializer public {
__ERC721_init(_name, _symbol);
__ERC721URIStorage_init();
__AccessControl_init();
_grantRole(DEFAULT_ADMIN_ROLE, _owner);
_grantRole(MINTER_ROLE, _owner);
_safeMint(_owner, 0);
_setTokenURI(0, uri);
_tokenIdCounter.increment();
createAccount(registry, implementation, 0);
}

function mint(address to, string memory uri) public onlyRole(MINTER_ROLE) {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}

function createAccount(address registry, address implementation, uint256 tokenId) public returns(address tba) {
tba = IRegistry(registry).createAccount(implementation, block.chainid, address(this), tokenId, 0, abi.encodeWithSignature("initialize()"));
}

// The following functions are overrides required by Solidity.

function _burn(uint256 tokenId)
internal
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
{
super._burn(tokenId);
}

function tokenURI(uint256 tokenId)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return super.tokenURI(tokenId);
}

function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721Upgradeable, AccessControlUpgradeable, ERC721URIStorageUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}

}
43 changes: 43 additions & 0 deletions packages/hardhat/contracts/FinanceNFTFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";

interface IFinanceNFT {
function initialize(string calldata _name, string calldata _symbol, address _owner, string memory uri, address registry, address implementation) external;
}

contract FinanceNFTFactory is Initializable {
address public nftImplementation;
mapping(address => address) public ownerToContract;

constructor() {
//_disableInitializers();
}

function initialize(address _nftImplementation) initializer public {
nftImplementation = _nftImplementation;
}

event FinanceNFTCreated(
address indexed owner,
address nftContract
);

// @dev deploys a FinanceNFT contract
function createFinanceNFT(string calldata _name, string calldata _symbol, address owner, string memory uri, address registry, address implementation) external returns (address) {
bytes32 salt = keccak256(abi.encode(_name, _symbol, owner));
address clone = Clones.cloneDeterministic(nftImplementation, salt);
IFinanceNFT(clone).initialize(_name, _symbol, owner, uri, registry, implementation);
emit FinanceNFTCreated(msg.sender, clone);
ownerToContract[msg.sender] = clone;
return clone;
}

// @dev returns deployed nft contract address a specified user address
function getContractForUser(address user) public view returns (address) {
return ownerToContract[user];
}

}
78 changes: 0 additions & 78 deletions packages/hardhat/contracts/YourContract.sol

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DeployFunction } from "hardhat-deploy/types";
*
* @param hre HardhatRuntimeEnvironment object.
*/
const deployYourContract: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const deployFinanceNFT: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
/*
On localhost, the deployer account is the one that comes with Hardhat, which is already funded.

Expand All @@ -21,10 +21,10 @@ const deployYourContract: DeployFunction = async function (hre: HardhatRuntimeEn
const { deployer } = await hre.getNamedAccounts();
const { deploy } = hre.deployments;

await deploy("YourContract", {
await deploy("FinanceNFT", {
from: deployer,
// Contract constructor arguments
args: [deployer],
args: [],
log: true,
// autoMine: can be passed to the deploy function to make the deployment process faster on local networks by
// automatically mining the contract deployment transaction. There is no effect on live networks.
Expand All @@ -35,8 +35,8 @@ const deployYourContract: DeployFunction = async function (hre: HardhatRuntimeEn
// const yourContract = await hre.ethers.getContract("YourContract", deployer);
};

export default deployYourContract;
export default deployFinanceNFT;

// Tags are useful if you have multiple deploy files and only want to run one of them.
// e.g. yarn deploy --tags YourContract
deployYourContract.tags = ["YourContract"];
deployFinanceNFT.tags = ["FinanceNFT"];
42 changes: 42 additions & 0 deletions packages/hardhat/deploy/01_deploy_financenftfactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";

/**
* Deploys a contract named "YourContract" using the deployer account and
* constructor arguments set to the deployer address
*
* @param hre HardhatRuntimeEnvironment object.
*/
const deployFinanceNFTFactory: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
/*
On localhost, the deployer account is the one that comes with Hardhat, which is already funded.

When deploying to live networks (e.g `yarn deploy --network goerli`), the deployer account
should have sufficient balance to pay for the gas fees for contract creation.

You can generate a random account with `yarn generate` which will fill DEPLOYER_PRIVATE_KEY
with a random private key in the .env file (then used on hardhat.config.ts)
You can run the `yarn account` command to check your balance in every network.
*/
const { deployer } = await hre.getNamedAccounts();
const { deploy } = hre.deployments;

await deploy("FinanceNFTFactory", {
from: deployer,
// Contract constructor arguments
args: [],
log: true,
// autoMine: can be passed to the deploy function to make the deployment process faster on local networks by
// automatically mining the contract deployment transaction. There is no effect on live networks.
autoMine: true,
});

// Get the deployed contract
// const yourContract = await hre.ethers.getContract("YourContract", deployer);
};

export default deployFinanceNFTFactory;

// Tags are useful if you have multiple deploy files and only want to run one of them.
// e.g. yarn deploy --tags YourContract
deployFinanceNFTFactory.tags = ["FinanceNFTFactory"];
9 changes: 7 additions & 2 deletions packages/hardhat/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const providerApiKey = process.env.ALCHEMY_API_KEY || "oKxs-03sij-U_N0iOlrSsZFr2
// If not set, it uses the hardhat account 0 private key.
const deployerPrivateKey =
process.env.DEPLOYER_PRIVATE_KEY ?? "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";

const recoveryPrivateKey =
process.env.RECOVERY_PRIV ?? "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
// If not set, it uses ours Etherscan default API key.
const etherscanApiKey = process.env.ETHERSCAN_API_KEY || "DNXJA8RX2Q3VZ4URQIWP7Z68CJXQZSC6AW";

Expand All @@ -26,7 +29,7 @@ const config: HardhatUserConfig = {
},
},
},
defaultNetwork: "localhost",
defaultNetwork: "goerli",
namedAccounts: {
deployer: {
// By default, it will take the first Hardhat account as the deployer
Expand All @@ -52,7 +55,9 @@ const config: HardhatUserConfig = {
},
goerli: {
url: `https://eth-goerli.alchemyapi.io/v2/${providerApiKey}`,
accounts: [deployerPrivateKey],
accounts: [deployerPrivateKey, recoveryPrivateKey],
gasMultiplier: 100,
gasPrice: 1000000000 * 30
},
arbitrum: {
url: `https://arb-mainnet.g.alchemy.com/v2/${providerApiKey}`,
Expand Down
1 change: 1 addition & 0 deletions packages/hardhat/lib/tokenbound
Submodule tokenbound added at 96ef95
3 changes: 2 additions & 1 deletion packages/hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"generate": "hardhat run scripts/generateAccount.ts",
"lint": "eslint --config ./.eslintrc.json --ignore-path ./.eslintignore ./*.ts ./deploy/**/*.ts ./scripts/**/*.ts ./test/**/*.ts",
"lint-staged": "eslint --config ./.eslintrc.json --ignore-path ./.eslintignore",
"test": "REPORT_GAS=true hardhat test --network hardhat",
"test": "REPORT_GAS=true hardhat test --network goerli",
"verify": "hardhat etherscan-verify"
},
"devDependencies": {
Expand Down Expand Up @@ -47,6 +47,7 @@
},
"dependencies": {
"@openzeppelin/contracts": "^4.8.1",
"@tokenbound/sdk": "^0.3.0",
"dotenv": "^16.0.3",
"envfile": "^6.18.0",
"qrcode": "^1.5.1"
Expand Down
Loading
Loading