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