Skip to content

Commit 1efd7f5

Browse files
committed
Added ERC 1151
1 parent 25fa6e4 commit 1efd7f5

File tree

4 files changed

+307
-4
lines changed

4 files changed

+307
-4
lines changed
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
4+
// Define an interface for ERC1151 options
5+
export interface ERC1151Options {
6+
name: string; // Name of the token
7+
symbol: string; // Symbol of the token
8+
baseUri?: string; // Base URI for token metadata
9+
burnable?: boolean; // Flag indicating if the token is burnable
10+
pausable?: boolean; // Flag indicating if the token is pausable
11+
mintable?: boolean; // Flag indicating if new tokens can be minted
12+
nftOwners?: Record<string, string>; // Mapping of token IDs to owner addresses
13+
ownerToNFTCount?: Record<string, number>; // Mapping of owner addresses to token count
14+
nftApprovals?: Record<string, string>; // Mapping of token IDs to approved addresses
15+
nftBalances?: Record<string, number>; // Mapping of token IDs to token balances
16+
nftData?: Record<string, string>; // Mapping of token IDs to token data
17+
operatorApprovals?: Record<string, Record<string, boolean>>; // Mapping of owner addresses to operator approvals
18+
}
19+
20+
// Function to print the ERC1151 contract code with the provided options
21+
export function printERC1151(opts: ERC1151Options): string {
22+
const solFilePath = path.join(__dirname, '..', 'solFiles', 'ERC1151.sol');
23+
let contractCode = fs.readFileSync(solFilePath, 'utf-8');
24+
25+
contractCode = contractCode.replace('${name}', opts.name);
26+
contractCode = contractCode.replace('${symbol}', opts.symbol);
27+
28+
if (opts.baseUri !== undefined) {
29+
contractCode = contractCode.replace('${baseUri}', opts.baseUri);
30+
}
31+
32+
if (opts.burnable !== undefined) {
33+
contractCode = contractCode.replace('${burnable}', opts.burnable.toString());
34+
}
35+
36+
if (opts.pausable !== undefined) {
37+
contractCode = contractCode.replace('${pausable}', opts.pausable.toString());
38+
}
39+
40+
if (opts.mintable !== undefined) {
41+
contractCode = contractCode.replace('${mintable}', opts.mintable.toString());
42+
}
43+
44+
return contractCode;
45+
}
46+
47+
// Define the default values for ERC1151 options
48+
export const defaults: Required<ERC1151Options> = {
49+
name: 'MyERC1151',
50+
symbol: 'ERC1151',
51+
baseUri: '',
52+
burnable: false,
53+
pausable: false,
54+
mintable: false,
55+
nftOwners: {},
56+
ownerToNFTCount: {},
57+
nftApprovals: {},
58+
nftBalances: {},
59+
nftData: {},
60+
operatorApprovals: {},
61+
};
62+
63+
// Function to check if access control is required based on the provided options
64+
export function isAccessControlRequired(opts: Partial<ERC1151Options>): boolean {
65+
// Check if any of the options require access control
66+
if (opts.burnable === true || opts.pausable === true || opts.mintable === true) {
67+
return true;
68+
}
69+
70+
// If none of the options require access control, return false
71+
return false;
72+
}
73+
74+
export const erc1151 = {
75+
print: printERC1151,
76+
defaults,
77+
isAccessControlRequired,
78+
};

src/chains/Ethereum/contracts/EthereumContract.ts

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import fs from "fs";
22
import { erc721, erc1155 } from "@openzeppelin/wizard";
3+
import { erc1151 } from "./ERC1151";
34
import path from "path";
45
import { ethers } from "ethers";
56
// eslint-disable-next-line @typescript-eslint/no-var-requires
67
const solc = require("solc");
78

