@pioneer-platform/pioneer-coins 9.2.26 → 9.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/paths.js CHANGED
@@ -72,7 +72,7 @@ function getPaths(blockchains, isTestnet) {
72
72
  else {
73
73
  //legacy bip44
74
74
  output.push({
75
- note: "Bitcoin legacy account 0",
75
+ note: "Bitcoin account 0",
76
76
  networks: ['bip122:000000000019d6689c085ae165831e93'],
77
77
  script_type: "p2pkh",
78
78
  available_scripts_types: ['p2pkh', 'p2sh', 'p2wpkh', 'p2sh-p2wpkh'],
@@ -82,6 +82,7 @@ function getPaths(blockchains, isTestnet) {
82
82
  curve: 'secp256k1',
83
83
  showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
84
84
  });
85
+ //TODO non-native segwit wraped p2sh
85
86
  output.push({
86
87
  note: "Bitcoin account 0 Segwit (p2sh-p2wpkh) (ypub) (bip49)",
87
88
  networks: ['bip122:000000000019d6689c085ae165831e93'],
@@ -105,84 +106,12 @@ function getPaths(blockchains, isTestnet) {
105
106
  curve: 'secp256k1',
106
107
  showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
107
108
  });
108
- //account 1
109
- output.push({
110
- note: "Bitcoin legacy account 1",
111
- networks: ['bip122:000000000019d6689c085ae165831e93'],
112
- script_type: "p2pkh",
113
- available_scripts_types: ['p2pkh', 'p2sh', 'p2wpkh', 'p2sh-p2wpkh'],
114
- type: "xpub",
115
- addressNList: [0x80000000 + 44, 0x80000000 + 0, 0x80000000 + 1],
116
- addressNListMaster: [0x80000000 + 44, 0x80000000 + 0, 0x80000000 + 1, 0, 0],
117
- curve: 'secp256k1',
118
- showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
119
- });
120
- output.push({
121
- note: "Bitcoin account 1 Segwit (p2sh-p2wpkh) (ypub) (bip49)",
122
- networks: ['bip122:000000000019d6689c085ae165831e93'],
123
- script_type: "p2sh-p2wpkh",
124
- available_scripts_types: ['p2pkh', 'p2sh', 'p2wpkh', 'p2sh-p2wpkh'],
125
- type: "ypub",
126
- addressNList: [0x80000000 + 49, 0x80000000 + 0, 0x80000000 + 1],
127
- addressNListMaster: [0x80000000 + 49, 0x80000000 + 0, 0x80000000 + 1, 0, 0],
128
- curve: 'secp256k1',
129
- showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
130
- });
131
- //bech32 bip84
132
- output.push({
133
- note: "Bitcoin account 1Native Segwit (Bech32)",
134
- networks: ['bip122:000000000019d6689c085ae165831e93'],
135
- script_type: "p2wpkh", //bech32
136
- available_scripts_types: ['p2pkh', 'p2sh', 'p2wpkh', 'p2sh-p2wpkh'],
137
- type: "zpub",
138
- addressNList: [0x80000000 + 84, 0x80000000 + 0, 0x80000000 + 1],
139
- addressNListMaster: [0x80000000 + 84, 0x80000000 + 0, 0x80000000 + 1, 0, 0],
140
- curve: 'secp256k1',
141
- showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
142
- });
143
- //account 2
144
- output.push({
145
- note: "Bitcoin legacy account 2",
146
- networks: ['bip122:000000000019d6689c085ae165831e93'],
147
- script_type: "p2pkh",
148
- available_scripts_types: ['p2pkh', 'p2sh', 'p2wpkh', 'p2sh-p2wpkh'],
149
- type: "xpub",
150
- addressNList: [0x80000000 + 44, 0x80000000 + 0, 0x80000000 + 2],
151
- addressNListMaster: [0x80000000 + 44, 0x80000000 + 0, 0x80000000 + 2, 0, 0],
152
- curve: 'secp256k1',
153
- showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
154
- });
155
- output.push({
156
- note: "Bitcoin account 1 Segwit (p2sh-p2wpkh) (ypub) (bip49)",
157
- networks: ['bip122:000000000019d6689c085ae165831e93'],
158
- script_type: "p2sh-p2wpkh",
159
- available_scripts_types: ['p2pkh', 'p2sh', 'p2wpkh', 'p2sh-p2wpkh'],
160
- type: "ypub",
161
- addressNList: [0x80000000 + 49, 0x80000000 + 0, 0x80000000 + 2],
162
- addressNListMaster: [0x80000000 + 49, 0x80000000 + 0, 0x80000000 + 2, 0, 0],
163
- curve: 'secp256k1',
164
- showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
165
- });
166
- //bech32 bip84
167
- output.push({
168
- note: "Bitcoin account 1Native Segwit (Bech32)",
169
- networks: ['bip122:000000000019d6689c085ae165831e93'],
170
- script_type: "p2wpkh", //bech32
171
- available_scripts_types: ['p2pkh', 'p2sh', 'p2wpkh', 'p2sh-p2wpkh'],
172
- type: "zpub",
173
- addressNList: [0x80000000 + 84, 0x80000000 + 0, 0x80000000 + 2],
174
- addressNListMaster: [0x80000000 + 84, 0x80000000 + 0, 0x80000000 + 2, 0, 0],
175
- curve: 'secp256k1',
176
- showDisplay: false // Not supported by TrezorConnect or Ledger, but KeepKey should do it
177
- });
178
- //account 0-2 parity with ShapeShift legacy
179
109
  }
180
110
  }
181
111
  if (blockchains.some(function (blockchain) { return blockchain.includes('eip155:'); })) {
182
112
  var entry = {
183
113
  note: " ETH primary (default)",
184
114
  networks: ['eip155:1', 'eip155:*'],
185
- script_type: "ethereum",
186
115
  type: "address",
187
116
  addressNList: [0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0],
188
117
  addressNListMaster: [0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0],
@@ -3,6 +3,8 @@ interface BaseTx {
3
3
  asset: string;
4
4
  destAddr: string;
5
5
  }
6
+ export declare function validateMemo(memo: string): boolean;
7
+ export declare function normalizeSwapMemo(memo: string): string;
6
8
  export declare function createMemo(tx: BaseTx): string;
7
9
  export declare function parseMemo(memo: string): BaseTx;
8
10
  export {};
package/lib/thorchain.js CHANGED
@@ -4,6 +4,8 @@
4
4
  ----------------------
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.validateMemo = validateMemo;
8
+ exports.normalizeSwapMemo = normalizeSwapMemo;
7
9
  exports.createMemo = createMemo;
8
10
  exports.parseMemo = parseMemo;
9
11
  var assetShortCodeMap = {
@@ -35,28 +37,24 @@ var assetShortCodeMap = {
35
37
  function interpretAssetShortCode(shortCode) {
36
38
  return assetShortCodeMap[shortCode] || shortCode;
37
39
  }
38
- // Utility function to interpret other shortened parts (e.g., scientific notation)
40
+ // Utility function to interpret shortened parts (parsing only, no sci notation)
39
41
  function interpretShortenedPart(part) {
40
- if (part.includes('e')) {
41
- var _a = part.split('e').map(Number), base = _a[0], exponent = _a[1];
42
- return base * Math.pow(10, exponent);
43
- }
42
+ // No scientific notation in THORChain memos - keep as is
44
43
  return part;
45
44
  }
46
45
  // Function to build an Aggregate Swap transaction memo
47
46
  function buildAggregateSwapMemo(tx) {
48
- var _a;
49
- var limIntervalQuantity = "".concat(tx.lim || '', "/").concat(tx.interval || '', "/").concat(tx.quantity || '');
47
+ var limInterval = "".concat(tx.lim || '', "/").concat(tx.interval || '');
50
48
  var parts = [
51
49
  'SWAP',
52
50
  tx.asset,
53
51
  tx.destAddr,
54
- limIntervalQuantity,
52
+ limInterval,
55
53
  tx.affiliate || '',
56
- ((_a = tx.fee) === null || _a === void 0 ? void 0 : _a.toString()) || '',
54
+ tx.fee || '',
57
55
  tx.dexAggregatorAddr,
58
56
  tx.finalAssetAddr,
59
- tx.minAmountOut.toString()
57
+ tx.minAmountOut || ''
60
58
  ];
61
59
  return truncateMemo(parts.join(':'));
62
60
  }
@@ -70,43 +68,29 @@ function truncateMemo(memo, limit) {
70
68
  }
71
69
  return memo;
72
70
  }
73
- // Utility function for converting numbers to scientific notation if needed
74
- function toScientificNotation(number) {
75
- if (number > 1000000) { // Adjust the threshold as needed
76
- var exponent = Math.floor(Math.log10(number));
77
- var base = number / Math.pow(10, exponent);
78
- return "".concat(base.toFixed(1), "e").concat(exponent);
79
- }
80
- return number.toString();
81
- }
71
+ // Removed toScientificNotation - THORChain requires plain integers
82
72
  // Function to build a Swap transaction memo
83
73
  function buildSwapMemo(tx) {
84
- var assetShort = Object.keys(assetShortCodeMap).find(function (key) { return assetShortCodeMap[key] === tx.asset; }) || tx.asset;
85
- var parts = [
86
- '=', // Shorthand for SWAP
87
- assetShort,
88
- tx.destAddr
89
- ];
90
- // Handle lim, interval, and quantity
91
- if (tx.lim || tx.interval || tx.quantity) {
92
- var lim = tx.lim ? toScientificNotation(tx.lim) : '';
93
- var interval = tx.interval ? toScientificNotation(tx.interval) : '';
94
- var quantity = tx.quantity ? toScientificNotation(tx.quantity) : '';
95
- parts.push("".concat(lim, "/").concat(interval, "/").concat(quantity));
74
+ // Always emit fully-qualified CHAIN.SYMBOL - never shorthand
75
+ var assetFQ = tx.asset; // e.g. 'BTC.BTC', 'ETH.ETH'
76
+ var parts = ['=', assetFQ, tx.destAddr];
77
+ // Handle lim and interval (no quantity in standard swap)
78
+ if (tx.lim !== undefined || tx.interval !== undefined) {
79
+ // Integers only, no sci-notation
80
+ var lim = tx.lim !== undefined ? String(tx.lim) : '';
81
+ var interval = tx.interval !== undefined ? String(tx.interval) : '';
82
+ parts.push("".concat(lim).concat(interval ? '/' + interval : ''));
96
83
  }
97
84
  else {
98
- parts.push(''); // Add an empty string to represent missing lim/interval/quantity
85
+ parts.push(''); // Add empty string for missing lim/interval
99
86
  }
100
- // Append other parts, handling empty fields appropriately
101
- parts.push(tx.affiliate || '');
102
- parts.push(tx.fee ? toScientificNotation(tx.fee) : '');
103
- parts.push(tx.dexAggregatorAddr || '');
104
- parts.push(tx.finalAssetAddr || '');
105
- parts.push(tx.minAmountOut ? toScientificNotation(tx.minAmountOut) : '');
106
- // Join parts with ':' and correctly handle empty fields
87
+ // Base swap supports optional affiliate tag + bp (basis points 0..1000)
88
+ if (tx.affiliate !== undefined)
89
+ parts.push(tx.affiliate);
90
+ if (tx.fee !== undefined)
91
+ parts.push(String(tx.fee)); // basis points
107
92
  var memo = parts.join(':');
108
- memo = memo.replace(/:{2,}/g, '::'); // Replace multiple colons with double colons
109
- memo = memo.replace(/:+$/, ''); // Remove trailing colons
93
+ memo = memo.replace(/:{2,}/g, '::').replace(/:+$/, '');
110
94
  return truncateMemo(memo);
111
95
  }
112
96
  // Function to build a Deposit transaction memo
@@ -216,6 +200,102 @@ function buildNoOpMemo(tx) {
216
200
  return truncateMemo(parts.filter(function (part) { return part; }).join(':'));
217
201
  }
218
202
  // Main function to create a memo from any transaction type
203
+ // Validate a THORChain memo - returns true if valid, false otherwise
204
+ function validateMemo(memo) {
205
+ try {
206
+ if (!memo || memo.trim() === '')
207
+ return false;
208
+ var trimmed = memo.trim();
209
+ // Check basic format
210
+ if (!trimmed.startsWith('=:') && !trimmed.startsWith('SWAP:') &&
211
+ !trimmed.startsWith('DEPOSIT:') && !trimmed.startsWith('WITHDRAW:') &&
212
+ !trimmed.startsWith('LOAN+:') && !trimmed.startsWith('LOAN-:') &&
213
+ !trimmed.startsWith('ADD:') && !trimmed.startsWith('WD:') &&
214
+ !trimmed.startsWith('BOND:') && !trimmed.startsWith('UNBOND:') &&
215
+ !trimmed.startsWith('MIGRATE:') && !trimmed.startsWith('*NOOP*:')) {
216
+ return false;
217
+ }
218
+ // For swap memos, validate format more strictly
219
+ if (trimmed.startsWith('=:') || trimmed.startsWith('SWAP:')) {
220
+ var prefix = trimmed.startsWith('=:') ? '=:' : 'SWAP:';
221
+ var parts = trimmed.slice(prefix.length).split(':');
222
+ // Must have at least asset and destination
223
+ if (parts.length < 2)
224
+ return false;
225
+ // Check asset format (must be CHAIN.SYMBOL)
226
+ var asset = parts[0];
227
+ // Don't allow single-letter shorthands in validation
228
+ if (asset.length === 1)
229
+ return false;
230
+ var assetParts = asset.split('.');
231
+ if (assetParts.length !== 2)
232
+ return false;
233
+ var chain = assetParts[0], symbol = assetParts[1];
234
+ // Must be uppercase alphanumeric (symbol can have dash)
235
+ if (!/^[A-Z0-9]+$/.test(chain))
236
+ return false;
237
+ if (!/^[A-Z0-9\-]+$/.test(symbol))
238
+ return false;
239
+ // Must have destination
240
+ var destination = parts[1];
241
+ if (!destination || destination.trim() === '')
242
+ return false;
243
+ // Check optional limit/stream format
244
+ if (parts[2] && parts[2] !== '') {
245
+ var limitStream = parts[2].split('/');
246
+ // Limit must be integer if present
247
+ if (limitStream[0] && !/^\d+$/.test(limitStream[0]))
248
+ return false;
249
+ // Stream must be integer if present
250
+ if (limitStream[1] && !/^\d+$/.test(limitStream[1]))
251
+ return false;
252
+ }
253
+ // Check affiliate BP if present
254
+ if (parts[4] && parts[4] !== '') {
255
+ if (!/^\d+$/.test(parts[4]))
256
+ return false;
257
+ var bp = parseInt(parts[4]);
258
+ if (bp < 0 || bp > 1000)
259
+ return false;
260
+ }
261
+ }
262
+ // Check memo length
263
+ if (Buffer.from(trimmed, 'utf-8').length > 250)
264
+ return false;
265
+ // If we made it here, memo is valid
266
+ return true;
267
+ }
268
+ catch (error) {
269
+ // Any error means invalid memo
270
+ return false;
271
+ }
272
+ }
273
+ // Normalize and validate swap memo
274
+ function normalizeSwapMemo(memo) {
275
+ // Ensure "=:" prefix and fully qualified asset
276
+ if (!memo.startsWith('=:')) {
277
+ if (memo.startsWith('='))
278
+ memo = memo.replace(/^=/, '=:');
279
+ else if (memo.startsWith('SWAP:'))
280
+ memo = memo.replace(/^SWAP:/, '=:');
281
+ }
282
+ var parts = memo.slice(2).split(':');
283
+ if (parts.length < 2)
284
+ throw new Error('Memo missing asset/destination');
285
+ // Expand single-letter shorthand if present (parse-time convenience only)
286
+ var cs = parts[0];
287
+ var fix = assetShortCodeMap[cs] || assetShortCodeMap[cs.toUpperCase()];
288
+ if (fix)
289
+ parts[0] = fix;
290
+ // Enforce UPPERCASE CHAIN.SYMBOL
291
+ var _a = parts[0].split('.'), chain = _a[0], symbol = _a[1];
292
+ if (!chain || !symbol)
293
+ throw new Error('Asset must be CHAIN.SYMBOL');
294
+ parts[0] = "".concat(chain.toUpperCase(), ".").concat(symbol.toUpperCase());
295
+ var normalized = "=:" + parts.join(':');
296
+ // guard length
297
+ return truncateMemo(normalized, 250);
298
+ }
219
299
  function createMemo(tx) {
220
300
  switch (tx.type) {
221
301
  case 'SWAP':
@@ -264,19 +344,15 @@ function parseMemo(memo) {
264
344
  case 'SWAP': {
265
345
  var asset_1 = parts[1];
266
346
  var destAddr_1 = parts[2];
267
- var _a = parts[3].split('/'), lim = _a[0], interval = _a[1], quantity = _a[2];
347
+ var _a = (parts[3] || '').split('/'), lim = _a[0], interval = _a[1];
268
348
  return {
269
- type: 'SWAP', // Type of the transaction
270
- asset: asset_1, // Asset being swapped
271
- destAddr: destAddr_1, // Destination address
272
- lim: lim ? parseInt(lim) : null, // Limit (optional, null if not provided)
273
- interval: interval ? parseInt(interval) : null, // Interval (optional)
274
- quantity: quantity ? parseInt(quantity) : null, // Quantity (optional)
275
- affiliate: parts[4] || null, // Affiliate (optional)
276
- fee: parts[5] ? parseFloat(parts[5]) : null, // Fee (optional)
277
- dexAggregatorAddr: parts[6] || null, // DEX aggregator address (optional)
278
- finalAssetAddr: parts[7] || null, // Final asset address (optional)
279
- minAmountOut: parts[8] ? parseInt(parts[8]) : null, // Minimum amount out (optional)
349
+ type: 'SWAP',
350
+ asset: asset_1,
351
+ destAddr: destAddr_1,
352
+ lim: lim || undefined, // keep as string
353
+ interval: interval || undefined, // keep as string
354
+ affiliate: parts[4] || undefined,
355
+ fee: parts[5] || undefined, // keep as string (bp)
280
356
  };
281
357
  }
282
358
  case 'DEPOSIT':
@@ -355,58 +431,21 @@ function parseMemo(memo) {
355
431
  noVault: parts[1] === 'NOVAULT',
356
432
  };
357
433
  case 'AGGREGATE_SWAP': {
358
- var _b = parts[3].split('/'), lim = _b[0], interval = _b[1], quantity = _b[2];
359
- return {
360
- type: 'SWAP', // Using 'SWAP' as the type for consistency
361
- asset: asset,
362
- destAddr: destAddr,
363
- lim: lim ? parseInt(lim) : null,
364
- interval: interval ? parseInt(interval) : null,
365
- quantity: quantity ? parseInt(quantity) : null,
366
- affiliate: parts[4] || null,
367
- fee: parts[5] ? parseFloat(parts[5]) : null,
368
- dexAggregatorAddr: parts[6],
369
- finalAssetAddr: parts[7],
370
- minAmountOut: parts[8] ? parseInt(parts[8]) : null,
371
- };
372
- }
373
- case 'LOAN+': {
374
- var minOut = parts[3] ? parseInt(parts[3]) : null;
375
- return {
376
- type: type,
377
- asset: asset,
378
- destAddr: destAddr,
379
- minOut: minOut,
380
- affiliate: parts[4] || null,
381
- fee: parts[5] ? parseFloat(parts[5]) : null,
382
- };
383
- }
384
- case 'LOAN-': {
385
- var minOut = parts[3] ? parseInt(parts[3]) : null;
434
+ var _b = (parts[3] || '').split('/'), lim = _b[0], interval = _b[1];
386
435
  return {
387
- type: type,
436
+ type: 'AGGREGATE_SWAP',
388
437
  asset: asset,
389
438
  destAddr: destAddr,
390
- minOut: minOut,
391
- };
392
- }
393
- case 'ADD': {
394
- return {
395
- type: type,
396
- asset: asset,
397
- pairedAddr: parts[3] || null,
398
- affiliate: parts[4] || null,
399
- fee: parts[5] ? parseFloat(parts[5]) : null,
400
- };
401
- }
402
- case 'WD': {
403
- return {
404
- type: type,
405
- asset: asset,
406
- basisPoints: parseInt(parts[3]),
407
- singleAsset: parts[4] || null,
439
+ lim: lim || undefined,
440
+ interval: interval || undefined,
441
+ affiliate: parts[4] || undefined,
442
+ fee: parts[5] || undefined,
443
+ dexAggregatorAddr: parts[6] || '',
444
+ finalAssetAddr: parts[7] || '',
445
+ minAmountOut: parts[8] || undefined,
408
446
  };
409
447
  }
448
+ // Removed duplicate cases - already handled above
410
449
  default:
411
450
  throw new Error("Unsupported memo type: ".concat(type));
412
451
  }
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@pioneer-platform/pioneer-coins",
3
- "version": "9.2.26",
3
+ "version": "9.3.1",
4
4
  "main": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "_moduleAliases": {
7
7
  "@coins": "lib/coins"
8
8
  },
9
9
  "scripts": {
10
- "npm": "npm i",
10
+ "npm": "pnpm i",
11
11
  "build": "tsc -p .",
12
- "test": "npm run build && node __tests__/test-module.js",
13
- "test-suite": "npm run build && node __tests__/tests-common.js",
14
- "build:watch": "npm run build && onchange 'src/**/*.ts' -- npm run build",
15
- "prepublish": "npm run build"
12
+ "test": "pnpm run build && node __tests__/test-module.js",
13
+ "test-suite": "pnpm run build && node __tests__/tests-common.js",
14
+ "build:watch": "pnpm run build && onchange 'src/**/*.ts' -- pnpm run build",
15
+ "prepublish": "pnpm run build"
16
16
  },
17
17
  "dependencies": {
18
18
  "@pioneer-platform/loggerdog": "^8.3.1",
@@ -21,9 +21,9 @@
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/express": "^4.17.6",
24
- "@types/node": "18.19.71",
24
+ "@types/node": "^18.16.0",
25
25
  "nodemon": "^2.0.3",
26
- "typescript": "^5.0.2"
26
+ "typescript": "^5.0.4"
27
27
  },
28
28
  "gitHead": "a76012f6693a12181c4744e53e977a9eaeef0ed3"
29
- }
29
+ }