@neuraiproject/neurai-assets 1.0.0

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.
Files changed (58) hide show
  1. package/README.md +522 -0
  2. package/examples/01-create-root-asset.js +71 -0
  3. package/examples/02-create-sub-asset.js +79 -0
  4. package/examples/03-create-nfts.js +140 -0
  5. package/examples/04-reissue-asset.js +164 -0
  6. package/examples/05-create-qualifier-and-tag.js +209 -0
  7. package/examples/06-create-restricted-asset.js +223 -0
  8. package/examples/07-freeze-and-unfreeze.js +292 -0
  9. package/examples/08-query-assets.js +332 -0
  10. package/examples/09-wallet-integration.js +320 -0
  11. package/examples/README.md +319 -0
  12. package/package.json +43 -0
  13. package/src/NeuraiAssets.js +468 -0
  14. package/src/builders/BaseAssetTransactionBuilder.js +303 -0
  15. package/src/builders/FreezeAddressBuilder.js +271 -0
  16. package/src/builders/IssueQualifierBuilder.js +251 -0
  17. package/src/builders/IssueRestrictedBuilder.js +187 -0
  18. package/src/builders/IssueRootBuilder.js +173 -0
  19. package/src/builders/IssueSubBuilder.js +237 -0
  20. package/src/builders/IssueUniqueBuilder.js +255 -0
  21. package/src/builders/ReissueBuilder.js +246 -0
  22. package/src/builders/ReissueRestrictedBuilder.js +264 -0
  23. package/src/builders/TagAddressBuilder.js +243 -0
  24. package/src/builders/index.js +38 -0
  25. package/src/constants/assetTypes.js +23 -0
  26. package/src/constants/burnAddresses.js +65 -0
  27. package/src/constants/fees.js +61 -0
  28. package/src/constants/index.js +44 -0
  29. package/src/constants/networks.js +112 -0
  30. package/src/errors/AssetErrors.js +135 -0
  31. package/src/errors/ValidationErrors.js +87 -0
  32. package/src/errors/index.js +56 -0
  33. package/src/index.js +68 -0
  34. package/src/managers/BurnManager.js +222 -0
  35. package/src/managers/OutputOrderer.js +289 -0
  36. package/src/managers/OwnerTokenManager.js +265 -0
  37. package/src/managers/UTXOSelector.js +309 -0
  38. package/src/managers/index.js +16 -0
  39. package/src/queries/AssetQueries.js +447 -0
  40. package/src/queries/index.js +10 -0
  41. package/src/utils/amountConverter.js +115 -0
  42. package/src/utils/assetNameParser.js +203 -0
  43. package/src/utils/index.js +16 -0
  44. package/src/utils/networkDetector.js +144 -0
  45. package/src/utils/outputFormatter.js +292 -0
  46. package/src/validators/amountValidator.js +149 -0
  47. package/src/validators/assetNameValidator.js +296 -0
  48. package/src/validators/index.js +16 -0
  49. package/src/validators/ipfsValidator.js +101 -0
  50. package/src/validators/verifierValidator.js +146 -0
  51. package/tests/README.md +126 -0
  52. package/tests/integration/assetLifecycle.test.js +244 -0
  53. package/tests/mocks/rpcMock.js +156 -0
  54. package/tests/unit/NeuraiAssets.test.js +217 -0
  55. package/tests/unit/utils/amountConverter.test.js +171 -0
  56. package/tests/unit/utils/assetNameParser.test.js +203 -0
  57. package/tests/unit/validators/amountValidator.test.js +143 -0
  58. package/tests/unit/validators/assetNameValidator.test.js +228 -0
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Example: Create UNIQUE Assets (NFTs)
3
+ *
4
+ * This example demonstrates how to create UNIQUE assets (NFTs).
5
+ * UNIQUE assets are one-of-a-kind tokens with the format: ROOT#TAG
6
+ *
7
+ * Requirements:
8
+ * - Must own the parent ROOT asset's owner token (ROOT!)
9
+ *
10
+ * Cost: 10 XNA per NFT (burned)
11
+ * Format: ROOT#TAG (e.g., MYTOKEN#001, MYTOKEN#GENESIS)
12
+ */
13
+
14
+ const NeuraiAssets = require('@neuraiproject/neurai-assets');
15
+
16
+ async function createNFTs() {
17
+ // Mock RPC function (replace with your actual RPC client)
18
+ const rpc = async (method, params) => {
19
+ console.log(`RPC Call: ${method}`, params);
20
+ // Your RPC implementation here
21
+ };
22
+
23
+ // Initialize NeuraiAssets
24
+ const assets = new NeuraiAssets(rpc, {
25
+ network: 'xna',
26
+ addresses: ['NYourAddress1...'],
27
+ changeAddress: 'NChangeAddress...',
28
+ toAddress: 'NReceivingAddress...'
29
+ });
30
+
31
+ try {
32
+ // Verify you own the ROOT asset's owner token
33
+ const rootOwnerToken = 'MYTOKEN!';
34
+ const myAssets = await assets.listMyAssets(rootOwnerToken);
35
+
36
+ if (!myAssets[rootOwnerToken]) {
37
+ throw new Error(`You must own ${rootOwnerToken} to create UNIQUE assets`);
38
+ }
39
+
40
+ console.log(`✓ Owner token found: ${rootOwnerToken}`);
41
+
42
+ // Create multiple NFTs in a single transaction
43
+ const result = await assets.createUniqueAssets({
44
+ rootAssetName: 'MYTOKEN',
45
+ assetTags: [
46
+ {
47
+ tag: 'GENESIS', // First NFT: MYTOKEN#GENESIS
48
+ hasIpfs: true,
49
+ ipfsHash: 'QmNFT1GenesisMetadata...'
50
+ },
51
+ {
52
+ tag: '001', // Second NFT: MYTOKEN#001
53
+ hasIpfs: true,
54
+ ipfsHash: 'QmNFT2Metadata...'
55
+ },
56
+ {
57
+ tag: '002', // Third NFT: MYTOKEN#002
58
+ hasIpfs: true,
59
+ ipfsHash: 'QmNFT3Metadata...'
60
+ },
61
+ {
62
+ tag: 'SPECIAL_EDITION', // Fourth NFT: MYTOKEN#SPECIAL_EDITION
63
+ hasIpfs: true,
64
+ ipfsHash: 'QmNFT4Metadata...'
65
+ }
66
+ ]
67
+ });
68
+
69
+ console.log('NFT Collection created successfully!');
70
+ console.log('Raw Transaction:', result.rawTx);
71
+ console.log('Total Fee:', result.fee, 'XNA');
72
+ console.log('Total Burn:', result.burn, 'XNA (10 XNA per NFT)');
73
+ console.log('NFTs Created:', result.metadata.assetTags.length);
74
+ console.log('Owner Token Used:', result.metadata.ownerTokenUsed);
75
+
76
+ console.log('\nNFTs created:');
77
+ result.metadata.assetTags.forEach((tag, index) => {
78
+ console.log(`${index + 1}. MYTOKEN#${tag}`);
79
+ });
80
+
81
+ // IMPORTANT: Each UNIQUE asset has a quantity of 1 and cannot be reissued
82
+ // Each NFT is truly unique and one-of-a-kind
83
+
84
+ console.log('\nNFT Properties:');
85
+ console.log('- Quantity: 1 (fixed, cannot be changed)');
86
+ console.log('- Reissuable: No (unique forever)');
87
+ console.log('- Units: 0 (not divisible)');
88
+ console.log('- IPFS: Each NFT can have its own metadata');
89
+
90
+ } catch (error) {
91
+ console.error('Error creating NFTs:', error.message);
92
+
93
+ if (error.name === 'OwnerTokenNotFoundError') {
94
+ console.error('You do not own the required ROOT owner token');
95
+ } else if (error.name === 'InvalidAssetNameError') {
96
+ console.error('Invalid NFT tag format');
97
+ }
98
+ }
99
+ }
100
+
101
+ // Alternative: Create a single NFT
102
+ async function createSingleNFT() {
103
+ const rpc = async (method, params) => {
104
+ console.log(`RPC Call: ${method}`, params);
105
+ };
106
+
107
+ const assets = new NeuraiAssets(rpc, {
108
+ network: 'xna',
109
+ addresses: ['NYourAddress1...'],
110
+ changeAddress: 'NChangeAddress...',
111
+ toAddress: 'NReceivingAddress...'
112
+ });
113
+
114
+ try {
115
+ // Create just one NFT
116
+ const result = await assets.createUniqueAssets({
117
+ rootAssetName: 'MYTOKEN',
118
+ assetTags: [
119
+ {
120
+ tag: 'LEGENDARY',
121
+ hasIpfs: true,
122
+ ipfsHash: 'QmLegendaryNFTMetadata...'
123
+ }
124
+ ]
125
+ });
126
+
127
+ console.log('Single NFT created: MYTOKEN#LEGENDARY');
128
+ console.log('Burn:', result.burn, 'XNA');
129
+
130
+ } catch (error) {
131
+ console.error('Error:', error.message);
132
+ }
133
+ }
134
+
135
+ // Run the examples
136
+ console.log('=== Example 1: Create NFT Collection ===\n');
137
+ createNFTs();
138
+
139
+ console.log('\n\n=== Example 2: Create Single NFT ===\n');
140
+ createSingleNFT();
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Example: Reissue Assets (Mint More Supply)
3
+ *
4
+ * This example demonstrates how to reissue (mint more) of an existing asset.
5
+ * Reissuing allows you to increase the total supply of a ROOT or SUB asset.
6
+ *
7
+ * Requirements:
8
+ * - Must own the asset's owner token (ASSET!)
9
+ * - Asset must be reissuable (reissuable flag must be true)
10
+ *
11
+ * Cost: 200 XNA (burned)
12
+ */
13
+
14
+ const NeuraiAssets = require('@neuraiproject/neurai-assets');
15
+
16
+ async function reissueAsset() {
17
+ // Mock RPC function (replace with your actual RPC client)
18
+ const rpc = async (method, params) => {
19
+ console.log(`RPC Call: ${method}`, params);
20
+ // Your RPC implementation here
21
+ };
22
+
23
+ // Initialize NeuraiAssets
24
+ const assets = new NeuraiAssets(rpc, {
25
+ network: 'xna',
26
+ addresses: ['NYourAddress1...'],
27
+ changeAddress: 'NChangeAddress...',
28
+ toAddress: 'NReceivingAddress...'
29
+ });
30
+
31
+ try {
32
+ // Step 1: Check current asset data
33
+ const assetName = 'MYTOKEN';
34
+ const assetData = await assets.getAssetData(assetName);
35
+
36
+ console.log('Current Asset Info:');
37
+ console.log('- Name:', assetData.name);
38
+ console.log('- Current Supply:', assetData.amount);
39
+ console.log('- Units:', assetData.units);
40
+ console.log('- Reissuable:', assetData.reissuable);
41
+
42
+ // Step 2: Verify asset is reissuable
43
+ if (!assetData.reissuable) {
44
+ throw new Error('Asset supply is locked and cannot be reissued');
45
+ }
46
+
47
+ // Step 3: Verify you own the owner token
48
+ const ownerToken = `${assetName}!`;
49
+ const myAssets = await assets.listMyAssets(ownerToken);
50
+
51
+ if (!myAssets[ownerToken]) {
52
+ throw new Error(`You must own ${ownerToken} to reissue this asset`);
53
+ }
54
+
55
+ console.log(`✓ Owner token found: ${ownerToken}`);
56
+
57
+ // Step 4: Reissue (mint more supply)
58
+ const result = await assets.reissueAsset({
59
+ assetName: assetName,
60
+ quantity: 500000, // Additional amount to mint
61
+ reissuable: true, // Keep it reissuable (false to lock forever)
62
+ newIpfs: '' // Optional: update IPFS metadata
63
+ });
64
+
65
+ const newTotalSupply = assetData.amount + 500000;
66
+
67
+ console.log('\nReissue transaction created successfully!');
68
+ console.log('Raw Transaction:', result.rawTx);
69
+ console.log('Fee:', result.fee, 'XNA');
70
+ console.log('Burn:', result.burn, 'XNA');
71
+ console.log('Amount to Mint:', result.metadata.quantityMinted);
72
+ console.log('Previous Supply:', result.metadata.previousSupply);
73
+ console.log('New Total Supply:', result.metadata.newTotalSupply);
74
+
75
+ console.log('\nNext steps:');
76
+ console.log('1. Sign the transaction');
77
+ console.log('2. Broadcast to network');
78
+ console.log('3. New tokens will be added to your balance');
79
+
80
+ } catch (error) {
81
+ console.error('Error reissuing asset:', error.message);
82
+
83
+ if (error.name === 'AssetNotReissuableError') {
84
+ console.error('This asset supply is locked and cannot be reissued');
85
+ } else if (error.name === 'OwnerTokenNotFoundError') {
86
+ console.error('You do not own the required owner token');
87
+ } else if (error.name === 'MaxSupplyExceededError') {
88
+ console.error('Reissuing would exceed maximum supply of 21 billion');
89
+ }
90
+ }
91
+ }
92
+
93
+ // Example: Lock the supply forever
94
+ async function lockSupply() {
95
+ const rpc = async (method, params) => {
96
+ console.log(`RPC Call: ${method}`, params);
97
+ };
98
+
99
+ const assets = new NeuraiAssets(rpc, {
100
+ network: 'xna',
101
+ addresses: ['NYourAddress1...'],
102
+ changeAddress: 'NChangeAddress...',
103
+ toAddress: 'NReceivingAddress...'
104
+ });
105
+
106
+ try {
107
+ // Reissue with reissuable=false to lock supply forever
108
+ const result = await assets.reissueAsset({
109
+ assetName: 'MYTOKEN',
110
+ quantity: 0, // No additional supply
111
+ reissuable: false, // LOCK SUPPLY FOREVER
112
+ newIpfs: ''
113
+ });
114
+
115
+ console.log('Supply locked permanently!');
116
+ console.log('No more tokens can ever be minted for this asset');
117
+ console.log('Reissuable Status:', result.metadata.reissuableLocked ? 'LOCKED' : 'UNLOCKED');
118
+
119
+ // WARNING: This action is PERMANENT and cannot be undone!
120
+
121
+ } catch (error) {
122
+ console.error('Error:', error.message);
123
+ }
124
+ }
125
+
126
+ // Example: Update IPFS metadata
127
+ async function updateMetadata() {
128
+ const rpc = async (method, params) => {
129
+ console.log(`RPC Call: ${method}`, params);
130
+ };
131
+
132
+ const assets = new NeuraiAssets(rpc, {
133
+ network: 'xna',
134
+ addresses: ['NYourAddress1...'],
135
+ changeAddress: 'NChangeAddress...',
136
+ toAddress: 'NReceivingAddress...'
137
+ });
138
+
139
+ try {
140
+ // Reissue to update IPFS hash without minting new supply
141
+ const result = await assets.reissueAsset({
142
+ assetName: 'MYTOKEN',
143
+ quantity: 0, // No new supply
144
+ reissuable: true, // Keep reissuable
145
+ newIpfs: 'QmNewUpdatedMetadata...' // New IPFS hash
146
+ });
147
+
148
+ console.log('Metadata updated successfully!');
149
+ console.log('New IPFS hash:', 'QmNewUpdatedMetadata...');
150
+
151
+ } catch (error) {
152
+ console.error('Error:', error.message);
153
+ }
154
+ }
155
+
156
+ // Run the examples
157
+ console.log('=== Example 1: Mint More Supply ===\n');
158
+ reissueAsset();
159
+
160
+ console.log('\n\n=== Example 2: Lock Supply Forever ===\n');
161
+ lockSupply();
162
+
163
+ console.log('\n\n=== Example 3: Update Metadata ===\n');
164
+ updateMetadata();
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Example: Create QUALIFIERs and Tag Addresses
3
+ *
4
+ * This example demonstrates how to create QUALIFIER assets (KYC/compliance tags)
5
+ * and assign them to addresses. QUALIFIERs are used for compliance in RESTRICTED assets.
6
+ *
7
+ * Format: #NAME (e.g., #KYC_VERIFIED, #ACCREDITED)
8
+ *
9
+ * Costs:
10
+ * - Create QUALIFIER (root): 2000 XNA
11
+ * - Create SUB_QUALIFIER: 200 XNA
12
+ * - Tag/Untag address: 0.1 XNA per address
13
+ */
14
+
15
+ const NeuraiAssets = require('@neuraiproject/neurai-assets');
16
+
17
+ async function createQualifierAndTagAddresses() {
18
+ // Mock RPC function (replace with your actual RPC client)
19
+ const rpc = async (method, params) => {
20
+ console.log(`RPC Call: ${method}`, params);
21
+ // Your RPC implementation here
22
+ };
23
+
24
+ // Initialize NeuraiAssets
25
+ const assets = new NeuraiAssets(rpc, {
26
+ network: 'xna',
27
+ addresses: ['NYourAddress1...'],
28
+ changeAddress: 'NChangeAddress...',
29
+ toAddress: 'NReceivingAddress...'
30
+ });
31
+
32
+ try {
33
+ // Step 1: Create a QUALIFIER (KYC tag)
34
+ console.log('=== Step 1: Create QUALIFIER ===\n');
35
+
36
+ const createResult = await assets.createQualifier({
37
+ qualifierName: '#KYC_VERIFIED', // Must start with #
38
+ quantity: 1, // Usually 1-10 (limited quantity)
39
+ hasIpfs: true,
40
+ ipfsHash: 'QmKYCMetadata...' // Metadata about the qualifier
41
+ });
42
+
43
+ console.log('QUALIFIER created successfully!');
44
+ console.log('Name:', '#KYC_VERIFIED');
45
+ console.log('Owner Token:', '#KYC_VERIFIED!');
46
+ console.log('Burn:', createResult.burn, 'XNA');
47
+
48
+ // Step 2: Tag addresses with the qualifier
49
+ console.log('\n=== Step 2: Tag Addresses ===\n');
50
+
51
+ const tagResult = await assets.tagAddresses({
52
+ qualifierName: '#KYC_VERIFIED',
53
+ addresses: [
54
+ 'NAddress1ToKYC...',
55
+ 'NAddress2ToKYC...',
56
+ 'NAddress3ToKYC...'
57
+ ],
58
+ assetData: 'KYC expires 2025-12-31' // Optional data
59
+ });
60
+
61
+ console.log('Addresses tagged successfully!');
62
+ console.log('Qualifier:', tagResult.metadata.qualifierName);
63
+ console.log('Addresses tagged:', tagResult.metadata.addressCount);
64
+ console.log('Burn:', tagResult.burn, 'XNA (0.1 per address)');
65
+
66
+ // Step 3: Verify tags
67
+ console.log('\n=== Step 3: Verify Tags ===\n');
68
+
69
+ for (const address of tagResult.metadata.targetAddresses) {
70
+ const hasTag = await assets.checkAddressTag(address, '#KYC_VERIFIED');
71
+ console.log(`${address}: ${hasTag ? '✓ Tagged' : '✗ Not tagged'}`);
72
+ }
73
+
74
+ // Step 4: List all tags for an address
75
+ console.log('\n=== Step 4: List Address Tags ===\n');
76
+
77
+ const tags = await assets.listTagsForAddress('NAddress1ToKYC...');
78
+ console.log('Tags for NAddress1ToKYC:');
79
+ tags.forEach(tag => console.log(`- ${tag}`));
80
+
81
+ } catch (error) {
82
+ console.error('Error:', error.message);
83
+
84
+ if (error.name === 'InvalidAssetNameError') {
85
+ console.error('Qualifier name must start with #');
86
+ } else if (error.name === 'OwnerTokenNotFoundError') {
87
+ console.error('You need the qualifier owner token to tag addresses');
88
+ }
89
+ }
90
+ }
91
+
92
+ // Example: Create multiple qualifiers for different compliance levels
93
+ async function createComplianceSystem() {
94
+ const rpc = async (method, params) => {
95
+ console.log(`RPC Call: ${method}`, params);
96
+ };
97
+
98
+ const assets = new NeuraiAssets(rpc, {
99
+ network: 'xna',
100
+ addresses: ['NYourAddress1...'],
101
+ changeAddress: 'NChangeAddress...',
102
+ toAddress: 'NReceivingAddress...'
103
+ });
104
+
105
+ try {
106
+ // Create different compliance qualifiers
107
+ const qualifiers = [
108
+ { name: '#KYC_BASIC', metadata: 'QmBasicKYC...' },
109
+ { name: '#KYC_ADVANCED', metadata: 'QmAdvancedKYC...' },
110
+ { name: '#ACCREDITED_INVESTOR', metadata: 'QmAccredited...' },
111
+ { name: '#INSTITUTIONAL', metadata: 'QmInstitutional...' }
112
+ ];
113
+
114
+ console.log('Creating compliance qualifier system...\n');
115
+
116
+ for (const qualifier of qualifiers) {
117
+ const result = await assets.createQualifier({
118
+ qualifierName: qualifier.name,
119
+ quantity: 1,
120
+ hasIpfs: true,
121
+ ipfsHash: qualifier.metadata
122
+ });
123
+
124
+ console.log(`✓ Created: ${qualifier.name} (burn: ${result.burn} XNA)`);
125
+ }
126
+
127
+ console.log('\nCompliance system created!');
128
+ console.log('You can now tag addresses with different compliance levels.');
129
+
130
+ } catch (error) {
131
+ console.error('Error:', error.message);
132
+ }
133
+ }
134
+
135
+ // Example: Remove tags from addresses
136
+ async function untagAddresses() {
137
+ const rpc = async (method, params) => {
138
+ console.log(`RPC Call: ${method}`, params);
139
+ };
140
+
141
+ const assets = new NeuraiAssets(rpc, {
142
+ network: 'xna',
143
+ addresses: ['NYourAddress1...'],
144
+ changeAddress: 'NChangeAddress...',
145
+ toAddress: 'NReceivingAddress...'
146
+ });
147
+
148
+ try {
149
+ // Remove KYC tag from addresses
150
+ const result = await assets.untagAddresses({
151
+ qualifierName: '#KYC_VERIFIED',
152
+ addresses: [
153
+ 'NAddressToUntag1...',
154
+ 'NAddressToUntag2...'
155
+ ]
156
+ });
157
+
158
+ console.log('Tags removed successfully!');
159
+ console.log('Addresses untagged:', result.metadata.addressCount);
160
+ console.log('Burn:', result.burn, 'XNA');
161
+
162
+ } catch (error) {
163
+ console.error('Error:', error.message);
164
+ }
165
+ }
166
+
167
+ // Example: Create SUB_QUALIFIER
168
+ async function createSubQualifier() {
169
+ const rpc = async (method, params) => {
170
+ console.log(`RPC Call: ${method}`, params);
171
+ };
172
+
173
+ const assets = new NeuraiAssets(rpc, {
174
+ network: 'xna',
175
+ addresses: ['NYourAddress1...'],
176
+ changeAddress: 'NChangeAddress...',
177
+ toAddress: 'NReceivingAddress...'
178
+ });
179
+
180
+ try {
181
+ // Create a sub-qualifier (requires parent qualifier owner token)
182
+ const result = await assets.createQualifier({
183
+ qualifierName: '#KYC/#LEVEL_2', // Format: #PARENT/#SUB
184
+ quantity: 1,
185
+ hasIpfs: true,
186
+ ipfsHash: 'QmLevel2Metadata...'
187
+ });
188
+
189
+ console.log('SUB_QUALIFIER created!');
190
+ console.log('Name:', '#KYC/#LEVEL_2');
191
+ console.log('Burn:', result.burn, 'XNA (200 for sub-qualifier)');
192
+
193
+ } catch (error) {
194
+ console.error('Error:', error.message);
195
+ }
196
+ }
197
+
198
+ // Run the examples
199
+ console.log('=== Example 1: Create Qualifier and Tag Addresses ===\n');
200
+ createQualifierAndTagAddresses();
201
+
202
+ console.log('\n\n=== Example 2: Create Compliance System ===\n');
203
+ createComplianceSystem();
204
+
205
+ console.log('\n\n=== Example 3: Untag Addresses ===\n');
206
+ untagAddresses();
207
+
208
+ console.log('\n\n=== Example 4: Create SUB_QUALIFIER ===\n');
209
+ createSubQualifier();