@neuraiproject/neurai-assets 1.2.2 → 1.2.5
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 +21 -21
- package/dist/NeuraiAssets.global.js +329 -235
- package/dist/NeuraiAssets.global.js.map +1 -1
- package/dist/browser.js +329 -235
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +329 -235
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +329 -235
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1041,11 +1041,15 @@ var hasRequiredNetworks;
|
|
|
1041
1041
|
function requireNetworks () {
|
|
1042
1042
|
if (hasRequiredNetworks) return networks;
|
|
1043
1043
|
hasRequiredNetworks = 1;
|
|
1044
|
+
const MAINNET_NETWORKS = ['xna', 'mainnet', 'xna-pq', 'mainnet-pq'];
|
|
1045
|
+
const TESTNET_NETWORKS = ['xna-test', 'testnet', 'regtest', 'xna-pq-test', 'testnet-pq'];
|
|
1046
|
+
|
|
1044
1047
|
const NETWORKS = {
|
|
1045
1048
|
MAINNET: {
|
|
1046
1049
|
name: 'xna',
|
|
1047
1050
|
displayName: 'Neurai Mainnet',
|
|
1048
1051
|
addressPrefix: 'N',
|
|
1052
|
+
authScriptAddressPrefix: 'nq1',
|
|
1049
1053
|
pqAddressPrefix: 'nq1',
|
|
1050
1054
|
assetNameMaxLength: 32,
|
|
1051
1055
|
defaultRPCPort: 19001,
|
|
@@ -1056,6 +1060,7 @@ function requireNetworks () {
|
|
|
1056
1060
|
name: 'xna-test',
|
|
1057
1061
|
displayName: 'Neurai Testnet',
|
|
1058
1062
|
addressPrefix: 't',
|
|
1063
|
+
authScriptAddressPrefix: 'tnq1',
|
|
1059
1064
|
pqAddressPrefix: 'tnq1',
|
|
1060
1065
|
assetNameMaxLength: 32, // Same as mainnet
|
|
1061
1066
|
defaultRPCPort: 19101,
|
|
@@ -1064,8 +1069,9 @@ function requireNetworks () {
|
|
|
1064
1069
|
},
|
|
1065
1070
|
MAINNET_PQ: {
|
|
1066
1071
|
name: 'xna-pq',
|
|
1067
|
-
displayName: 'Neurai Mainnet
|
|
1072
|
+
displayName: 'Neurai Mainnet AuthScript',
|
|
1068
1073
|
addressPrefix: 'N',
|
|
1074
|
+
authScriptAddressPrefix: 'nq1',
|
|
1069
1075
|
pqAddressPrefix: 'nq1',
|
|
1070
1076
|
assetNameMaxLength: 32,
|
|
1071
1077
|
defaultRPCPort: 19001,
|
|
@@ -1074,8 +1080,9 @@ function requireNetworks () {
|
|
|
1074
1080
|
},
|
|
1075
1081
|
TESTNET_PQ: {
|
|
1076
1082
|
name: 'xna-pq-test',
|
|
1077
|
-
displayName: 'Neurai Testnet
|
|
1083
|
+
displayName: 'Neurai Testnet AuthScript',
|
|
1078
1084
|
addressPrefix: 't',
|
|
1085
|
+
authScriptAddressPrefix: 'tnq1',
|
|
1079
1086
|
pqAddressPrefix: 'tnq1',
|
|
1080
1087
|
assetNameMaxLength: 32,
|
|
1081
1088
|
defaultRPCPort: 19101,
|
|
@@ -1085,45 +1092,45 @@ function requireNetworks () {
|
|
|
1085
1092
|
};
|
|
1086
1093
|
|
|
1087
1094
|
/**
|
|
1088
|
-
* Asset naming
|
|
1095
|
+
* Asset naming helpers.
|
|
1096
|
+
* Network-specific maximum lengths are enforced in AssetNameValidator.
|
|
1089
1097
|
*/
|
|
1090
1098
|
const ASSET_NAME_RULES = {
|
|
1091
1099
|
ROOT: {
|
|
1092
1100
|
minLength: 3,
|
|
1093
|
-
maxLength:
|
|
1101
|
+
maxLength: 31,
|
|
1094
1102
|
pattern: /^[A-Z0-9_.]+$/,
|
|
1095
|
-
|
|
1096
|
-
reserved: ['XNA', 'NEURAI']
|
|
1103
|
+
reserved: ['XNA', 'NEURAI', 'NEURAICOIN']
|
|
1097
1104
|
},
|
|
1098
1105
|
SUB: {
|
|
1099
1106
|
minLength: 1,
|
|
1100
|
-
maxLength:
|
|
1107
|
+
maxLength: 31,
|
|
1101
1108
|
pattern: /^[A-Z0-9_.]+$/,
|
|
1102
1109
|
separator: '/',
|
|
1103
|
-
maxDepth:
|
|
1110
|
+
maxDepth: null
|
|
1104
1111
|
},
|
|
1105
1112
|
UNIQUE: {
|
|
1106
1113
|
minLength: 1,
|
|
1107
|
-
maxLength:
|
|
1108
|
-
pattern: /^[A-
|
|
1114
|
+
maxLength: 32,
|
|
1115
|
+
pattern: /^[-A-Za-z0-9@$%&*()[\]{}_.?:]+$/,
|
|
1109
1116
|
separator: '#'
|
|
1110
1117
|
},
|
|
1111
1118
|
QUALIFIER: {
|
|
1112
1119
|
minLength: 3,
|
|
1113
|
-
maxLength:
|
|
1114
|
-
pattern: /^[A-Z0-9_]+$/,
|
|
1120
|
+
maxLength: 32,
|
|
1121
|
+
pattern: /^[A-Z0-9_.]+$/,
|
|
1115
1122
|
prefix: '#',
|
|
1116
1123
|
separator: '/'
|
|
1117
1124
|
},
|
|
1118
1125
|
RESTRICTED: {
|
|
1119
1126
|
minLength: 3,
|
|
1120
|
-
maxLength:
|
|
1127
|
+
maxLength: 32,
|
|
1121
1128
|
pattern: /^[A-Z0-9_.]+$/,
|
|
1122
1129
|
prefix: '$'
|
|
1123
1130
|
},
|
|
1124
1131
|
DEPIN: {
|
|
1125
1132
|
minLength: 3,
|
|
1126
|
-
maxLength:
|
|
1133
|
+
maxLength: 121,
|
|
1127
1134
|
pattern: /^[A-Z0-9_.]+$/,
|
|
1128
1135
|
prefix: '&',
|
|
1129
1136
|
separator: '/'
|
|
@@ -1145,32 +1152,68 @@ function requireNetworks () {
|
|
|
1145
1152
|
|
|
1146
1153
|
/**
|
|
1147
1154
|
* Get network configuration
|
|
1155
|
+
* `xna-pq` / `xna-pq-test` are preserved as compatibility aliases for
|
|
1156
|
+
* AuthScript address flows on the same mainnet/testnet families.
|
|
1157
|
+
*
|
|
1148
1158
|
* @param {string} networkName - Network name ('xna', 'xna-test', 'xna-pq', or 'xna-pq-test')
|
|
1149
1159
|
* @returns {object} Network configuration
|
|
1150
1160
|
*/
|
|
1151
1161
|
function getNetworkConfig(networkName) {
|
|
1152
|
-
if (networkName
|
|
1153
|
-
return
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
} else if (networkName
|
|
1157
|
-
return
|
|
1158
|
-
|
|
1159
|
-
|
|
1162
|
+
if (MAINNET_NETWORKS.includes(networkName)) {
|
|
1163
|
+
return networkName === 'xna-pq' || networkName === 'mainnet-pq'
|
|
1164
|
+
? NETWORKS.MAINNET_PQ
|
|
1165
|
+
: NETWORKS.MAINNET;
|
|
1166
|
+
} else if (TESTNET_NETWORKS.includes(networkName)) {
|
|
1167
|
+
return networkName === 'xna-pq-test' || networkName === 'testnet-pq'
|
|
1168
|
+
? NETWORKS.TESTNET_PQ
|
|
1169
|
+
: NETWORKS.TESTNET;
|
|
1160
1170
|
} else {
|
|
1161
1171
|
throw new Error(`Unknown network: ${networkName}`);
|
|
1162
1172
|
}
|
|
1163
1173
|
}
|
|
1164
1174
|
|
|
1165
1175
|
/**
|
|
1166
|
-
*
|
|
1176
|
+
* Resolve a network name to its chain family.
|
|
1177
|
+
* AuthScript aliases share the same family as legacy addresses.
|
|
1178
|
+
*
|
|
1179
|
+
* @param {string} networkName - Network name
|
|
1180
|
+
* @returns {'mainnet'|'testnet'} Network family
|
|
1181
|
+
*/
|
|
1182
|
+
function resolveAddressNetworkFamily(networkName) {
|
|
1183
|
+
if (MAINNET_NETWORKS.includes(networkName)) {
|
|
1184
|
+
return 'mainnet';
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
if (TESTNET_NETWORKS.includes(networkName)) {
|
|
1188
|
+
return 'testnet';
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
throw new Error(`Unknown network: ${networkName}`);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Determine whether two network labels are compatible for address use.
|
|
1196
|
+
* This treats legacy and AuthScript labels on the same chain as compatible.
|
|
1197
|
+
*
|
|
1198
|
+
* @param {string} left - First network name
|
|
1199
|
+
* @param {string} right - Second network name
|
|
1200
|
+
* @returns {boolean} True if both belong to the same chain family
|
|
1201
|
+
*/
|
|
1202
|
+
function areAddressNetworksCompatible(left, right) {
|
|
1203
|
+
return resolveAddressNetworkFamily(left) === resolveAddressNetworkFamily(right);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/**
|
|
1207
|
+
* Detect network from address prefix.
|
|
1208
|
+
* `nq1...` / `tnq1...` are AuthScript witness-v1 destinations.
|
|
1209
|
+
*
|
|
1167
1210
|
* @param {string} address - Neurai address
|
|
1168
1211
|
* @returns {string} Network name ('xna', 'xna-test', 'xna-pq', or 'xna-pq-test')
|
|
1169
1212
|
*/
|
|
1170
1213
|
function detectNetworkFromAddress(address) {
|
|
1171
|
-
if (address.startsWith(NETWORKS.MAINNET_PQ.
|
|
1214
|
+
if (address.startsWith(NETWORKS.MAINNET_PQ.authScriptAddressPrefix)) {
|
|
1172
1215
|
return 'xna-pq';
|
|
1173
|
-
} else if (address.startsWith(NETWORKS.TESTNET_PQ.
|
|
1216
|
+
} else if (address.startsWith(NETWORKS.TESTNET_PQ.authScriptAddressPrefix)) {
|
|
1174
1217
|
return 'xna-pq-test';
|
|
1175
1218
|
} else if (address.startsWith('N')) {
|
|
1176
1219
|
return 'xna';
|
|
@@ -1183,9 +1226,13 @@ function requireNetworks () {
|
|
|
1183
1226
|
|
|
1184
1227
|
networks = {
|
|
1185
1228
|
NETWORKS,
|
|
1229
|
+
MAINNET_NETWORKS,
|
|
1230
|
+
TESTNET_NETWORKS,
|
|
1186
1231
|
ASSET_NAME_RULES,
|
|
1187
1232
|
ASSET_LIMITS,
|
|
1188
1233
|
getNetworkConfig,
|
|
1234
|
+
resolveAddressNetworkFamily,
|
|
1235
|
+
areAddressNetworksCompatible,
|
|
1189
1236
|
detectNetworkFromAddress
|
|
1190
1237
|
};
|
|
1191
1238
|
return networks;
|
|
@@ -1213,9 +1260,13 @@ function requireConstants () {
|
|
|
1213
1260
|
} = requireBurnAddresses();
|
|
1214
1261
|
const {
|
|
1215
1262
|
NETWORKS,
|
|
1263
|
+
MAINNET_NETWORKS,
|
|
1264
|
+
TESTNET_NETWORKS,
|
|
1216
1265
|
ASSET_NAME_RULES,
|
|
1217
1266
|
ASSET_LIMITS,
|
|
1218
1267
|
getNetworkConfig,
|
|
1268
|
+
resolveAddressNetworkFamily,
|
|
1269
|
+
areAddressNetworksCompatible,
|
|
1219
1270
|
detectNetworkFromAddress
|
|
1220
1271
|
} = requireNetworks();
|
|
1221
1272
|
|
|
@@ -1238,9 +1289,13 @@ function requireConstants () {
|
|
|
1238
1289
|
|
|
1239
1290
|
// Networks
|
|
1240
1291
|
NETWORKS,
|
|
1292
|
+
MAINNET_NETWORKS,
|
|
1293
|
+
TESTNET_NETWORKS,
|
|
1241
1294
|
ASSET_NAME_RULES,
|
|
1242
1295
|
ASSET_LIMITS,
|
|
1243
1296
|
getNetworkConfig,
|
|
1297
|
+
resolveAddressNetworkFamily,
|
|
1298
|
+
areAddressNetworksCompatible,
|
|
1244
1299
|
detectNetworkFromAddress
|
|
1245
1300
|
};
|
|
1246
1301
|
return constants$1;
|
|
@@ -1857,7 +1912,11 @@ var hasRequiredNetworkDetector;
|
|
|
1857
1912
|
function requireNetworkDetector () {
|
|
1858
1913
|
if (hasRequiredNetworkDetector) return networkDetector;
|
|
1859
1914
|
hasRequiredNetworkDetector = 1;
|
|
1860
|
-
const {
|
|
1915
|
+
const {
|
|
1916
|
+
NETWORKS,
|
|
1917
|
+
areAddressNetworksCompatible,
|
|
1918
|
+
resolveAddressNetworkFamily
|
|
1919
|
+
} = requireConstants();
|
|
1861
1920
|
|
|
1862
1921
|
class NetworkDetector {
|
|
1863
1922
|
/**
|
|
@@ -1894,18 +1953,18 @@ function requireNetworkDetector () {
|
|
|
1894
1953
|
/**
|
|
1895
1954
|
* Detect network from address
|
|
1896
1955
|
* @param {string} address - Neurai address
|
|
1897
|
-
* @returns {string} Network
|
|
1956
|
+
* @returns {string} Network label ('xna', 'xna-test', 'xna-pq', or 'xna-pq-test')
|
|
1898
1957
|
*/
|
|
1899
1958
|
static detectFromAddress(address) {
|
|
1900
1959
|
if (!address || typeof address !== 'string') {
|
|
1901
1960
|
throw new Error('Address must be a non-empty string');
|
|
1902
1961
|
}
|
|
1903
1962
|
|
|
1904
|
-
if (address.startsWith(NETWORKS.MAINNET_PQ.
|
|
1963
|
+
if (address.startsWith(NETWORKS.MAINNET_PQ.authScriptAddressPrefix)) {
|
|
1905
1964
|
return 'xna-pq';
|
|
1906
1965
|
}
|
|
1907
1966
|
|
|
1908
|
-
if (address.startsWith(NETWORKS.TESTNET_PQ.
|
|
1967
|
+
if (address.startsWith(NETWORKS.TESTNET_PQ.authScriptAddressPrefix)) {
|
|
1909
1968
|
return 'xna-pq-test';
|
|
1910
1969
|
}
|
|
1911
1970
|
|
|
@@ -1925,31 +1984,32 @@ function requireNetworkDetector () {
|
|
|
1925
1984
|
/**
|
|
1926
1985
|
* Detect network from multiple addresses
|
|
1927
1986
|
* @param {string[]} addresses - Array of addresses
|
|
1928
|
-
* @returns {string} Network
|
|
1987
|
+
* @returns {string} Network label. Mixed legacy/AuthScript addresses on the same
|
|
1988
|
+
* chain are normalized to the chain family label (`xna` or `xna-test`).
|
|
1929
1989
|
*/
|
|
1930
1990
|
static detectFromAddresses(addresses) {
|
|
1931
1991
|
if (!Array.isArray(addresses) || addresses.length === 0) {
|
|
1932
1992
|
throw new Error('Addresses must be a non-empty array');
|
|
1933
1993
|
}
|
|
1934
1994
|
|
|
1935
|
-
|
|
1936
|
-
const
|
|
1995
|
+
const firstNetwork = this.detectFromAddress(addresses[0]);
|
|
1996
|
+
const family = resolveAddressNetworkFamily(firstNetwork);
|
|
1937
1997
|
|
|
1938
1998
|
// Verify all addresses are from the same network
|
|
1939
1999
|
for (let i = 1; i < addresses.length; i++) {
|
|
1940
2000
|
const otherNetwork = this.detectFromAddress(addresses[i]);
|
|
1941
|
-
if (otherNetwork
|
|
1942
|
-
throw new Error(`Mixed network addresses detected: ${
|
|
2001
|
+
if (!areAddressNetworksCompatible(firstNetwork, otherNetwork)) {
|
|
2002
|
+
throw new Error(`Mixed network addresses detected: ${firstNetwork} and ${otherNetwork}`);
|
|
1943
2003
|
}
|
|
1944
2004
|
}
|
|
1945
2005
|
|
|
1946
|
-
return
|
|
2006
|
+
return family === 'mainnet' ? 'xna' : 'xna-test';
|
|
1947
2007
|
}
|
|
1948
2008
|
|
|
1949
2009
|
/**
|
|
1950
2010
|
* Validate that addresses match expected network
|
|
1951
2011
|
* @param {string[]} addresses - Array of addresses
|
|
1952
|
-
* @param {string} expectedNetwork - Expected network
|
|
2012
|
+
* @param {string} expectedNetwork - Expected network label
|
|
1953
2013
|
* @returns {boolean} True if all addresses match network
|
|
1954
2014
|
*/
|
|
1955
2015
|
static validateAddressesNetwork(addresses, expectedNetwork) {
|
|
@@ -1959,7 +2019,7 @@ function requireNetworkDetector () {
|
|
|
1959
2019
|
|
|
1960
2020
|
for (const address of addresses) {
|
|
1961
2021
|
const network = this.detectFromAddress(address);
|
|
1962
|
-
if (network
|
|
2022
|
+
if (!areAddressNetworksCompatible(network, expectedNetwork)) {
|
|
1963
2023
|
throw new Error(
|
|
1964
2024
|
`Address ${address} is from ${network} but expected ${expectedNetwork}`
|
|
1965
2025
|
);
|
|
@@ -3311,52 +3371,164 @@ function requireAssetNameValidator () {
|
|
|
3311
3371
|
const { ASSET_NAME_RULES } = requireConstants();
|
|
3312
3372
|
const { InvalidAssetNameError } = requireErrors();
|
|
3313
3373
|
|
|
3374
|
+
const MIN_ASSET_LENGTH = 3;
|
|
3375
|
+
const MAINNET_MAX_NAME_LENGTH = 32;
|
|
3376
|
+
const TESTNET_MAX_NAME_LENGTH = 121;
|
|
3377
|
+
|
|
3378
|
+
const ROOT_NAME_CHARACTERS = /^[A-Z0-9._]{3,}$/;
|
|
3379
|
+
const SUB_NAME_CHARACTERS = /^[A-Z0-9._]+$/;
|
|
3380
|
+
const UNIQUE_TAG_CHARACTERS = /^[-A-Za-z0-9@$%&*()[\]{}_.?:]+$/;
|
|
3381
|
+
const QUALIFIER_NAME_CHARACTERS = /^#[A-Z0-9._]{3,}$/;
|
|
3382
|
+
const SUB_QUALIFIER_NAME_CHARACTERS = /^#[A-Z0-9._]+$/;
|
|
3383
|
+
const RESTRICTED_NAME_CHARACTERS = /^\$[A-Z0-9._]{3,}$/;
|
|
3384
|
+
const DEPIN_NAME_CHARACTERS = /^&[A-Z0-9._]{3,}$/;
|
|
3385
|
+
const SUB_DEPIN_NAME_CHARACTERS = /^&[A-Z0-9._]+\/[A-Z0-9._/]+$/;
|
|
3386
|
+
const DOUBLE_PUNCTUATION = /^.*[._]{2,}.*$/;
|
|
3387
|
+
const LEADING_PUNCTUATION = /^[._].*$/;
|
|
3388
|
+
const TRAILING_PUNCTUATION = /^.*[._]$/;
|
|
3389
|
+
const QUALIFIER_LEADING_PUNCTUATION = /^[#$][._].*$/;
|
|
3390
|
+
const NEURAI_NAMES = /^XNA$|^NEURAI$|^NEURAICOIN$|^#XNA$|^#NEURAI$|^#NEURAICOIN$/;
|
|
3391
|
+
|
|
3392
|
+
function isTestnet(network) {
|
|
3393
|
+
return typeof network === 'string' && network.toLowerCase().includes('test');
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
function getMaxAssetNameLength(network) {
|
|
3397
|
+
return isTestnet(network) ? TESTNET_MAX_NAME_LENGTH : MAINNET_MAX_NAME_LENGTH;
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
function getRootOrSubMaxLength(network) {
|
|
3401
|
+
return getMaxAssetNameLength(network) - 1;
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
function ensureName(name, label) {
|
|
3405
|
+
if (!name || typeof name !== 'string') {
|
|
3406
|
+
throw new InvalidAssetNameError(`${label} must be a non-empty string`, name);
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
function ensureMaxLength(name, maxLength, label) {
|
|
3411
|
+
if (name.length > maxLength) {
|
|
3412
|
+
throw new InvalidAssetNameError(`${label} cannot exceed ${maxLength} characters`, name);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
function ensureUppercase(name, message) {
|
|
3417
|
+
if (name !== name.toUpperCase()) {
|
|
3418
|
+
throw new InvalidAssetNameError(message, name);
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3422
|
+
function isRootNameValid(name) {
|
|
3423
|
+
return ROOT_NAME_CHARACTERS.test(name)
|
|
3424
|
+
&& !DOUBLE_PUNCTUATION.test(name)
|
|
3425
|
+
&& !LEADING_PUNCTUATION.test(name)
|
|
3426
|
+
&& !TRAILING_PUNCTUATION.test(name)
|
|
3427
|
+
&& !NEURAI_NAMES.test(name);
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3430
|
+
function isSubNameValid(name) {
|
|
3431
|
+
return SUB_NAME_CHARACTERS.test(name)
|
|
3432
|
+
&& !DOUBLE_PUNCTUATION.test(name)
|
|
3433
|
+
&& !LEADING_PUNCTUATION.test(name)
|
|
3434
|
+
&& !TRAILING_PUNCTUATION.test(name);
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
function isQualifierNameValid(name) {
|
|
3438
|
+
return QUALIFIER_NAME_CHARACTERS.test(name)
|
|
3439
|
+
&& !DOUBLE_PUNCTUATION.test(name)
|
|
3440
|
+
&& !QUALIFIER_LEADING_PUNCTUATION.test(name)
|
|
3441
|
+
&& !TRAILING_PUNCTUATION.test(name)
|
|
3442
|
+
&& !NEURAI_NAMES.test(name);
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
function isSubQualifierNameValid(name) {
|
|
3446
|
+
return SUB_QUALIFIER_NAME_CHARACTERS.test(name)
|
|
3447
|
+
&& !DOUBLE_PUNCTUATION.test(name)
|
|
3448
|
+
&& !LEADING_PUNCTUATION.test(name)
|
|
3449
|
+
&& !TRAILING_PUNCTUATION.test(name);
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
function isRestrictedNameValid(name) {
|
|
3453
|
+
return RESTRICTED_NAME_CHARACTERS.test(name)
|
|
3454
|
+
&& !DOUBLE_PUNCTUATION.test(name)
|
|
3455
|
+
&& !LEADING_PUNCTUATION.test(name)
|
|
3456
|
+
&& !TRAILING_PUNCTUATION.test(name)
|
|
3457
|
+
&& !NEURAI_NAMES.test(name);
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3460
|
+
function isNameValidBeforeTag(name) {
|
|
3461
|
+
const parts = name.split('/');
|
|
3462
|
+
|
|
3463
|
+
if (!isRootNameValid(parts[0])) {
|
|
3464
|
+
return false;
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
for (let index = 1; index < parts.length; index += 1) {
|
|
3468
|
+
if (!isSubNameValid(parts[index])) {
|
|
3469
|
+
return false;
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3473
|
+
return true;
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
function isQualifierNameValidBeforeTag(name) {
|
|
3477
|
+
const parts = name.split('/');
|
|
3478
|
+
|
|
3479
|
+
if (!isQualifierNameValid(parts[0])) {
|
|
3480
|
+
return false;
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
if (parts.length > 2) {
|
|
3484
|
+
return false;
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3487
|
+
for (let index = 1; index < parts.length; index += 1) {
|
|
3488
|
+
if (!isSubQualifierNameValid(parts[index])) {
|
|
3489
|
+
return false;
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3493
|
+
return true;
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
function isDepinIndicator(name) {
|
|
3497
|
+
return DEPIN_NAME_CHARACTERS.test(name) || SUB_DEPIN_NAME_CHARACTERS.test(name);
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3314
3500
|
class AssetNameValidator {
|
|
3315
3501
|
/**
|
|
3316
3502
|
* Validate ROOT asset name
|
|
3317
|
-
* Rules: 3-
|
|
3318
|
-
* Cannot start with period,
|
|
3503
|
+
* Rules: 3-31 visible characters on mainnet, A-Z, 0-9, underscore, period
|
|
3504
|
+
* Cannot start or end with period/underscore, cannot use repeated punctuation
|
|
3319
3505
|
* Cannot be reserved names
|
|
3320
3506
|
*/
|
|
3321
|
-
static validateRoot(name) {
|
|
3322
|
-
|
|
3323
|
-
throw new InvalidAssetNameError('Asset name must be a non-empty string', name);
|
|
3324
|
-
}
|
|
3507
|
+
static validateRoot(name, network = 'xna') {
|
|
3508
|
+
ensureName(name, 'Asset name');
|
|
3325
3509
|
|
|
3326
|
-
|
|
3327
|
-
|
|
3510
|
+
const maxLength = getRootOrSubMaxLength(network);
|
|
3511
|
+
|
|
3512
|
+
if (name.length < MIN_ASSET_LENGTH || name.length > maxLength) {
|
|
3328
3513
|
throw new InvalidAssetNameError(
|
|
3329
|
-
`ROOT asset name must be ${
|
|
3514
|
+
`ROOT asset name must be ${MIN_ASSET_LENGTH}-${maxLength} characters`,
|
|
3330
3515
|
name
|
|
3331
3516
|
);
|
|
3332
3517
|
}
|
|
3333
3518
|
|
|
3334
|
-
|
|
3335
|
-
if (name !== name.toUpperCase()) {
|
|
3336
|
-
throw new InvalidAssetNameError('Asset name must be uppercase', name);
|
|
3337
|
-
}
|
|
3519
|
+
ensureUppercase(name, 'Asset name must be uppercase');
|
|
3338
3520
|
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
throw new InvalidAssetNameError(
|
|
3342
|
-
`Asset name cannot start with: ${ASSET_NAME_RULES.ROOT.cannotStartWith.join(', ')}`,
|
|
3343
|
-
name
|
|
3344
|
-
);
|
|
3521
|
+
if (NEURAI_NAMES.test(name)) {
|
|
3522
|
+
throw new InvalidAssetNameError(`${name} is a reserved asset name`, name);
|
|
3345
3523
|
}
|
|
3346
3524
|
|
|
3347
|
-
|
|
3348
|
-
if (!ASSET_NAME_RULES.ROOT.pattern.test(name)) {
|
|
3525
|
+
if (!isRootNameValid(name)) {
|
|
3349
3526
|
throw new InvalidAssetNameError(
|
|
3350
|
-
'
|
|
3527
|
+
'Name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (special characters can\'t be the first or last characters)',
|
|
3351
3528
|
name
|
|
3352
3529
|
);
|
|
3353
3530
|
}
|
|
3354
3531
|
|
|
3355
|
-
// Reserved names check
|
|
3356
|
-
if (ASSET_NAME_RULES.ROOT.reserved.includes(name)) {
|
|
3357
|
-
throw new InvalidAssetNameError(`${name} is a reserved asset name`, name);
|
|
3358
|
-
}
|
|
3359
|
-
|
|
3360
3532
|
return true;
|
|
3361
3533
|
}
|
|
3362
3534
|
|
|
@@ -3364,39 +3536,25 @@ function requireAssetNameValidator () {
|
|
|
3364
3536
|
* Validate SUB asset name
|
|
3365
3537
|
* Format: ROOT/SUBNAME
|
|
3366
3538
|
*/
|
|
3367
|
-
static validateSub(name) {
|
|
3368
|
-
|
|
3369
|
-
throw new InvalidAssetNameError('SUB asset name must be a non-empty string', name);
|
|
3370
|
-
}
|
|
3539
|
+
static validateSub(name, network = 'xna') {
|
|
3540
|
+
ensureName(name, 'SUB asset name');
|
|
3371
3541
|
|
|
3372
|
-
|
|
3373
|
-
if (parts.length !== 2) {
|
|
3542
|
+
if (!name.includes(ASSET_NAME_RULES.SUB.separator)) {
|
|
3374
3543
|
throw new InvalidAssetNameError(
|
|
3375
3544
|
`SUB asset must be in ${ASSET_NAME_RULES.SUB.separator} format (ROOT/SUBNAME)`,
|
|
3376
3545
|
name
|
|
3377
3546
|
);
|
|
3378
3547
|
}
|
|
3379
3548
|
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
// Validate root part
|
|
3383
|
-
this.validateRoot(rootName);
|
|
3549
|
+
ensureMaxLength(name, getRootOrSubMaxLength(network), 'SUB asset name');
|
|
3384
3550
|
|
|
3385
|
-
|
|
3386
|
-
if (subName.length < ASSET_NAME_RULES.SUB.minLength || subName.length > ASSET_NAME_RULES.SUB.maxLength) {
|
|
3387
|
-
throw new InvalidAssetNameError(
|
|
3388
|
-
`SUB asset name must be ${ASSET_NAME_RULES.SUB.minLength}-${ASSET_NAME_RULES.SUB.maxLength} characters`,
|
|
3389
|
-
name
|
|
3390
|
-
);
|
|
3391
|
-
}
|
|
3392
|
-
|
|
3393
|
-
if (subName !== subName.toUpperCase()) {
|
|
3551
|
+
if (name !== name.toUpperCase()) {
|
|
3394
3552
|
throw new InvalidAssetNameError('SUB asset name must be uppercase', name);
|
|
3395
3553
|
}
|
|
3396
3554
|
|
|
3397
|
-
if (!
|
|
3555
|
+
if (!isNameValidBeforeTag(name)) {
|
|
3398
3556
|
throw new InvalidAssetNameError(
|
|
3399
|
-
'
|
|
3557
|
+
'Name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (special characters can\'t be the first or last characters)',
|
|
3400
3558
|
name
|
|
3401
3559
|
);
|
|
3402
3560
|
}
|
|
@@ -3408,10 +3566,10 @@ function requireAssetNameValidator () {
|
|
|
3408
3566
|
* Validate UNIQUE asset name
|
|
3409
3567
|
* Format: ROOT#TAG
|
|
3410
3568
|
*/
|
|
3411
|
-
static validateUnique(name) {
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3569
|
+
static validateUnique(name, network = 'xna') {
|
|
3570
|
+
ensureName(name, 'UNIQUE asset name');
|
|
3571
|
+
|
|
3572
|
+
ensureMaxLength(name, getMaxAssetNameLength(network), 'UNIQUE asset name');
|
|
3415
3573
|
|
|
3416
3574
|
const parts = name.split(ASSET_NAME_RULES.UNIQUE.separator);
|
|
3417
3575
|
if (parts.length !== 2) {
|
|
@@ -3423,24 +3581,9 @@ function requireAssetNameValidator () {
|
|
|
3423
3581
|
|
|
3424
3582
|
const [rootName, tag] = parts;
|
|
3425
3583
|
|
|
3426
|
-
|
|
3427
|
-
this.validateRoot(rootName);
|
|
3428
|
-
|
|
3429
|
-
// Validate tag
|
|
3430
|
-
if (tag.length < ASSET_NAME_RULES.UNIQUE.minLength || tag.length > ASSET_NAME_RULES.UNIQUE.maxLength) {
|
|
3431
|
-
throw new InvalidAssetNameError(
|
|
3432
|
-
`UNIQUE tag must be ${ASSET_NAME_RULES.UNIQUE.minLength}-${ASSET_NAME_RULES.UNIQUE.maxLength} characters`,
|
|
3433
|
-
name
|
|
3434
|
-
);
|
|
3435
|
-
}
|
|
3436
|
-
|
|
3437
|
-
if (tag !== tag.toUpperCase()) {
|
|
3438
|
-
throw new InvalidAssetNameError('UNIQUE tag must be uppercase', name);
|
|
3439
|
-
}
|
|
3440
|
-
|
|
3441
|
-
if (!ASSET_NAME_RULES.UNIQUE.pattern.test(tag)) {
|
|
3584
|
+
if (!isNameValidBeforeTag(rootName) || !UNIQUE_TAG_CHARACTERS.test(tag)) {
|
|
3442
3585
|
throw new InvalidAssetNameError(
|
|
3443
|
-
'
|
|
3586
|
+
'Unique name contains invalid characters (Valid characters are: A-Z a-z 0-9 @ $ % & * ( ) [ ] { } _ . ? : -)',
|
|
3444
3587
|
name
|
|
3445
3588
|
);
|
|
3446
3589
|
}
|
|
@@ -3452,10 +3595,8 @@ function requireAssetNameValidator () {
|
|
|
3452
3595
|
* Validate QUALIFIER asset name
|
|
3453
3596
|
* Format: #NAME or #ROOT/SUB
|
|
3454
3597
|
*/
|
|
3455
|
-
static validateQualifier(name) {
|
|
3456
|
-
|
|
3457
|
-
throw new InvalidAssetNameError('QUALIFIER asset name must be a non-empty string', name);
|
|
3458
|
-
}
|
|
3598
|
+
static validateQualifier(name, network = 'xna') {
|
|
3599
|
+
ensureName(name, 'QUALIFIER asset name');
|
|
3459
3600
|
|
|
3460
3601
|
if (!name.startsWith(ASSET_NAME_RULES.QUALIFIER.prefix)) {
|
|
3461
3602
|
throw new InvalidAssetNameError(
|
|
@@ -3464,58 +3605,17 @@ function requireAssetNameValidator () {
|
|
|
3464
3605
|
);
|
|
3465
3606
|
}
|
|
3466
3607
|
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
if (withoutPrefix.includes(ASSET_NAME_RULES.QUALIFIER.separator)) {
|
|
3470
|
-
// Sub-qualifier: #ROOT/SUB
|
|
3471
|
-
const parts = withoutPrefix.split(ASSET_NAME_RULES.QUALIFIER.separator);
|
|
3472
|
-
if (parts.length !== 2) {
|
|
3473
|
-
throw new InvalidAssetNameError(
|
|
3474
|
-
'SUB_QUALIFIER must be in #ROOT/SUB format',
|
|
3475
|
-
name
|
|
3476
|
-
);
|
|
3477
|
-
}
|
|
3478
|
-
|
|
3479
|
-
// Validate each part as a qualifier name (without the #)
|
|
3480
|
-
parts.forEach(part => {
|
|
3481
|
-
if (part.length < ASSET_NAME_RULES.QUALIFIER.minLength || part.length > ASSET_NAME_RULES.QUALIFIER.maxLength) {
|
|
3482
|
-
throw new InvalidAssetNameError(
|
|
3483
|
-
`QUALIFIER name must be ${ASSET_NAME_RULES.QUALIFIER.minLength}-${ASSET_NAME_RULES.QUALIFIER.maxLength} characters`,
|
|
3484
|
-
name
|
|
3485
|
-
);
|
|
3486
|
-
}
|
|
3487
|
-
|
|
3488
|
-
if (part !== part.toUpperCase()) {
|
|
3489
|
-
throw new InvalidAssetNameError('QUALIFIER name must be uppercase', name);
|
|
3490
|
-
}
|
|
3491
|
-
|
|
3492
|
-
if (!ASSET_NAME_RULES.QUALIFIER.pattern.test(part)) {
|
|
3493
|
-
throw new InvalidAssetNameError(
|
|
3494
|
-
'QUALIFIER name can only contain A-Z, 0-9, and underscore',
|
|
3495
|
-
name
|
|
3496
|
-
);
|
|
3497
|
-
}
|
|
3498
|
-
});
|
|
3499
|
-
} else {
|
|
3500
|
-
// Root qualifier: #NAME
|
|
3501
|
-
if (withoutPrefix.length < ASSET_NAME_RULES.QUALIFIER.minLength ||
|
|
3502
|
-
withoutPrefix.length > ASSET_NAME_RULES.QUALIFIER.maxLength) {
|
|
3503
|
-
throw new InvalidAssetNameError(
|
|
3504
|
-
`QUALIFIER name must be ${ASSET_NAME_RULES.QUALIFIER.minLength}-${ASSET_NAME_RULES.QUALIFIER.maxLength} characters`,
|
|
3505
|
-
name
|
|
3506
|
-
);
|
|
3507
|
-
}
|
|
3608
|
+
ensureMaxLength(name, getMaxAssetNameLength(network), 'QUALIFIER asset name');
|
|
3508
3609
|
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3610
|
+
if (name !== name.toUpperCase()) {
|
|
3611
|
+
throw new InvalidAssetNameError('QUALIFIER name must be uppercase', name);
|
|
3612
|
+
}
|
|
3512
3613
|
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
}
|
|
3614
|
+
if (!isQualifierNameValidBeforeTag(name)) {
|
|
3615
|
+
throw new InvalidAssetNameError(
|
|
3616
|
+
'Qualifier name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (# must be the first character, _ . special characters can\'t be the first or last characters)',
|
|
3617
|
+
name
|
|
3618
|
+
);
|
|
3519
3619
|
}
|
|
3520
3620
|
|
|
3521
3621
|
return true;
|
|
@@ -3525,10 +3625,8 @@ function requireAssetNameValidator () {
|
|
|
3525
3625
|
* Validate RESTRICTED asset name
|
|
3526
3626
|
* Format: $NAME
|
|
3527
3627
|
*/
|
|
3528
|
-
static validateRestricted(name) {
|
|
3529
|
-
|
|
3530
|
-
throw new InvalidAssetNameError('RESTRICTED asset name must be a non-empty string', name);
|
|
3531
|
-
}
|
|
3628
|
+
static validateRestricted(name, network = 'xna') {
|
|
3629
|
+
ensureName(name, 'RESTRICTED asset name');
|
|
3532
3630
|
|
|
3533
3631
|
if (!name.startsWith(ASSET_NAME_RULES.RESTRICTED.prefix)) {
|
|
3534
3632
|
throw new InvalidAssetNameError(
|
|
@@ -3537,10 +3635,18 @@ function requireAssetNameValidator () {
|
|
|
3537
3635
|
);
|
|
3538
3636
|
}
|
|
3539
3637
|
|
|
3540
|
-
|
|
3638
|
+
ensureMaxLength(name, getMaxAssetNameLength(network), 'RESTRICTED asset name');
|
|
3541
3639
|
|
|
3542
|
-
|
|
3543
|
-
|
|
3640
|
+
if (name !== name.toUpperCase()) {
|
|
3641
|
+
throw new InvalidAssetNameError('RESTRICTED asset name must be uppercase', name);
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
if (!isRestrictedNameValid(name)) {
|
|
3645
|
+
throw new InvalidAssetNameError(
|
|
3646
|
+
'Restricted name contains invalid characters (Valid characters are: A-Z 0-9 _ .) ($ must be the first character, _ . special characters can\'t be the first or last characters)',
|
|
3647
|
+
name
|
|
3648
|
+
);
|
|
3649
|
+
}
|
|
3544
3650
|
|
|
3545
3651
|
return true;
|
|
3546
3652
|
}
|
|
@@ -3549,10 +3655,8 @@ function requireAssetNameValidator () {
|
|
|
3549
3655
|
* Validate DEPIN asset name
|
|
3550
3656
|
* Format: &NAME or &NAME/SUB[/...]
|
|
3551
3657
|
*/
|
|
3552
|
-
static validateDepin(name) {
|
|
3553
|
-
|
|
3554
|
-
throw new InvalidAssetNameError('DEPIN asset name must be a non-empty string', name);
|
|
3555
|
-
}
|
|
3658
|
+
static validateDepin(name, network) {
|
|
3659
|
+
ensureName(name, 'DEPIN asset name');
|
|
3556
3660
|
|
|
3557
3661
|
if (!name.startsWith(ASSET_NAME_RULES.DEPIN.prefix)) {
|
|
3558
3662
|
throw new InvalidAssetNameError(
|
|
@@ -3561,58 +3665,41 @@ function requireAssetNameValidator () {
|
|
|
3561
3665
|
);
|
|
3562
3666
|
}
|
|
3563
3667
|
|
|
3564
|
-
if (
|
|
3565
|
-
throw new InvalidAssetNameError(
|
|
3566
|
-
`DEPIN asset name cannot exceed ${ASSET_NAME_RULES.DEPIN.maxLength} characters`,
|
|
3567
|
-
name
|
|
3568
|
-
);
|
|
3668
|
+
if (network && !isTestnet(network)) {
|
|
3669
|
+
throw new InvalidAssetNameError('DEPIN assets are only available in testnet', name);
|
|
3569
3670
|
}
|
|
3570
3671
|
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3672
|
+
ensureMaxLength(name, getMaxAssetNameLength(network || 'xna-test'), 'DEPIN asset name');
|
|
3673
|
+
|
|
3674
|
+
if (name !== name.toUpperCase()) {
|
|
3675
|
+
throw new InvalidAssetNameError('DEPIN asset name must be uppercase', name);
|
|
3574
3676
|
}
|
|
3575
3677
|
|
|
3576
|
-
|
|
3577
|
-
if (rootPart.length < ASSET_NAME_RULES.DEPIN.minLength) {
|
|
3678
|
+
if (!isDepinIndicator(name)) {
|
|
3578
3679
|
throw new InvalidAssetNameError(
|
|
3579
|
-
|
|
3680
|
+
'DEPIN asset name can only contain A-Z, 0-9, underscore, period, and separator /',
|
|
3580
3681
|
name
|
|
3581
3682
|
);
|
|
3582
3683
|
}
|
|
3583
3684
|
|
|
3584
|
-
|
|
3585
|
-
throw new InvalidAssetNameError('DEPIN asset name must be uppercase', name);
|
|
3586
|
-
}
|
|
3685
|
+
const parts = name.split(ASSET_NAME_RULES.DEPIN.separator);
|
|
3587
3686
|
|
|
3588
|
-
if (
|
|
3687
|
+
if (parts.length > 1) {
|
|
3688
|
+
parts.forEach(part => {
|
|
3689
|
+
if (part.length < MIN_ASSET_LENGTH) {
|
|
3690
|
+
throw new InvalidAssetNameError(
|
|
3691
|
+
`Each DEPIN sub-part must be at least ${MIN_ASSET_LENGTH} characters`,
|
|
3692
|
+
name
|
|
3693
|
+
);
|
|
3694
|
+
}
|
|
3695
|
+
});
|
|
3696
|
+
} else if (name.length < MIN_ASSET_LENGTH + 1) {
|
|
3589
3697
|
throw new InvalidAssetNameError(
|
|
3590
|
-
|
|
3698
|
+
`DEPIN name must be at least ${MIN_ASSET_LENGTH} characters (excluding &)`,
|
|
3591
3699
|
name
|
|
3592
3700
|
);
|
|
3593
3701
|
}
|
|
3594
3702
|
|
|
3595
|
-
const subParts = parts.slice(1);
|
|
3596
|
-
subParts.forEach(part => {
|
|
3597
|
-
if (part.length < ASSET_NAME_RULES.DEPIN.minLength) {
|
|
3598
|
-
throw new InvalidAssetNameError(
|
|
3599
|
-
`Each DEPIN sub-part must be at least ${ASSET_NAME_RULES.DEPIN.minLength} characters`,
|
|
3600
|
-
name
|
|
3601
|
-
);
|
|
3602
|
-
}
|
|
3603
|
-
|
|
3604
|
-
if (part !== part.toUpperCase()) {
|
|
3605
|
-
throw new InvalidAssetNameError('DEPIN asset name must be uppercase', name);
|
|
3606
|
-
}
|
|
3607
|
-
|
|
3608
|
-
if (!ASSET_NAME_RULES.DEPIN.pattern.test(part)) {
|
|
3609
|
-
throw new InvalidAssetNameError(
|
|
3610
|
-
'DEPIN asset name can only contain A-Z, 0-9, underscore, and period',
|
|
3611
|
-
name
|
|
3612
|
-
);
|
|
3613
|
-
}
|
|
3614
|
-
});
|
|
3615
|
-
|
|
3616
3703
|
return true;
|
|
3617
3704
|
}
|
|
3618
3705
|
|
|
@@ -3620,24 +3707,31 @@ function requireAssetNameValidator () {
|
|
|
3620
3707
|
* Validate owner token name
|
|
3621
3708
|
* Format: ASSETNAME!
|
|
3622
3709
|
*/
|
|
3623
|
-
static validateOwnerToken(name) {
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3710
|
+
static validateOwnerToken(name, network) {
|
|
3711
|
+
ensureName(name, 'Owner token name');
|
|
3712
|
+
|
|
3713
|
+
ensureMaxLength(name, getMaxAssetNameLength(network), 'Owner token name');
|
|
3627
3714
|
|
|
3628
3715
|
if (!name.endsWith('!')) {
|
|
3629
3716
|
throw new InvalidAssetNameError('Owner token must end with !', name);
|
|
3630
3717
|
}
|
|
3631
3718
|
|
|
3632
3719
|
const assetName = name.substring(0, name.length - 1);
|
|
3720
|
+
const validBaseName = isNameValidBeforeTag(assetName)
|
|
3721
|
+
|| (assetName.startsWith('&') && (() => {
|
|
3722
|
+
try {
|
|
3723
|
+
this.validateDepin(assetName, network);
|
|
3724
|
+
return true;
|
|
3725
|
+
} catch (error) {
|
|
3726
|
+
return false;
|
|
3727
|
+
}
|
|
3728
|
+
})());
|
|
3633
3729
|
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
} else {
|
|
3640
|
-
this.validateRoot(assetName);
|
|
3730
|
+
if (!validBaseName) {
|
|
3731
|
+
throw new InvalidAssetNameError(
|
|
3732
|
+
'Owner name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (special characters can\'t be the first or last characters)',
|
|
3733
|
+
name
|
|
3734
|
+
);
|
|
3641
3735
|
}
|
|
3642
3736
|
|
|
3643
3737
|
return true;
|
|
@@ -3648,27 +3742,27 @@ function requireAssetNameValidator () {
|
|
|
3648
3742
|
* @param {string} name - Asset name
|
|
3649
3743
|
* @returns {string} Asset type ('ROOT', 'SUB', 'UNIQUE', 'QUALIFIER', 'RESTRICTED', 'DEPIN', 'OWNER')
|
|
3650
3744
|
*/
|
|
3651
|
-
static validateAndDetectType(name) {
|
|
3745
|
+
static validateAndDetectType(name, network) {
|
|
3652
3746
|
if (name.endsWith('!')) {
|
|
3653
|
-
this.validateOwnerToken(name);
|
|
3747
|
+
this.validateOwnerToken(name, network);
|
|
3654
3748
|
return 'OWNER';
|
|
3655
3749
|
} else if (name.startsWith('#')) {
|
|
3656
|
-
this.validateQualifier(name);
|
|
3750
|
+
this.validateQualifier(name, network);
|
|
3657
3751
|
return name.includes('/') ? 'SUB_QUALIFIER' : 'QUALIFIER';
|
|
3658
3752
|
} else if (name.startsWith('$')) {
|
|
3659
|
-
this.validateRestricted(name);
|
|
3753
|
+
this.validateRestricted(name, network);
|
|
3660
3754
|
return 'RESTRICTED';
|
|
3661
3755
|
} else if (name.startsWith('&')) {
|
|
3662
|
-
this.validateDepin(name);
|
|
3756
|
+
this.validateDepin(name, network);
|
|
3663
3757
|
return 'DEPIN';
|
|
3664
3758
|
} else if (name.includes('#')) {
|
|
3665
|
-
this.validateUnique(name);
|
|
3759
|
+
this.validateUnique(name, network);
|
|
3666
3760
|
return 'UNIQUE';
|
|
3667
3761
|
} else if (name.includes('/')) {
|
|
3668
|
-
this.validateSub(name);
|
|
3762
|
+
this.validateSub(name, network);
|
|
3669
3763
|
return 'SUB';
|
|
3670
3764
|
} else {
|
|
3671
|
-
this.validateRoot(name);
|
|
3765
|
+
this.validateRoot(name, network);
|
|
3672
3766
|
return 'ROOT';
|
|
3673
3767
|
}
|
|
3674
3768
|
}
|
|
@@ -4345,22 +4439,22 @@ function requireBaseAssetTransactionBuilder () {
|
|
|
4345
4439
|
|
|
4346
4440
|
switch (type) {
|
|
4347
4441
|
case 'ROOT':
|
|
4348
|
-
AssetNameValidator.validateRoot(assetName);
|
|
4442
|
+
AssetNameValidator.validateRoot(assetName, this.network);
|
|
4349
4443
|
break;
|
|
4350
4444
|
case 'SUB':
|
|
4351
|
-
AssetNameValidator.validateSub(assetName);
|
|
4445
|
+
AssetNameValidator.validateSub(assetName, this.network);
|
|
4352
4446
|
break;
|
|
4353
4447
|
case 'UNIQUE':
|
|
4354
|
-
AssetNameValidator.validateUnique(assetName);
|
|
4448
|
+
AssetNameValidator.validateUnique(assetName, this.network);
|
|
4355
4449
|
break;
|
|
4356
4450
|
case 'QUALIFIER':
|
|
4357
|
-
AssetNameValidator.validateQualifier(assetName);
|
|
4451
|
+
AssetNameValidator.validateQualifier(assetName, this.network);
|
|
4358
4452
|
break;
|
|
4359
4453
|
case 'RESTRICTED':
|
|
4360
|
-
AssetNameValidator.validateRestricted(assetName);
|
|
4454
|
+
AssetNameValidator.validateRestricted(assetName, this.network);
|
|
4361
4455
|
break;
|
|
4362
4456
|
case 'DEPIN':
|
|
4363
|
-
AssetNameValidator.validateDepin(assetName);
|
|
4457
|
+
AssetNameValidator.validateDepin(assetName, this.network);
|
|
4364
4458
|
break;
|
|
4365
4459
|
default:
|
|
4366
4460
|
throw new Error(`Unknown asset type: ${type}`);
|
|
@@ -5781,7 +5875,7 @@ function requireIssueUniqueBuilder () {
|
|
|
5781
5875
|
*
|
|
5782
5876
|
* QUALIFIER assets:
|
|
5783
5877
|
* - KYC/compliance tags (e.g., #KYC_VERIFIED, #ACCREDITED)
|
|
5784
|
-
* - Format: #NAME or #ROOT
|
|
5878
|
+
* - Format: #NAME or #ROOT/#SUB
|
|
5785
5879
|
* - Cost: 2000 XNA (root) or 200 XNA (sub-qualifier)
|
|
5786
5880
|
* - Quantity: 1-10 units only
|
|
5787
5881
|
* - Units: Always 0 (non-divisible)
|
|
@@ -7246,7 +7340,7 @@ function requireNeuraiAssets () {
|
|
|
7246
7340
|
/**
|
|
7247
7341
|
* Create a ROOT asset
|
|
7248
7342
|
* @param {object} params - Asset creation parameters
|
|
7249
|
-
|
|
7343
|
+
* @param {string} params.assetName - Asset name (3-31 visible chars on mainnet, A-Z 0-9 _ .)
|
|
7250
7344
|
* @param {number} params.quantity - Total supply
|
|
7251
7345
|
* @param {number} [params.units=0] - Decimal places (0-8)
|
|
7252
7346
|
* @param {boolean} [params.reissuable=true] - Can mint more later
|