neozipkit 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +400 -0
- package/contracts/Lock.sol +34 -0
- package/contracts/bytecode.txt +1 -0
- package/contracts/compile-contract.js +168 -0
- package/contracts/deploy/deploy-both-contracts.js +286 -0
- package/contracts/deploy/deploy-enhanced-contract.js +197 -0
- package/contracts/deploy/deploy-private-contract.js +190 -0
- package/contracts/deploy/deploy-public-clean.js +1063 -0
- package/contracts/deploy/deploy-public-contract.js +1107 -0
- package/contracts/deployment.config.example.js +25 -0
- package/contracts/remix-compile.js +222 -0
- package/contracts/setup-deployment.js +51 -0
- package/contracts/src/NZIP-NFT-Private.sol +350 -0
- package/contracts/src/NZIP-NFT.sol +265 -0
- package/contracts/src/ZipFileNFT-DEPRECATED-6field.sol +260 -0
- package/contracts/src/ZipFileNFT-DEPRECATED-Enhanced.sol +289 -0
- package/dist/browser/CertificateGeneratorBrowser.d.ts +75 -0
- package/dist/browser/CertificateGeneratorBrowser.js +433 -0
- package/dist/browser/TokenVerifierBrowser.d.ts +76 -0
- package/dist/browser/TokenVerifierBrowser.js +299 -0
- package/dist/browser/ZipKitBrowser.d.ts +18 -0
- package/dist/browser/ZipKitBrowser.js +250 -0
- package/dist/browser/ZipKitStampBrowser.d.ts +2 -0
- package/dist/browser/ZipKitStampBrowser.js +12 -0
- package/dist/browser-index.d.ts +21 -0
- package/dist/browser-index.js +58 -0
- package/dist/browser.d.ts +21 -0
- package/dist/browser.js +58 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +76 -0
- package/dist/server/blockchain/CertificateToken.d.ts +48 -0
- package/dist/server/blockchain/CertificateToken.js +386 -0
- package/dist/server/blockchain/NFTMinter.d.ts +41 -0
- package/dist/server/blockchain/NFTMinter.js +323 -0
- package/dist/server/blockchain/TokenQuerier.d.ts +31 -0
- package/dist/server/blockchain/TokenQuerier.js +259 -0
- package/dist/server/blockchain/TokenVerifier.d.ts +20 -0
- package/dist/server/blockchain/TokenVerifier.js +395 -0
- package/dist/server/blockchain/WalletAnalyzer.d.ts +81 -0
- package/dist/server/blockchain/WalletAnalyzer.js +356 -0
- package/dist/server/blockchain/WalletFormatter.d.ts +39 -0
- package/dist/server/blockchain/WalletFormatter.js +196 -0
- package/dist/server/blockchain/WalletManager.d.ts +46 -0
- package/dist/server/blockchain/WalletManager.js +294 -0
- package/dist/server/blockchain/ZipMetadata.d.ts +27 -0
- package/dist/server/blockchain/ZipMetadata.js +131 -0
- package/dist/server/blockchain/ZipTokenProcessor.d.ts +44 -0
- package/dist/server/blockchain/ZipTokenProcessor.js +204 -0
- package/dist/server/blockchain/constants.d.ts +102 -0
- package/dist/server/blockchain/constants.js +968 -0
- package/dist/server/blockchain/index.d.ts +9 -0
- package/dist/server/blockchain/index.js +44 -0
- package/dist/server/blockchain/test-certificate.d.ts +8 -0
- package/dist/server/blockchain/test-certificate.js +100 -0
- package/dist/server/blockchain/types.d.ts +69 -0
- package/dist/server/blockchain/types.js +51 -0
- package/dist/server/platform/server/ZipKitServer.d.ts +105 -0
- package/dist/server/platform/server/ZipKitServer.js +437 -0
- package/dist/server/platform/servercomponents/ZipKitOTS.d.ts +91 -0
- package/dist/server/platform/servercomponents/ZipKitOTS.js +271 -0
- package/dist/shared/ZipEntry.d.ts +131 -0
- package/dist/shared/ZipEntry.js +686 -0
- package/dist/shared/ZipKit.d.ts +249 -0
- package/dist/shared/ZipKit.js +789 -0
- package/dist/shared/components/CertificateOTS.d.ts +15 -0
- package/dist/shared/components/CertificateOTS.js +116 -0
- package/dist/shared/components/FileSys.d.ts +2 -0
- package/dist/shared/components/FileSys.js +113 -0
- package/dist/shared/components/HashAccumulator.d.ts +55 -0
- package/dist/shared/components/HashAccumulator.js +100 -0
- package/dist/shared/components/Support.d.ts +63 -0
- package/dist/shared/components/Support.js +70 -0
- package/dist/shared/components/Util.d.ts +21 -0
- package/dist/shared/components/Util.js +115 -0
- package/dist/shared/components/ZipCrypto.d.ts +3 -0
- package/dist/shared/components/ZipCrypto.js +78 -0
- package/dist/shared/components/merkleTree.d.ts +66 -0
- package/dist/shared/components/merkleTree.js +136 -0
- package/dist/shared/constants/Errors.d.ts +53 -0
- package/dist/shared/constants/Errors.js +69 -0
- package/dist/shared/constants/Headers.d.ts +167 -0
- package/dist/shared/constants/Headers.js +191 -0
- package/dist/shared/types/index.d.ts +21 -0
- package/dist/shared/types/index.js +3 -0
- package/dist/shared/types.d.ts +33 -0
- package/dist/shared/types.js +8 -0
- package/dist/shared/version.d.ts +4 -0
- package/dist/shared/version.js +7 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.js +3 -0
- package/examples/unzip-token.ts +488 -0
- package/examples/zip-token.ts +604 -0
- package/package.json +117 -0
- package/src/browser/CertificateGeneratorBrowser.ts +498 -0
- package/src/browser/TokenVerifierBrowser.ts +344 -0
- package/src/browser/ZipKitBrowser.ts +242 -0
- package/src/browser/ZipKitStampBrowser.ts +9 -0
- package/src/browser-index.ts +36 -0
- package/src/index.ts +48 -0
- package/src/server/blockchain/CertificateToken.ts +444 -0
- package/src/server/blockchain/NFTMinter.ts +357 -0
- package/src/server/blockchain/TokenQuerier.ts +287 -0
- package/src/server/blockchain/TokenVerifier.ts +453 -0
- package/src/server/blockchain/WalletAnalyzer.ts +397 -0
- package/src/server/blockchain/WalletFormatter.ts +206 -0
- package/src/server/blockchain/WalletManager.ts +294 -0
- package/src/server/blockchain/ZipMetadata.ts +117 -0
- package/src/server/blockchain/ZipTokenProcessor.ts +234 -0
- package/src/server/blockchain/constants.ts +969 -0
- package/src/server/blockchain/index.ts +42 -0
- package/src/server/blockchain/test-certificate.ts +137 -0
- package/src/server/blockchain/types.ts +134 -0
- package/src/server/platform/server/ZipKitServer.ts +459 -0
- package/src/server/platform/servercomponents/ZipKitOTS.ts +313 -0
- package/src/server/platform/servercomponents/opentimestamps.d.ts +23 -0
- package/src/shared/ZipEntry.ts +767 -0
- package/src/shared/ZipKit.ts +899 -0
- package/src/shared/components/CertificateOTS.ts +132 -0
- package/src/shared/components/FileSys.ts +87 -0
- package/src/shared/components/HashAccumulator.ts +113 -0
- package/src/shared/components/Support.ts +77 -0
- package/src/shared/components/Util.ts +113 -0
- package/src/shared/components/ZipCrypto.ts +91 -0
- package/src/shared/components/merkleTree.ts +162 -0
- package/src/shared/constants/Errors.ts +82 -0
- package/src/shared/constants/Headers.ts +203 -0
- package/src/shared/types/index.ts +25 -0
- package/src/shared/types/modules.d.ts +22 -0
- package/src/shared/types/opentimestamps.d.ts +23 -0
- package/src/shared/types.d.ts +8 -0
- package/src/shared/types.ts +43 -0
- package/src/shared/version.ts +4 -0
- package/src/types/index.ts +25 -0
- package/src/types/modules.d.ts +22 -0
- package/src/types/opentimestamps.d.ts +23 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NZIP Contract Deployment Configuration
|
|
3
|
+
*
|
|
4
|
+
* Copy this file to deployment.config.js and update with your values
|
|
5
|
+
* The deployment scripts will automatically load this configuration
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
// Wallet Configuration (Required for deployment)
|
|
10
|
+
// Uncomment and set your private key (without 0x prefix)
|
|
11
|
+
// PRIVATE_KEY: '17e6f5c34c693cf989a579a80c0a50aad090030242b5edcc4dfed565a4804022',
|
|
12
|
+
|
|
13
|
+
// Network Configuration
|
|
14
|
+
CHAIN_ID: 84532, // Base Sepolia (testnet)
|
|
15
|
+
// CHAIN_ID: 8453, // Base Mainnet (production)
|
|
16
|
+
|
|
17
|
+
// Previous contract is now DEPRECATED - do not use:
|
|
18
|
+
// DEPRECATED: 0xb78CB3bcC788fca38c731b1E9D70CF60b04CA015
|
|
19
|
+
// EXISTING_CONTRACT: '0xb78CB3bcC788fca38c731b1E9D70CF60b04CA015', // DEPRECATED
|
|
20
|
+
|
|
21
|
+
// Deployment Notes:
|
|
22
|
+
// 1. Set PRIVATE_KEY to deploy new contracts (required - previous contract deprecated)
|
|
23
|
+
// 2. Make sure you have ETH for gas fees on the target network
|
|
24
|
+
// 3. Previous contract is deprecated - you must deploy a new one
|
|
25
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interactive Remix IDE Compilation Guide
|
|
5
|
+
*
|
|
6
|
+
* This script walks you through compiling NZIP contracts using Remix IDE
|
|
7
|
+
* Usage: node remix-compile.js
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const readline = require('readline');
|
|
13
|
+
|
|
14
|
+
const rl = readline.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
console.log('🌐 NZIP Contract - Remix IDE Compilation Guide');
|
|
20
|
+
console.log('==============================================\n');
|
|
21
|
+
|
|
22
|
+
const contractPath = path.join(__dirname, 'src/NZIP-NFT.sol');
|
|
23
|
+
|
|
24
|
+
function askQuestion(question) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
rl.question(question, (answer) => {
|
|
27
|
+
resolve(answer);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function main() {
|
|
33
|
+
console.log('This guide will walk you through compiling the NZIP NFT contract using Remix IDE.\n');
|
|
34
|
+
|
|
35
|
+
// Step 1: Introduction
|
|
36
|
+
console.log('📋 Step 1: Preparation');
|
|
37
|
+
console.log('======================');
|
|
38
|
+
console.log('✅ Contract: NZIP NFT v2.0 (Public Contract)');
|
|
39
|
+
console.log('✅ Target: Production deployment');
|
|
40
|
+
console.log('✅ Method: Remix IDE (Online)\n');
|
|
41
|
+
|
|
42
|
+
await askQuestion('Press Enter to continue...');
|
|
43
|
+
console.clear();
|
|
44
|
+
|
|
45
|
+
// Step 2: Open Remix
|
|
46
|
+
console.log('🌐 Step 2: Open Remix IDE');
|
|
47
|
+
console.log('=========================');
|
|
48
|
+
console.log('1. Open your web browser');
|
|
49
|
+
console.log('2. Go to: https://remix.ethereum.org');
|
|
50
|
+
console.log('3. Wait for Remix to load completely\n');
|
|
51
|
+
|
|
52
|
+
console.log('💡 Tip: Use Chrome or Firefox for best compatibility\n');
|
|
53
|
+
|
|
54
|
+
const remixOpen = await askQuestion('Have you opened Remix IDE? (y/n): ');
|
|
55
|
+
if (remixOpen.toLowerCase() !== 'y') {
|
|
56
|
+
console.log('Please open Remix IDE first, then run this script again.');
|
|
57
|
+
rl.close();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.clear();
|
|
61
|
+
|
|
62
|
+
// Step 3: Create new file
|
|
63
|
+
console.log('📄 Step 3: Create Contract File');
|
|
64
|
+
console.log('===============================');
|
|
65
|
+
console.log('In Remix IDE:');
|
|
66
|
+
console.log('1. Look for the "File Explorer" tab (📁 icon on the left)');
|
|
67
|
+
console.log('2. Right-click in the file explorer');
|
|
68
|
+
console.log('3. Select "New File"');
|
|
69
|
+
console.log('4. Name it: NZIP-NFT.sol');
|
|
70
|
+
console.log('5. Press Enter to create the file\n');
|
|
71
|
+
|
|
72
|
+
await askQuestion('Have you created the NZIP-NFT.sol file? Press Enter when ready...');
|
|
73
|
+
console.clear();
|
|
74
|
+
|
|
75
|
+
// Step 4: Copy contract source
|
|
76
|
+
console.log('📝 Step 4: Copy Contract Source Code');
|
|
77
|
+
console.log('====================================');
|
|
78
|
+
console.log('I will now display the contract source code.');
|
|
79
|
+
console.log('Copy ALL of it and paste it into your NZIP-NFT.sol file in Remix.\n');
|
|
80
|
+
|
|
81
|
+
await askQuestion('Ready to see the contract source? Press Enter...');
|
|
82
|
+
console.log('\n' + '='.repeat(80));
|
|
83
|
+
console.log('CONTRACT SOURCE CODE - COPY EVERYTHING BELOW:');
|
|
84
|
+
console.log('='.repeat(80) + '\n');
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const contractContent = fs.readFileSync(contractPath, 'utf8');
|
|
88
|
+
console.log(contractContent);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.log('❌ Error reading contract:', err.message);
|
|
91
|
+
rl.close();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log('\n' + '='.repeat(80));
|
|
96
|
+
console.log('END OF CONTRACT SOURCE CODE');
|
|
97
|
+
console.log('='.repeat(80) + '\n');
|
|
98
|
+
|
|
99
|
+
await askQuestion('Have you copied and pasted the contract into Remix? Press Enter when done...');
|
|
100
|
+
console.clear();
|
|
101
|
+
|
|
102
|
+
// Step 5: Install dependencies
|
|
103
|
+
console.log('📦 Step 5: Install OpenZeppelin Dependencies');
|
|
104
|
+
console.log('============================================');
|
|
105
|
+
console.log('In Remix IDE:');
|
|
106
|
+
console.log('1. Click on the "Solidity Compiler" tab (📄 icon on the left)');
|
|
107
|
+
console.log('2. Remix should automatically detect and install OpenZeppelin dependencies');
|
|
108
|
+
console.log('3. Look for "@openzeppelin/contracts" in the file explorer');
|
|
109
|
+
console.log('4. If dependencies don\'t auto-install, Remix will show import errors\n');
|
|
110
|
+
|
|
111
|
+
console.log('💡 If you see import errors:');
|
|
112
|
+
console.log('• Remix will offer to install dependencies automatically');
|
|
113
|
+
console.log('• Click "Install" when prompted\n');
|
|
114
|
+
|
|
115
|
+
await askQuestion('Are the OpenZeppelin dependencies installed? Press Enter when ready...');
|
|
116
|
+
console.clear();
|
|
117
|
+
|
|
118
|
+
// Step 6: Compile
|
|
119
|
+
console.log('⚙️ Step 6: Compile the Contract');
|
|
120
|
+
console.log('=================================');
|
|
121
|
+
console.log('In the Solidity Compiler tab:');
|
|
122
|
+
console.log('1. Set Compiler Version: 0.8.19 or higher');
|
|
123
|
+
console.log('2. Enable "Optimization" (recommended)');
|
|
124
|
+
console.log('3. Click "Compile NZIP-NFT.sol" button');
|
|
125
|
+
console.log('4. Wait for compilation to complete\n');
|
|
126
|
+
|
|
127
|
+
console.log('✅ Success indicators:');
|
|
128
|
+
console.log('• Green checkmark appears');
|
|
129
|
+
console.log('• No error messages');
|
|
130
|
+
console.log('• "ZipFileNFT" contract appears in compiled contracts list\n');
|
|
131
|
+
|
|
132
|
+
const compiled = await askQuestion('Did the contract compile successfully? (y/n): ');
|
|
133
|
+
if (compiled.toLowerCase() !== 'y') {
|
|
134
|
+
console.log('\n❌ Compilation Issues:');
|
|
135
|
+
console.log('• Check for red error messages in Remix');
|
|
136
|
+
console.log('• Ensure Solidity version is 0.8.19+');
|
|
137
|
+
console.log('• Make sure all OpenZeppelin dependencies are installed');
|
|
138
|
+
console.log('• Copy the contract source again if needed\n');
|
|
139
|
+
|
|
140
|
+
await askQuestion('Fix the issues and press Enter to continue...');
|
|
141
|
+
}
|
|
142
|
+
console.clear();
|
|
143
|
+
|
|
144
|
+
// Step 7: Extract compilation artifacts
|
|
145
|
+
console.log('📋 Step 7: Extract Bytecode and ABI');
|
|
146
|
+
console.log('===================================');
|
|
147
|
+
console.log('In Remix IDE:');
|
|
148
|
+
console.log('1. Stay in the "Solidity Compiler" tab');
|
|
149
|
+
console.log('2. Look for "ZipFileNFT" in the compiled contracts section');
|
|
150
|
+
console.log('3. Click on "ZipFileNFT" to expand it');
|
|
151
|
+
console.log('4. You\'ll see several options - we need two:\n');
|
|
152
|
+
|
|
153
|
+
console.log('📄 For BYTECODE:');
|
|
154
|
+
console.log('• Click on "ZipFileNFT" contract name');
|
|
155
|
+
console.log('• Scroll down to find "BYTECODE" section');
|
|
156
|
+
console.log('• Copy the "object" field (starts with 0x...)');
|
|
157
|
+
console.log('• This is your CONTRACT_BYTECODE\n');
|
|
158
|
+
|
|
159
|
+
console.log('📄 For ABI:');
|
|
160
|
+
console.log('• In the same expanded view');
|
|
161
|
+
console.log('• Look for "ABI" section');
|
|
162
|
+
console.log('• Copy the entire ABI array');
|
|
163
|
+
console.log('• This is your CONTRACT_ABI\n');
|
|
164
|
+
|
|
165
|
+
await askQuestion('Have you copied both BYTECODE and ABI? Press Enter when ready...');
|
|
166
|
+
console.clear();
|
|
167
|
+
|
|
168
|
+
// Step 8: Update deployment script
|
|
169
|
+
console.log('🔧 Step 8: Update Deployment Script');
|
|
170
|
+
console.log('===================================');
|
|
171
|
+
console.log('Now you need to update the deployment script with your compiled data:\n');
|
|
172
|
+
|
|
173
|
+
console.log('📁 File to edit: contracts/deploy/deploy-public-contract.js\n');
|
|
174
|
+
|
|
175
|
+
console.log('🔍 Find these lines and replace:');
|
|
176
|
+
console.log('1. Look for: const CONTRACT_BYTECODE = "0x608060..."; // PLACEHOLDER');
|
|
177
|
+
console.log(' Replace with your copied bytecode\n');
|
|
178
|
+
|
|
179
|
+
console.log('2. Look for: const CONTRACT_ABI = [ // PLACEHOLDER ABI');
|
|
180
|
+
console.log(' Replace with your copied ABI array\n');
|
|
181
|
+
|
|
182
|
+
console.log('💡 Tips:');
|
|
183
|
+
console.log('• Bytecode should be one long string starting with 0x');
|
|
184
|
+
console.log('• ABI should be an array of function definitions');
|
|
185
|
+
console.log('• Keep the semicolons and proper formatting\n');
|
|
186
|
+
|
|
187
|
+
await askQuestion('Have you updated the deployment script? Press Enter when ready...');
|
|
188
|
+
console.clear();
|
|
189
|
+
|
|
190
|
+
// Step 9: Deploy
|
|
191
|
+
console.log('🚀 Step 9: Deploy Your Contract');
|
|
192
|
+
console.log('===============================');
|
|
193
|
+
console.log('Now you\'re ready to deploy!\n');
|
|
194
|
+
|
|
195
|
+
console.log('📋 Pre-deployment checklist:');
|
|
196
|
+
console.log('✅ Contract compiled successfully');
|
|
197
|
+
console.log('✅ Bytecode copied to deployment script');
|
|
198
|
+
console.log('✅ ABI copied to deployment script');
|
|
199
|
+
console.log('✅ Wallet has ETH for gas fees\n');
|
|
200
|
+
|
|
201
|
+
console.log('🎯 Deploy commands:');
|
|
202
|
+
console.log('# Setup deployment configuration (if not done)');
|
|
203
|
+
console.log('npm run setup-deployment\n');
|
|
204
|
+
|
|
205
|
+
console.log('# Deploy to Base Sepolia (testnet)');
|
|
206
|
+
console.log('npm run deploy:public\n');
|
|
207
|
+
|
|
208
|
+
console.log('# Deploy to Base Mainnet (production)');
|
|
209
|
+
console.log('CHAIN_ID=8453 npm run deploy:public\n');
|
|
210
|
+
|
|
211
|
+
console.log('🎉 Congratulations!');
|
|
212
|
+
console.log('You\'ve successfully compiled your NZIP NFT contract using Remix IDE.');
|
|
213
|
+
console.log('Your contract is now ready for deployment to the blockchain!\n');
|
|
214
|
+
|
|
215
|
+
console.log('📚 Need help with deployment?');
|
|
216
|
+
console.log('• Run: npm run setup-deployment');
|
|
217
|
+
console.log('• Check: contracts/docs/DEPLOYMENT_GUIDE.md');
|
|
218
|
+
|
|
219
|
+
rl.close();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Deployment Setup Helper for NZIP Contracts
|
|
5
|
+
*
|
|
6
|
+
* This script helps you set up deployment configuration
|
|
7
|
+
* Usage: node setup-deployment.js
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
console.log('🚀 NZIP Contract Deployment Setup');
|
|
14
|
+
console.log('==================================\n');
|
|
15
|
+
|
|
16
|
+
// Check current status
|
|
17
|
+
const configPath = path.join(__dirname, 'deployment.config.js');
|
|
18
|
+
const examplePath = path.join(__dirname, 'deployment.config.example.js');
|
|
19
|
+
|
|
20
|
+
if (fs.existsSync(configPath)) {
|
|
21
|
+
console.log('✅ deployment.config.js already exists');
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const config = require(configPath);
|
|
25
|
+
console.log(`📋 Chain ID: ${config.CHAIN_ID || 'Not set'}`);
|
|
26
|
+
console.log(`📋 Private Key: ${config.PRIVATE_KEY ? '✅ Set' : '❌ Not set'}`);
|
|
27
|
+
console.log(`📋 Existing Contract: ${config.EXISTING_CONTRACT || 'None'}`);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.log('⚠️ Config file exists but has errors:', err.message);
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
console.log('📁 Creating deployment.config.js from template...');
|
|
33
|
+
|
|
34
|
+
if (fs.existsSync(examplePath)) {
|
|
35
|
+
fs.copyFileSync(examplePath, configPath);
|
|
36
|
+
console.log('✅ Created deployment.config.js');
|
|
37
|
+
console.log('📝 Edit this file to add your PRIVATE_KEY');
|
|
38
|
+
} else {
|
|
39
|
+
console.log('❌ deployment.config.example.js not found');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log('\n🎯 Next Steps:');
|
|
44
|
+
console.log('1. Edit deployment.config.js and uncomment PRIVATE_KEY');
|
|
45
|
+
console.log('2. Add your wallet private key (without 0x prefix)');
|
|
46
|
+
console.log('3. Make sure you have ETH for gas fees');
|
|
47
|
+
console.log('4. Run: npm run deploy:public');
|
|
48
|
+
|
|
49
|
+
console.log('\n⚠️ Important Notice:');
|
|
50
|
+
console.log('Previous contract is now DEPRECATED: 0xb78CB3bcC788fca38c731b1E9D70CF60b04CA015');
|
|
51
|
+
console.log('You must deploy a new contract for production use!');
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.19;
|
|
3
|
+
|
|
4
|
+
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
|
5
|
+
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
|
|
6
|
+
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title NZIP NFT Private Contract v2.0
|
|
10
|
+
* @dev Private NFT contract for tokenizing ZIP files with blockchain metadata
|
|
11
|
+
* Features:
|
|
12
|
+
* - Blockchain metadata (block number, timestamps)
|
|
13
|
+
* - Multiple tokens allowed for same content (differentiated by timestamp)
|
|
14
|
+
* - PRIVATE access control - only token owners can verify their tokens
|
|
15
|
+
* - Enhanced events with blockchain context
|
|
16
|
+
* - Selective authorization system for third-party verification
|
|
17
|
+
* - Improved input validation and error handling
|
|
18
|
+
* - Removed unreliable block hash storage
|
|
19
|
+
*
|
|
20
|
+
* Version: 2.0 (New Production Contract - Previous contract deprecated)
|
|
21
|
+
* Network: Base Sepolia (for testing) / Base Mainnet (for production)
|
|
22
|
+
*
|
|
23
|
+
* Privacy Model: Owner-controlled verification with optional authorization
|
|
24
|
+
*/
|
|
25
|
+
contract ZipFileNFTPrivate is ERC721, ERC721URIStorage, Ownable {
|
|
26
|
+
|
|
27
|
+
// Counter for token IDs
|
|
28
|
+
uint256 private _tokenIdCounter;
|
|
29
|
+
|
|
30
|
+
// Struct to store ZIP file information - Latest Enhanced Version
|
|
31
|
+
struct ZipFileInfo {
|
|
32
|
+
// File identification
|
|
33
|
+
string fileName; // Original ZIP file name
|
|
34
|
+
string merkleRootHash; // Merkle root hash of the ZIP contents (PRIVATE)
|
|
35
|
+
string ipfsHash; // IPFS hash where the ZIP file is stored (PRIVATE)
|
|
36
|
+
address creator; // Address that created/minted this token
|
|
37
|
+
|
|
38
|
+
// Timestamps (grouped together)
|
|
39
|
+
uint256 creationTimestamp; // Timestamp when the ZIP was created (user-provided)
|
|
40
|
+
uint256 tokenizationTime; // Timestamp when the NFT was minted (block.timestamp)
|
|
41
|
+
|
|
42
|
+
// Blockchain metadata
|
|
43
|
+
uint256 blockNumber; // Block number when the token was minted
|
|
44
|
+
// Note: Block hash removed - blockhash(block.number) always returns 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// PRIVATE storage mappings - not accessible by public
|
|
48
|
+
mapping(uint256 => ZipFileInfo) private zipFileInfo;
|
|
49
|
+
|
|
50
|
+
// Mapping from composite key (merkleRoot + timestamp) to token ID
|
|
51
|
+
// This prevents duplicate tokens with same content AND same timestamp
|
|
52
|
+
mapping(bytes32 => uint256) private compositeKeyToTokenId;
|
|
53
|
+
|
|
54
|
+
// Authorization system - token owners can authorize specific addresses for verification
|
|
55
|
+
mapping(uint256 => mapping(address => bool)) public authorizedVerifiers;
|
|
56
|
+
|
|
57
|
+
// Events - Enhanced with blockchain metadata (but verification still requires authorization)
|
|
58
|
+
// Note: merkleRootHash included for verification - privacy handled via access control
|
|
59
|
+
// Note: ipfsHash excluded from event for privacy
|
|
60
|
+
// Note: Block hash removed - not reliably available during execution
|
|
61
|
+
event ZipFileTokenized(
|
|
62
|
+
uint256 indexed tokenId,
|
|
63
|
+
address indexed creator,
|
|
64
|
+
string fileName,
|
|
65
|
+
string merkleRootHash,
|
|
66
|
+
uint256 creationTimestamp,
|
|
67
|
+
uint256 tokenizationTime,
|
|
68
|
+
uint256 blockNumber
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
event VerifierAuthorized(
|
|
72
|
+
uint256 indexed tokenId,
|
|
73
|
+
address indexed authorizedAddress,
|
|
74
|
+
bool authorized
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Custom errors
|
|
78
|
+
error NotTokenOwner(uint256 tokenId, address caller);
|
|
79
|
+
error NotAuthorized(uint256 tokenId, address caller);
|
|
80
|
+
error TokenDoesNotExist(uint256 tokenId);
|
|
81
|
+
error ZipFileAlreadyTokenized(string merkleRootHash, uint256 timestamp);
|
|
82
|
+
|
|
83
|
+
// Access control modifier
|
|
84
|
+
modifier onlyTokenOwner(uint256 tokenId) {
|
|
85
|
+
if (ownerOf(tokenId) != msg.sender) {
|
|
86
|
+
revert NotTokenOwner(tokenId, msg.sender);
|
|
87
|
+
}
|
|
88
|
+
_;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Access control modifier for authorized verifiers
|
|
92
|
+
modifier onlyAuthorized(uint256 tokenId) {
|
|
93
|
+
address owner = ownerOf(tokenId);
|
|
94
|
+
if (owner != msg.sender && !authorizedVerifiers[tokenId][msg.sender]) {
|
|
95
|
+
revert NotAuthorized(tokenId, msg.sender);
|
|
96
|
+
}
|
|
97
|
+
_;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
constructor() ERC721("NeoZip File NFT Private v2", "NZIPPRV") Ownable(msg.sender) {}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @dev Get the contract version
|
|
104
|
+
* @return version The version string of this contract
|
|
105
|
+
*/
|
|
106
|
+
function getVersion() public pure returns (string memory) {
|
|
107
|
+
return "2.0.0";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @dev Generate composite key from merkle root and timestamp
|
|
112
|
+
* @param merkleRootHash The merkle root hash
|
|
113
|
+
* @param creationTimestamp The creation timestamp
|
|
114
|
+
* @return The composite key
|
|
115
|
+
*/
|
|
116
|
+
function generateCompositeKey(
|
|
117
|
+
string memory merkleRootHash,
|
|
118
|
+
uint256 creationTimestamp
|
|
119
|
+
) public pure returns (bytes32) {
|
|
120
|
+
return keccak256(abi.encodePacked(merkleRootHash, creationTimestamp));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @dev Public minting function for ZIP files
|
|
125
|
+
* @param fileName Name of the ZIP file
|
|
126
|
+
* @param merkleRootHash Merkle root hash of the ZIP contents
|
|
127
|
+
* @param creationTimestamp Timestamp when the ZIP was created
|
|
128
|
+
* @param ipfsHash IPFS hash where the ZIP is stored
|
|
129
|
+
* @param metadataURI URI for the token metadata
|
|
130
|
+
* @return The newly minted token ID
|
|
131
|
+
*/
|
|
132
|
+
function publicMintZipFile(
|
|
133
|
+
string memory fileName,
|
|
134
|
+
string memory merkleRootHash,
|
|
135
|
+
uint256 creationTimestamp,
|
|
136
|
+
string memory ipfsHash,
|
|
137
|
+
string memory metadataURI
|
|
138
|
+
) public returns (uint256) {
|
|
139
|
+
// Input validation
|
|
140
|
+
require(bytes(fileName).length > 0, "File name cannot be empty");
|
|
141
|
+
require(bytes(merkleRootHash).length > 0, "Merkle root hash cannot be empty");
|
|
142
|
+
require(creationTimestamp > 0, "Creation timestamp must be greater than 0");
|
|
143
|
+
|
|
144
|
+
// Generate composite key to check for duplicates
|
|
145
|
+
bytes32 compositeKey = generateCompositeKey(merkleRootHash, creationTimestamp);
|
|
146
|
+
|
|
147
|
+
// Check if this exact combination already exists
|
|
148
|
+
if (compositeKeyToTokenId[compositeKey] != 0) {
|
|
149
|
+
revert ZipFileAlreadyTokenized(merkleRootHash, creationTimestamp);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Increment token counter
|
|
153
|
+
_tokenIdCounter++;
|
|
154
|
+
uint256 tokenId = _tokenIdCounter;
|
|
155
|
+
|
|
156
|
+
// Mint the NFT to the caller
|
|
157
|
+
_safeMint(msg.sender, tokenId);
|
|
158
|
+
|
|
159
|
+
// Set token URI if provided
|
|
160
|
+
if (bytes(metadataURI).length > 0) {
|
|
161
|
+
_setTokenURI(tokenId, metadataURI);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Store the ZIP file information with blockchain metadata
|
|
165
|
+
zipFileInfo[tokenId] = ZipFileInfo({
|
|
166
|
+
fileName: fileName,
|
|
167
|
+
merkleRootHash: merkleRootHash,
|
|
168
|
+
ipfsHash: ipfsHash,
|
|
169
|
+
creator: msg.sender,
|
|
170
|
+
creationTimestamp: creationTimestamp,
|
|
171
|
+
tokenizationTime: block.timestamp,
|
|
172
|
+
blockNumber: block.number
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Store the composite key mapping
|
|
176
|
+
compositeKeyToTokenId[compositeKey] = tokenId;
|
|
177
|
+
|
|
178
|
+
// Emit event with merkleRootHash for verification (ipfsHash excluded for privacy)
|
|
179
|
+
emit ZipFileTokenized(
|
|
180
|
+
tokenId,
|
|
181
|
+
msg.sender,
|
|
182
|
+
fileName,
|
|
183
|
+
merkleRootHash,
|
|
184
|
+
creationTimestamp,
|
|
185
|
+
block.timestamp,
|
|
186
|
+
block.number
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return tokenId;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @dev Get ZIP file information for a token - OWNER OR AUTHORIZED ONLY
|
|
194
|
+
* @param tokenId The token ID to query
|
|
195
|
+
* @return ZipFileInfo struct containing all file and blockchain metadata
|
|
196
|
+
*/
|
|
197
|
+
function getZipFileInfo(uint256 tokenId) external view onlyAuthorized(tokenId) returns (ZipFileInfo memory) {
|
|
198
|
+
if (_ownerOf(tokenId) == address(0)) {
|
|
199
|
+
revert TokenDoesNotExist(tokenId);
|
|
200
|
+
}
|
|
201
|
+
return zipFileInfo[tokenId];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @dev Get basic public information about a token (safe for public viewing)
|
|
206
|
+
* @param tokenId The token ID to query
|
|
207
|
+
* @return fileName The file name
|
|
208
|
+
* @return creator The creator address
|
|
209
|
+
* @return tokenizationTime When the token was minted
|
|
210
|
+
* @return blockNumber Block number when minted
|
|
211
|
+
*/
|
|
212
|
+
function getPublicTokenInfo(uint256 tokenId) external view returns (
|
|
213
|
+
string memory fileName,
|
|
214
|
+
address creator,
|
|
215
|
+
uint256 tokenizationTime,
|
|
216
|
+
uint256 blockNumber
|
|
217
|
+
) {
|
|
218
|
+
if (_ownerOf(tokenId) == address(0)) {
|
|
219
|
+
revert TokenDoesNotExist(tokenId);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
ZipFileInfo memory info = zipFileInfo[tokenId];
|
|
223
|
+
return (info.fileName, info.creator, info.tokenizationTime, info.blockNumber);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @dev Check if a ZIP file is already tokenized (for minting validation)
|
|
228
|
+
* @param merkleRootHash The merkle root hash to check
|
|
229
|
+
* @param creationTimestamp The creation timestamp to check
|
|
230
|
+
* @return exists Whether the combination exists
|
|
231
|
+
* @return tokenId The token ID if it exists (0 if not)
|
|
232
|
+
* Note: This is public for minting validation, but doesn't reveal token details
|
|
233
|
+
*/
|
|
234
|
+
function isZipFileTokenized(
|
|
235
|
+
string memory merkleRootHash,
|
|
236
|
+
uint256 creationTimestamp
|
|
237
|
+
) external view returns (bool exists, uint256 tokenId) {
|
|
238
|
+
bytes32 compositeKey = generateCompositeKey(merkleRootHash, creationTimestamp);
|
|
239
|
+
tokenId = compositeKeyToTokenId[compositeKey];
|
|
240
|
+
exists = tokenId != 0;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @dev Verify that a token matches the provided merkle root - OWNER OR AUTHORIZED ONLY
|
|
245
|
+
* @param tokenId The token ID to verify
|
|
246
|
+
* @param providedMerkleRoot The merkle root to check against
|
|
247
|
+
* @return isValid Whether the token matches the provided merkle root
|
|
248
|
+
*/
|
|
249
|
+
function verifyZipFile(uint256 tokenId, string memory providedMerkleRoot)
|
|
250
|
+
external view onlyAuthorized(tokenId) returns (bool isValid) {
|
|
251
|
+
if (_ownerOf(tokenId) == address(0)) {
|
|
252
|
+
revert TokenDoesNotExist(tokenId);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return keccak256(abi.encodePacked(zipFileInfo[tokenId].merkleRootHash)) ==
|
|
256
|
+
keccak256(abi.encodePacked(providedMerkleRoot));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @dev Authorize or revoke access for a specific address to verify this token
|
|
261
|
+
* @param tokenId The token ID to manage access for
|
|
262
|
+
* @param authorizedAddress The address to authorize or revoke
|
|
263
|
+
* @param authorized Whether to grant or revoke access
|
|
264
|
+
*/
|
|
265
|
+
function authorizeVerifier(
|
|
266
|
+
uint256 tokenId,
|
|
267
|
+
address authorizedAddress,
|
|
268
|
+
bool authorized
|
|
269
|
+
) external onlyTokenOwner(tokenId) {
|
|
270
|
+
authorizedVerifiers[tokenId][authorizedAddress] = authorized;
|
|
271
|
+
emit VerifierAuthorized(tokenId, authorizedAddress, authorized);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* @dev Check if an address is authorized to verify a specific token
|
|
276
|
+
* @param tokenId The token ID to check
|
|
277
|
+
* @param verifierAddress The address to check authorization for
|
|
278
|
+
* @return Whether the address is authorized
|
|
279
|
+
*/
|
|
280
|
+
function isAuthorizedVerifier(uint256 tokenId, address verifierAddress)
|
|
281
|
+
external view returns (bool) {
|
|
282
|
+
return authorizedVerifiers[tokenId][verifierAddress];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @dev Get blockchain metadata for a token - OWNER OR AUTHORIZED ONLY
|
|
287
|
+
* @param tokenId The token ID to query
|
|
288
|
+
* @return blockNumber Block number when token was minted
|
|
289
|
+
* @return tokenizationTime Exact timestamp when token was minted
|
|
290
|
+
*/
|
|
291
|
+
function getBlockchainMetadata(uint256 tokenId) external view onlyAuthorized(tokenId) returns (
|
|
292
|
+
uint256 blockNumber,
|
|
293
|
+
uint256 tokenizationTime
|
|
294
|
+
) {
|
|
295
|
+
if (_ownerOf(tokenId) == address(0)) {
|
|
296
|
+
revert TokenDoesNotExist(tokenId);
|
|
297
|
+
}
|
|
298
|
+
ZipFileInfo memory info = zipFileInfo[tokenId];
|
|
299
|
+
return (info.blockNumber, info.tokenizationTime);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* @dev Get the current total supply of tokens
|
|
304
|
+
* @return The total number of tokens minted
|
|
305
|
+
*/
|
|
306
|
+
function totalSupply() public view returns (uint256) {
|
|
307
|
+
return _tokenIdCounter;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @dev Get the balance of tokens for an address
|
|
312
|
+
* @param owner The address to query
|
|
313
|
+
* @return The number of tokens owned by the address
|
|
314
|
+
*/
|
|
315
|
+
function balanceOf(address owner) public view override(ERC721, IERC721) returns (uint256) {
|
|
316
|
+
require(owner != address(0), "ERC721: address zero is not a valid owner");
|
|
317
|
+
return super.balanceOf(owner);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* @dev Get all token IDs owned by a specific address (for owner's dashboard)
|
|
322
|
+
* @param owner The address to get tokens for
|
|
323
|
+
* @return tokenIds Array of token IDs owned by the address
|
|
324
|
+
*/
|
|
325
|
+
function getTokensByOwner(address owner) external view returns (uint256[] memory) {
|
|
326
|
+
uint256 balance = balanceOf(owner);
|
|
327
|
+
uint256[] memory result = new uint256[](balance);
|
|
328
|
+
|
|
329
|
+
uint256 counter = 0;
|
|
330
|
+
for (uint256 i = 1; i <= _tokenIdCounter; i++) {
|
|
331
|
+
if (_ownerOf(i) == owner) {
|
|
332
|
+
result[counter] = i;
|
|
333
|
+
counter++;
|
|
334
|
+
if (counter >= balance) break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return result;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Override required by Solidity
|
|
342
|
+
function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) {
|
|
343
|
+
return super.tokenURI(tokenId);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Override required by Solidity
|
|
347
|
+
function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721URIStorage) returns (bool) {
|
|
348
|
+
return super.supportsInterface(interfaceId);
|
|
349
|
+
}
|
|
350
|
+
}
|