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

Use proxy factory for NFTs #3

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
50 changes: 25 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12
node-version: 14
- uses: actions/cache@master
id: yarn-cache
with:
Expand All @@ -30,7 +30,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12
node-version: 14
- uses: actions/cache@master
id: yarn-cache
with:
Expand Down Expand Up @@ -66,7 +66,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12
node-version: 14
- uses: actions/cache@master
id: yarn-cache
with:
Expand All @@ -76,27 +76,27 @@ jobs:
key: ${{ runner.os }}-lerna-${{ hashFiles('**/package.json', '**/yarn.lock') }}
- run: yarn test

# coverage:
# name: Coverage
# runs-on: ubuntu-latest
# needs: [install]
# steps:
# - uses: actions/checkout@v1
# - uses: actions/setup-node@v1
# with:
# node-version: 12
# - uses: actions/cache@master
# id: yarn-cache
# with:
# path: |
# node_modules
# */*/node_modules
# key: ${{ runner.os }}-lerna-${{ hashFiles('**/package.json', '**/yarn.lock') }}
# - run: yarn coverage || true
# - name: Coveralls
# uses: coverallsapp/github-action@master
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
coverage:
name: Coverage
runs-on: ubuntu-latest
needs: [install]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 14
- uses: actions/cache@master
id: yarn-cache
with:
path: |
node_modules
*/*/node_modules
key: ${{ runner.os }}-lerna-${{ hashFiles('**/package.json', '**/yarn.lock') }}
- run: yarn coverage
- uses: actions/upload-artifact@v2
with:
name: test-coverage
path: coverage

build:
name: Is latest build commited?
Expand All @@ -106,7 +106,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12
node-version: 14
- uses: actions/cache@master
id: yarn-cache
with:
Expand Down
1 change: 1 addition & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import '@nomiclabs/hardhat-ethers'

import 'hardhat-gas-reporter'
import '@nomiclabs/hardhat-etherscan'
import "solidity-coverage"

const chainIds = {
hardhat: 31337,
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"adapter:gen": "rimraf src/gen/typechain && typechain --target ethers-v5 --out-dir src/gen/typechain \"./src/artifacts/contracts/**/*[^dbg].json\"",
"adapter:build": "rimraf src/gen/adapter && tsc -p ./src/tsconfig.json",
"test": "yarn hardhat test",
"coverage": "hardhat coverage",
"release": "yarn publish src --access public",
"release-list": "cd src && rm -f ./*niftyup-contracts-v*.tgz && yarn pack && tar --list -zf *niftyup-contracts-v*.tgz",
"lint:ts": "eslint -c .eslintrc.js './**/*.ts'",
Expand Down Expand Up @@ -42,6 +43,7 @@
"prettier-plugin-solidity": "^1.0.0-beta.18",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.17",
"ts-generator": "^0.1.1",
"ts-node": "^10.2.1",
"typechain": "^5.1.2",
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/artifacts/@openzeppelin/contracts/proxy/Clones.sol/Clones.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Clones",
"sourceName": "@openzeppelin/contracts/proxy/Clones.sol",
"abi": [],
"bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220844b8a2921660edc3cd3c4751c12436811a7acb432eaf78b6b14d1550f6c756a64736f6c63430007040033",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220844b8a2921660edc3cd3c4751c12436811a7acb432eaf78b6b14d1550f6c756a64736f6c63430007040033",
"linkReferences": {},
"deployedLinkReferences": {}
}
98 changes: 98 additions & 0 deletions src/artifacts/contracts/NiftyupFactory.sol/NiftyupFactory.json

Large diffs are not rendered by default.

45 changes: 41 additions & 4 deletions src/artifacts/contracts/NiftyupNFT.sol/NiftyupNFT.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Context",
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
"contractName": "Initializable",
"sourceName": "contracts/utils/Initializable.sol",
"abi": [],
"bytecode": "0x",
"deployedBytecode": "0x",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Ownable",
"sourceName": "@openzeppelin/contracts/access/Ownable.sol",
"sourceName": "contracts/utils/Ownable.sol",
"abi": [
{
"anonymous": false,
Expand Down
44 changes: 44 additions & 0 deletions src/contracts/NiftyupFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;

import '@openzeppelin/contracts/proxy/Clones.sol';
import "./NiftyupNFT.sol";


contract NiftyupFactory {
mapping(uint256 => NiftyupNFT) public implementations;

event CreatedNFTContract(address indexed creator, address indexed owner, address indexed nft);
event CreatedImplementationContract(uint256 indexed bits, address indexed implementation);

/**
* @notice Creates a new NiftyNFT proxy contract instance
* @param _owner Owner of the NFT contract
* @param _bits Number of bits used to store balances
* @return Address of the created NFT contract
*/
function create(address _owner, uint256 _bits) external returns (address) {
NiftyupNFT clone = NiftyupNFT(Clones.clone(implementationFor(_bits)));
clone.initialize(_owner);

emit CreatedNFTContract(msg.sender, _owner, address(clone));

return address(clone);
}

function implementationFor(uint256 _bits) internal returns (address) {
require(_bits != 0 && _bits < 256 && 256 % _bits == 0, "NiftyupFactory#implementationFor: INVALID_BITS");

address existing = address(implementations[_bits]);
if (existing != address(0)) {
return existing;
}

NiftyupNFT imp = new NiftyupNFT(_bits);
emit CreatedImplementationContract(_bits, address(imp));

imp.initialize(address(this));
implementations[_bits] = imp;
return address(imp);
}
}
22 changes: 19 additions & 3 deletions src/contracts/NiftyupNFT.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
pragma solidity ^0.7.0;

import '@0xsequence/erc-1155/contracts/tokens/ERC1155PackedBalance/ERC1155MintBurnPackedBalance.sol';
import '@0xsequence/erc-1155/contracts/tokens/ERC1155/ERC1155Metadata.sol';
import '@openzeppelin/contracts/access/Ownable.sol';

contract NiftyupNFT is ERC1155MintBurnPackedBalance, ERC1155Metadata, Ownable {
import './utils/Initializable.sol';
import './utils/Ownable.sol';


contract NiftyupNFT is Initializable, Ownable, ERC1155MintBurnPackedBalance, ERC1155Metadata {
constructor (uint256 _bits) ERC1155MintBurnPackedBalance(_bits) {}

/**
* @notice Constructor for proxy instances, initializes the contract with given values
* @dev This method can only be called once
* @param _owner Owner of the NFT contract
*/
function initialize(
address _owner
) external initializer {
_transferOwnership(_owner);
}

/**
* @notice Mint _amount of tokens of a given id, if allowed.
* @param _to The address to mint tokens to
Expand Down
35 changes: 35 additions & 0 deletions src/contracts/utils/Initializable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.24 <0.8.0;


/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/8e0296096449d9b1cd7c5631e917330635244c37/contracts/proxy/Initializable.sol
*
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;

/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(!_initialized, "Initializable: contract is already initialized");
_initialized = true;

_;
}
}
76 changes: 76 additions & 0 deletions src/contracts/utils/Ownable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;


/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*
* Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/e6f26b46fc8015f1b9b09bb85297464069302125/contracts/access/Ownable.sol
*
*/
abstract contract Ownable {
address private _owner;

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(msg.sender);
}

/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}

/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}

/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}

/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}

/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Loading