@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.
- package/README.md +522 -0
- package/examples/01-create-root-asset.js +71 -0
- package/examples/02-create-sub-asset.js +79 -0
- package/examples/03-create-nfts.js +140 -0
- package/examples/04-reissue-asset.js +164 -0
- package/examples/05-create-qualifier-and-tag.js +209 -0
- package/examples/06-create-restricted-asset.js +223 -0
- package/examples/07-freeze-and-unfreeze.js +292 -0
- package/examples/08-query-assets.js +332 -0
- package/examples/09-wallet-integration.js +320 -0
- package/examples/README.md +319 -0
- package/package.json +43 -0
- package/src/NeuraiAssets.js +468 -0
- package/src/builders/BaseAssetTransactionBuilder.js +303 -0
- package/src/builders/FreezeAddressBuilder.js +271 -0
- package/src/builders/IssueQualifierBuilder.js +251 -0
- package/src/builders/IssueRestrictedBuilder.js +187 -0
- package/src/builders/IssueRootBuilder.js +173 -0
- package/src/builders/IssueSubBuilder.js +237 -0
- package/src/builders/IssueUniqueBuilder.js +255 -0
- package/src/builders/ReissueBuilder.js +246 -0
- package/src/builders/ReissueRestrictedBuilder.js +264 -0
- package/src/builders/TagAddressBuilder.js +243 -0
- package/src/builders/index.js +38 -0
- package/src/constants/assetTypes.js +23 -0
- package/src/constants/burnAddresses.js +65 -0
- package/src/constants/fees.js +61 -0
- package/src/constants/index.js +44 -0
- package/src/constants/networks.js +112 -0
- package/src/errors/AssetErrors.js +135 -0
- package/src/errors/ValidationErrors.js +87 -0
- package/src/errors/index.js +56 -0
- package/src/index.js +68 -0
- package/src/managers/BurnManager.js +222 -0
- package/src/managers/OutputOrderer.js +289 -0
- package/src/managers/OwnerTokenManager.js +265 -0
- package/src/managers/UTXOSelector.js +309 -0
- package/src/managers/index.js +16 -0
- package/src/queries/AssetQueries.js +447 -0
- package/src/queries/index.js +10 -0
- package/src/utils/amountConverter.js +115 -0
- package/src/utils/assetNameParser.js +203 -0
- package/src/utils/index.js +16 -0
- package/src/utils/networkDetector.js +144 -0
- package/src/utils/outputFormatter.js +292 -0
- package/src/validators/amountValidator.js +149 -0
- package/src/validators/assetNameValidator.js +296 -0
- package/src/validators/index.js +16 -0
- package/src/validators/ipfsValidator.js +101 -0
- package/src/validators/verifierValidator.js +146 -0
- package/tests/README.md +126 -0
- package/tests/integration/assetLifecycle.test.js +244 -0
- package/tests/mocks/rpcMock.js +156 -0
- package/tests/unit/NeuraiAssets.test.js +217 -0
- package/tests/unit/utils/amountConverter.test.js +171 -0
- package/tests/unit/utils/assetNameParser.test.js +203 -0
- package/tests/unit/validators/amountValidator.test.js +143 -0
- 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();
|