8-
type ercStandards = "ERC721" | "ERC1155";
9+
type ercStandards = "ERC721" | "ERC1151"| "ERC1155";
910
type networks =
1011
| "homestead"
1112
| "ropsten"
@@ -29,6 +30,20 @@ interface ERC721Options {
2930
votes?: boolean;
3031
}
3132
33+
interface ERC1151Options {
34+
baseUri: string;
35+
burnable?: boolean;
36+
pausable?: boolean;
37+
mintable?: boolean;
38+
nftOwners: Record<string, string>;
39+
ownerToNFTCount: Record<string, number>;
40+
nftApprovals: Record<string, string>;
41+
nftBalances: Record<string, number>;
42+
nftData: Record<string, string>;
43+
operatorApprovals: Record<string, Record<string, boolean>>;
44+
}
45+
46+
3247
interface ERC1155Options {
3348
name: string;
3449
uri: string;
@@ -50,6 +65,13 @@ export interface DraftOptions {
5065
uriStorage?: boolean;
5166
incremental?: boolean;
5267
votes?: boolean;
68+
// ERC1151 options
69+
nftOwners?: Record<string, string>;
70+
ownerToNFTCount?: Record<string, number>;
71+
nftApprovals?: Record<string, string>;
72+
nftBalances?: Record<string, number>;
73+
nftData?: Record<string, string>;
74+
operatorApprovals?: Record<string, Record<string, boolean>>;
5375
// ERC1155 options
5476
supply?: boolean;
5577
updatableUri?: boolean;
@@ -184,6 +206,13 @@ export class Contract {
184206
...options,
185207
});
186208
break;
209+
case "ERC1151":
210+
contractCode = erc1151.print({
211+
name: this.name,
212+
symbol: this.symbol,
213+
...options,
214+
});
215+
break;
187216
case "ERC1155":
188217
contractCode = erc1155.print({
189218
name: this.name,
@@ -212,7 +241,6 @@ export class Contract {
212241
return { error: "OPEN ZEPPELIN IMPORT FAILED" };
213242
}
214243
}
215-
216244
const compilerInput = {
217245
language: "Solidity",
218246
sources: {

src/chains/Ethereum/functions/draftEthereum.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ nftToolbox.initEthereumContract({
66
name: "DemoContract",
77
symbol: "DEMO",
88
dir: path.join(__dirname, "Contracts"),
9-
standard: "ERC721",
9+
standard: "ERC1151",
1010
connection: JSON.parse(
11-
readFileSync(path.join(__dirname, "connection.json")).toString()
11+
readFileSync(path.join(__dirname, "..","..","..","connection.json")).toString()
1212
),
1313
});
1414

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.18;
3+
4+
import "@openzeppelin/contracts/utils/Address.sol";
5+
import "@openzeppelin/contracts/utils/Context.sol";
6+
import "@openzeppelin/contracts/utils/Strings.sol";
7+
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
8+
9+
interface IERC1151Receiver {
10+
function onERC1151Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
11+
}
12+
13+
contract MyERC1151 is Context, ERC165 {
14+
using Address for address;
15+
using Strings for uint256;
16+
17+
string private _name;
18+
string private _symbol;
19+
string private _baseUri;
20+
21+
mapping(uint256 => address) private _nftOwners;
22+
mapping(address => uint256) private _ownerToNFTCount;
23+
mapping(uint256 => address) private _nftApprovals;
24+
mapping(uint256 => uint256) private _nftBalances;
25+
mapping(uint256 => string) private _nftData;
26+
mapping(address => mapping(address => bool)) private _operatorApprovals;
27+
28+
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
29+
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
30+
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
31+
32+
constructor(
33+
string memory name_,
34+
string memory symbol_,
35+
string memory baseUri_
36+
) {
37+
_name = name_;
38+
_symbol = symbol_;
39+
_baseUri = baseUri_;
40+
}
41+
42+
function balanceOf(address owner) public view virtual returns (uint256) {
43+
require(owner != address(0), "ERC1151: balance query for the zero address");
44+
return _ownerToNFTCount[owner];
45+
}
46+
47+
function ownerOf(uint256 tokenId) public view virtual returns (address) {
48+
address owner = _nftOwners[tokenId];
49+
require(owner != address(0), "ERC1151: owner query for nonexistent token");
50+
return owner;
51+
}
52+
53+
function name() public view virtual returns (string memory) {
54+
return _name;
55+
}
56+
57+
function symbol() public view virtual returns (string memory) {
58+
return _symbol;
59+
}
60+
61+
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
62+
require(_exists(tokenId), "ERC1151: URI query for nonexistent token");
63+
string memory baseURI = _baseURI();
64+
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
65+
}
66+
67+
function _baseURI() internal view virtual returns (string memory) {
68+
return _baseUri;
69+
}
70+
71+
function approve(address to, uint256 tokenId) public virtual {
72+
address owner = ownerOf(tokenId);
73+
require(to != owner, "ERC1151: approval to current owner");
74+
require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC1151: approve caller is not owner nor approved for all");
75+
_approve(to, tokenId);
76+
}
77+
78+
function getApproved(uint256 tokenId) public view virtual returns (address) {
79+
require(_exists(tokenId), "ERC1151: approved query for nonexistent token");
80+
return _nftApprovals[tokenId];
81+
}
82+
83+
function setApprovalForAll(address operator, bool approved) public virtual {
84+
require(operator != _msgSender(), "ERC1151: approve to caller");
85+
_operatorApprovals[_msgSender()][operator] = approved;
86+
emit ApprovalForAll(_msgSender(), operator, approved);
87+
}
88+
89+
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
90+
return _operatorApprovals[owner][operator];
91+
}
92+
93+
function transferFrom(address from, address to, uint256 tokenId) public virtual {
94+
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC1151: transfer caller is not owner nor approved");
95+
_transfer(from, to, tokenId);
96+
}
97+
98+
function safeTransferFrom(address from, address to, uint256 tokenId) public virtual {
99+
safeTransferFrom(from, to, tokenId, "");
100+
}
101+
102+
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual {
103+
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC1151: transfer caller is not owner nor approved");
104+
_safeTransfer(from, to, tokenId, _data);
105+
}
106+
107+
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
108+
_transfer(from, to, tokenId);
109+
require(_checkOnERC1151Received(from, to, tokenId, _data), "ERC1151: transfer to non-ERC1151Receiver implementer");
110+
}
111+
112+
function _exists(uint256 tokenId) internal view virtual returns (bool) {
113+
return _nftOwners[tokenId] != address(0);
114+
}
115+
116+
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
117+
require(_exists(tokenId), "ERC1151: operator query for nonexistent token");
118+
address owner = ownerOf(tokenId);
119+
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
120+
}
121+
122+
function _safeMint(address to, uint256 tokenId) internal virtual {
123+
_safeMint(to, tokenId, "");
124+
}
125+
126+
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
127+
_mint(to, tokenId);
128+
require(_checkOnERC1151Received(address(0), to, tokenId, _data), "ERC1151: transfer to non-ERC1151Receiver implementer");
129+
}
130+
131+
function _mint(address to, uint256 tokenId) internal virtual {
132+
require(to != address(0), "ERC1151: mint to the zero address");
133+
require(!_exists(tokenId), "ERC1151: token already minted");
134+
135+
_beforeTokenTransfer(address(0), to, tokenId);
136+
137+
_nftOwners[tokenId] = to;
138+
_ownerToNFTCount[to] += 1;
139+
140+
emit Transfer(address(0), to, tokenId);
141+
}
142+
143+
function _burn(uint256 tokenId) internal virtual {
144+
address owner = ownerOf(tokenId);
145+
146+
_beforeTokenTransfer(owner, address(0), tokenId);
147+
148+
// Clear approvals
149+
_approve(address(0), tokenId);
150+
151+
_ownerToNFTCount[owner] -= 1;
152+
delete _nftOwners[tokenId];
153+
154+
emit Transfer(owner, address(0), tokenId);
155+
}
156+
157+
function _transfer(address from, address to, uint256 tokenId) internal virtual {
158+
require(ownerOf(tokenId) == from, "ERC1151: transfer of token that is not own");
159+
require(to != address(0), "ERC1151: transfer to the zero address");
160+
161+
_beforeTokenTransfer(from, to, tokenId);
162+
163+
// Clear approvals from the previous owner
164+
_approve(address(0), tokenId);
165+
166+
_ownerToNFTCount[from] -= 1;
167+
_ownerToNFTCount[to] += 1;
168+
_nftOwners[tokenId] = to;
169+
170+
emit Transfer(from, to, tokenId);
171+
}
172+
173+
function _approve(address to, uint256 tokenId) internal virtual {
174+
_nftApprovals[tokenId] = to;
175+
emit Approval(ownerOf(tokenId), to, tokenId);
176+
}
177+
178+
function _checkOnERC1151Received(address from, address to, uint256 tokenId, bytes memory _data) private returns (bool) {
179+
if (to.code.length > 0) {
180+
try IERC1151Receiver(to).onERC1151Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
181+
return retval == IERC1151Receiver.onERC1151Received.selector;
182+
} catch (bytes memory reason) {
183+
if (reason.length == 0) {
184+
revert("ERC1151: transfer to non-ERC1151Receiver implementer");
185+
} else {
186+
assembly {
187+
revert(add(32, reason), mload(reason))
188+
}
189+
}
190+
}
191+
} else {
192+
return true;
193+
}
194+
}
195+
196+
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual {}
197+
}

0 commit comments

Comments
 (0)