@pioneer-platform/maya-network 8.11.1 → 8.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @pioneer-platform/maya-network
2
2
 
3
+ ## 8.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Migrate MayaChain network module to Unchained API
8
+
9
+ - Replace direct node calls with ShapeShift Unchained API
10
+ - Remove verbose error logging and 503 spam
11
+ - Add proper timeouts to all requests (5-10s)
12
+ - Reduce code size by 50% (646 → 320 lines)
13
+ - Improve reliability and performance
14
+ - Keep Midgard API for pool data only
15
+ - Add comprehensive test suite and documentation
16
+
3
17
  ## 8.11.1
4
18
 
5
19
  ### Patch Changes
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # MayaChain Network Module
2
+
3
+ MayaChain network integration using ShapeShift Unchained API.
4
+
5
+ ## Architecture
6
+
7
+ This module has been migrated from direct MayaChain node calls to use the Unchained API for better reliability and reduced node connection errors.
8
+
9
+ ### API Endpoints
10
+
11
+ **Primary: ShapeShift Unchained API**
12
+ - Base URL: `https://api.mayachain.shapeshift.com`
13
+ - Documentation: https://api.mayachain.shapeshift.com/swagger
14
+ - Provides: Account info, balances, transaction history, broadcasting
15
+
16
+ **Fallback: Midgard API**
17
+ - Base URL: `https://midgard.mayachain.info/v2`
18
+ - Provides: Pool data, aggregated chain statistics
19
+ - Used for: Pool queries not available in Unchained
20
+
21
+ ## Features
22
+
23
+ ### ✅ Implemented via Unchained
24
+ - `getInfo()` - Network information
25
+ - `getAccount(address)` - Account details with balances
26
+ - `getBalance(address)` - Single CACAO balance
27
+ - `getBalances(address)` - All asset balances
28
+ - `txs(address, cursor, pageSize)` - Paginated transaction history
29
+ - `broadcast(rawTx)` - Transaction broadcasting
30
+
31
+ ### ✅ Implemented via Midgard
32
+ - `getPools()` - All liquidity pools
33
+ - `getPool(poolId)` - Specific pool details
34
+
35
+ ### ⚠️ Not Available in Unchained
36
+ - `getTransaction(txid)` - Direct tx lookup (use account txs instead)
37
+ - `getPoolAddress()` - Inbound addresses (requires node access)
38
+
39
+ ## Usage
40
+
41
+ ```javascript
42
+ const network = require('@pioneer-platform/mayachain-network')
43
+
44
+ // Get network info
45
+ const info = await network.info()
46
+
47
+ // Get account balances
48
+ const balances = await network.getBalances('maya1...')
49
+
50
+ // Get transaction history (paginated)
51
+ const txs = await network.txs('maya1...', undefined, 50)
52
+
53
+ // Broadcast transaction
54
+ const result = await network.broadcast(signedTxBase64)
55
+ ```
56
+
57
+ ## Balance Formats
58
+
59
+ The module returns balances in standardized format:
60
+
61
+ ```javascript
62
+ [
63
+ {
64
+ denom: 'cacao', // Asset denomination
65
+ amountBase: '25029714637', // Raw amount (base units)
66
+ amount: 25.029714637, // Decimal amount
67
+ decimals: 10 // Decimal places
68
+ },
69
+ {
70
+ denom: 'maya',
71
+ amountBase: '4104',
72
+ amount: 0.4104,
73
+ decimals: 4
74
+ }
75
+ ]
76
+ ```
77
+
78
+ ### Decimal Places
79
+ - **CACAO**: 10 decimals (1 CACAO = 10,000,000,000 base units)
80
+ - **MAYA**: 4 decimals (1 MAYA = 10,000 base units)
81
+
82
+ ## Error Handling
83
+
84
+ The module uses minimal logging with retry logic:
85
+ - 2 retries on 503 errors with exponential backoff
86
+ - Logs only errors and key operations (no verbose stack traces)
87
+ - Returns structured error responses for broadcast failures
88
+
89
+ ## Migration Notes
90
+
91
+ ### Changes from Previous Version
92
+ 1. ✅ Removed direct node calls to `mayanode.mayachain.info`
93
+ 2. ✅ Removed verbose error logging (no more giant stack traces)
94
+ 3. ✅ Uses Unchained API for account/balance/tx operations
95
+ 4. ✅ Keeps Midgard for pool data (not in Unchained)
96
+ 5. ✅ Simplified retry logic with minimal logging
97
+
98
+ ### Benefits
99
+ - **Reliability**: Unchained API is more stable than direct node access
100
+ - **Performance**: Faster responses, better caching
101
+ - **Cleaner logs**: No more 503 spam in logs
102
+ - **Maintainability**: Single API contract vs multiple node endpoints
103
+
104
+ ## Testing
105
+
106
+ ```bash
107
+ cd modules/coins/mayachain/mayachain-network
108
+ bun run test
109
+ ```
110
+
111
+ Test coverage:
112
+ - ✅ Network info retrieval
113
+ - ✅ Account balance queries
114
+ - ✅ Multi-asset balance parsing
115
+ - ✅ Transaction history (paginated)
116
+ - ✅ Pool data from Midgard
117
+ - 💬 Broadcasting (commented out - needs real signed tx)
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ # Build
123
+ bun run build
124
+
125
+ # Test
126
+ bun run test
127
+
128
+ # Install dependencies
129
+ bun install
130
+ ```
131
+
132
+ ## Dependencies
133
+
134
+ - `axios` - HTTP client
135
+ - `axios-retry` - Retry logic for 503 errors
136
+ - `@pioneer-platform/loggerdog` - Logging
137
+
138
+ ## License
139
+
140
+ MIT
package/lib/index.d.ts CHANGED
@@ -1,34 +1,23 @@
1
- declare const TAG = " | thorchain-api | ";
2
- declare const prettyjson: any;
1
+ declare const TAG = " | mayachain-api | ";
2
+ declare const log: any;
3
3
  declare const axiosLib: any;
4
- declare const Axios: any;
5
- declare const https: any;
6
4
  declare const axios: any;
5
+ declare const https: any;
6
+ declare const axiosInstance: any;
7
7
  declare const axiosRetry: any;
8
- declare const log: any;
9
- declare let URL_THORNODE: string;
10
- declare let URL_MIDGARD: string;
11
- declare const NOWNODES_ENDPOINTS: string[];
12
- declare const UNCHAINED_ENDPOINT = "https://api.mayachain.shapeshift.com";
13
- declare let BASE_THOR: number;
8
+ declare const UNCHAINED_API = "https://api.mayachain.shapeshift.com";
9
+ declare const MIDGARD_API = "https://midgard.mayachain.info/v2";
10
+ declare const BASE_MAYA = 10000000000;
14
11
  /**********************************
15
- // Lib
12
+ // Implementation
16
13
  //**********************************/
14
+ declare const get_info: () => Promise<any>;
15
+ declare const get_account_info: (address: string) => Promise<any>;
16
+ declare const get_balance: (address: string) => Promise<number>;
17
+ declare const get_balances: (address: string) => Promise<any[]>;
18
+ declare const get_txs_by_address: (address: string, cursor?: string, pageSize?: number) => Promise<any>;
19
+ declare const get_transaction: (txid: string) => Promise<never>;
20
+ declare const broadcast_transaction: (tx: string) => Promise<any>;
17
21
  declare const get_pool: (poolId: string) => Promise<any>;
18
22
  declare const get_pools: () => Promise<any>;
19
- declare const get_pool_addresses: () => Promise<any>;
20
- declare let get_last_block: () => Promise<any>;
21
- declare let get_block_height: () => Promise<any>;
22
- declare let get_transaction: (txid: string) => Promise<any>;
23
- declare let broadcast_transaction: (tx: string) => Promise<any>;
24
- declare let get_account_info: (address: string) => Promise<any>;
25
- declare let normalize_tx: (tx: any, address?: string) => any;
26
- declare let get_txs_by_address: (address: string) => Promise<any>;
27
- declare let get_balance: (address: string) => Promise<number>;
28
- declare let get_balances: (address: string) => Promise<{
29
- denom: any;
30
- amountBase: any;
31
- amount: number;
32
- decimals: number;
33
- }[]>;
34
- declare let get_node_info_verbose: () => Promise<any>;
23
+ declare const get_pool_addresses: () => Promise<never>;
package/lib/index.js CHANGED
@@ -1,4 +1,10 @@
1
1
  "use strict";
2
+ /*
3
+ MayaChain Network Module - Unchained API Integration
4
+
5
+ Migrated from direct node calls to ShapeShift Unchained API
6
+ API Documentation: https://api.mayachain.shapeshift.com/swagger
7
+ */
2
8
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
9
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
10
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -35,68 +41,39 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
41
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
42
  }
37
43
  };
38
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
- if (ar || !(i in from)) {
41
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
42
- ar[i] = from[i];
43
- }
44
- }
45
- return to.concat(ar || Array.prototype.slice.call(from));
46
- };
47
- /*
48
- const thorMainnetClient: CosmosSDKClient = new CosmosSDKClient({
49
- server: 'http://104.248.96.152:1317',
50
- chainId: 'thorchain',
51
- prefix: 'thor',
52
- derive_path: "44'/931'/0'/0/0",
53
- })
54
-
55
-
56
- get nodes
57
- curl https://testnet-seed.thorchain.info
58
-
59
- //testnet
60
- https://main.d3mbd42yfy75lz.amplifyapp.com/#/nodes
61
-
62
- */
63
- var TAG = " | thorchain-api | ";
64
- var prettyjson = require('prettyjson');
65
- require("dotenv").config({ path: '../../../.env' });
44
+ var TAG = " | mayachain-api | ";
45
+ var log = require('@pioneer-platform/loggerdog')();
66
46
  var axiosLib = require('axios');
67
- var Axios = axiosLib.default || axiosLib;
47
+ var axios = axiosLib.default || axiosLib;
68
48
  var https = require('https');
69
- var axios = Axios.create({
49
+ // Create axios instance with retry logic but minimal logging
50
+ var axiosInstance = axios.create({
70
51
  httpsAgent: new https.Agent({
71
52
  rejectUnauthorized: false
72
53
  })
73
54
  });
74
55
  var axiosRetry = require('axios-retry');
75
- axiosRetry(axios, {
76
- retries: 3, // number of retries
56
+ axiosRetry(axiosInstance, {
57
+ retries: 2,
77
58
  retryDelay: function (retryCount) {
78
- console.log("retry attempt: ".concat(retryCount));
79
- return retryCount * 2000; // time interval between retries
59
+ return retryCount * 1000;
80
60
  },
81
61
  retryCondition: function (error) {
82
- console.error(error);
83
- // if retry condition is not specified, by default idempotent requests are retried
84
- return error.response.status === 503;
62
+ var _a;
63
+ return ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 503;
85
64
  },
65
+ onRetry: function (retryCount, error) {
66
+ log.debug(TAG, "Retry ".concat(retryCount, "/2: ").concat(error.message));
67
+ }
86
68
  });
87
- var log = require('@pioneer-platform/loggerdog')();
88
- var URL_THORNODE = 'https://mayanode.mayachain.info';
89
- var URL_MIDGARD = 'https://midgard.mayachain.info/v2';
90
- // NowNodes fallback endpoints
91
- var NOWNODES_ENDPOINTS = [
92
- 'https://maya.nownodes.io',
93
- 'https://mayachain.nownodes.io'
94
- ];
95
- // ShapeShift Unchained API endpoint
96
- var UNCHAINED_ENDPOINT = 'https://api.mayachain.shapeshift.com';
97
- var BASE_THOR = 10000000000;
69
+ // Unchained API endpoint
70
+ var UNCHAINED_API = 'https://api.mayachain.shapeshift.com';
71
+ // Fallback to Midgard for pool data (not available in Unchained)
72
+ var MIDGARD_API = 'https://midgard.mayachain.info/v2';
73
+ // Base unit conversion (10 decimal places for CACAO)
74
+ var BASE_MAYA = 10000000000;
98
75
  /**********************************
99
- // Module
76
+ // Module Exports
100
77
  //**********************************/
101
78
  module.exports = {
102
79
  init: function (url, settings) {
@@ -106,7 +83,7 @@ module.exports = {
106
83
  return true;
107
84
  },
108
85
  info: function () {
109
- return get_node_info_verbose();
86
+ return get_info();
110
87
  },
111
88
  getBalance: function (address) {
112
89
  return get_balance(address);
@@ -117,12 +94,6 @@ module.exports = {
117
94
  getAccount: function (address) {
118
95
  return get_account_info(address);
119
96
  },
120
- getLastBlock: function () {
121
- return get_last_block();
122
- },
123
- getBlockHeight: function () {
124
- return get_block_height();
125
- },
126
97
  getAccountInfo: function (address) {
127
98
  return get_account_info(address);
128
99
  },
@@ -149,148 +120,174 @@ module.exports = {
149
120
  },
150
121
  };
151
122
  /**********************************
152
- // Lib
123
+ // Implementation
153
124
  //**********************************/
154
- var get_pool = function (poolId) {
125
+ var get_info = function () {
155
126
  return __awaiter(this, void 0, void 0, function () {
156
- var tag, params, body, resp, e_1;
127
+ var tag, result, e_1;
157
128
  return __generator(this, function (_a) {
158
129
  switch (_a.label) {
159
130
  case 0:
160
- tag = TAG + " | get_pool | ";
131
+ tag = TAG + " | get_info | ";
161
132
  _a.label = 1;
162
133
  case 1:
163
134
  _a.trys.push([1, 3, , 4]);
164
- params = {
165
- view: "full",
166
- asset: poolId
167
- };
168
- body = {
169
- method: 'GET',
170
- url: URL_MIDGARD + "/pools/detail",
171
- headers: { 'content-type': 'application/json' },
172
- params: params
173
- };
174
- log.debug(body);
175
- return [4 /*yield*/, axios(body)];
135
+ return [4 /*yield*/, axiosInstance({
136
+ method: 'GET',
137
+ url: "".concat(UNCHAINED_API, "/api/v1/info"),
138
+ timeout: 5000
139
+ })];
176
140
  case 2:
177
- resp = _a.sent();
178
- return [2 /*return*/, resp.data];
141
+ result = _a.sent();
142
+ return [2 /*return*/, result.data];
179
143
  case 3:
180
144
  e_1 = _a.sent();
181
- log.error(tag, "e: ", e_1);
145
+ log.error(tag, "Error:", e_1.message);
182
146
  throw e_1;
183
147
  case 4: return [2 /*return*/];
184
148
  }
185
149
  });
186
150
  });
187
151
  };
188
- var get_pools = function () {
152
+ var get_account_info = function (address) {
189
153
  return __awaiter(this, void 0, void 0, function () {
190
- var tag, body, resp, e_2;
154
+ var tag, result, e_2;
191
155
  return __generator(this, function (_a) {
192
156
  switch (_a.label) {
193
157
  case 0:
194
- tag = TAG + " | get_pools | ";
158
+ tag = TAG + " | get_account_info | ";
195
159
  _a.label = 1;
196
160
  case 1:
197
161
  _a.trys.push([1, 3, , 4]);
198
- body = {
199
- method: 'GET',
200
- url: URL_MIDGARD + "/pools",
201
- headers: { 'content-type': 'application/json' },
202
- // body: {account_name: actor},
203
- // json: true
204
- };
205
- log.debug(body.url);
206
- return [4 /*yield*/, axios(body)];
162
+ return [4 /*yield*/, axiosInstance({
163
+ method: 'GET',
164
+ url: "".concat(UNCHAINED_API, "/api/v1/account/").concat(address),
165
+ timeout: 5000
166
+ })];
207
167
  case 2:
208
- resp = _a.sent();
209
- return [2 /*return*/, resp.data];
168
+ result = _a.sent();
169
+ return [2 /*return*/, result.data];
210
170
  case 3:
211
171
  e_2 = _a.sent();
212
- log.error(tag, "e: ", e_2);
172
+ log.error(tag, "Error:", e_2.message);
213
173
  throw e_2;
214
174
  case 4: return [2 /*return*/];
215
175
  }
216
176
  });
217
177
  });
218
178
  };
219
- //https://testnet.thornode.thorchain.info/thorchain/inbound_addresses
220
- var get_pool_addresses = function () {
179
+ var get_balance = function (address) {
221
180
  return __awaiter(this, void 0, void 0, function () {
222
- var tag, output, body, resp, e_3;
181
+ var tag, accountInfo, balance, e_3;
223
182
  return __generator(this, function (_a) {
224
183
  switch (_a.label) {
225
184
  case 0:
226
- tag = TAG + " | get_pool_addresses | ";
185
+ tag = TAG + " | get_balance | ";
227
186
  _a.label = 1;
228
187
  case 1:
229
188
  _a.trys.push([1, 3, , 4]);
230
- output = {};
231
- body = {
232
- method: 'GET',
233
- url: URL_THORNODE + "/thorchain/inbound_addresses",
234
- headers: { 'content-type': 'application/json' },
235
- // body: {account_name: actor},
236
- // json: true
237
- };
238
- log.debug(body);
239
- return [4 /*yield*/, axios(body)];
189
+ return [4 /*yield*/, get_account_info(address)
190
+ // Parse balance from string to number
191
+ ];
240
192
  case 2:
241
- resp = _a.sent();
242
- return [2 /*return*/, resp.data];
193
+ accountInfo = _a.sent();
194
+ balance = parseFloat(accountInfo.balance || '0');
195
+ // Convert from base units to CACAO
196
+ return [2 /*return*/, balance / BASE_MAYA];
243
197
  case 3:
244
198
  e_3 = _a.sent();
245
- log.error(tag, "e: ", e_3);
246
- return [3 /*break*/, 4];
199
+ log.error(tag, "Error:", e_3.message);
200
+ throw e_3;
247
201
  case 4: return [2 /*return*/];
248
202
  }
249
203
  });
250
204
  });
251
205
  };
252
- var get_last_block = function () {
206
+ var get_balances = function (address) {
253
207
  return __awaiter(this, void 0, void 0, function () {
254
- var tag, lastBlock, e_4;
255
- return __generator(this, function (_a) {
256
- switch (_a.label) {
208
+ var tag, accountInfo, output, cacaoBalance, _i, _a, asset, e_4;
209
+ return __generator(this, function (_b) {
210
+ switch (_b.label) {
257
211
  case 0:
258
- tag = TAG + " | get_last_block | ";
259
- _a.label = 1;
212
+ tag = TAG + " | get_balances | ";
213
+ _b.label = 1;
260
214
  case 1:
261
- _a.trys.push([1, 3, , 4]);
262
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/blocks/latest' })];
215
+ _b.trys.push([1, 3, , 4]);
216
+ return [4 /*yield*/, get_account_info(address)];
263
217
  case 2:
264
- lastBlock = _a.sent();
265
- log.debug(tag, "lastBlock: ", lastBlock.data);
266
- return [2 /*return*/, lastBlock.data.block];
218
+ accountInfo = _b.sent();
219
+ output = [];
220
+ cacaoBalance = parseFloat(accountInfo.balance || '0');
221
+ if (cacaoBalance > 0) {
222
+ output.push({
223
+ denom: 'cacao',
224
+ amountBase: accountInfo.balance,
225
+ amount: cacaoBalance / BASE_MAYA,
226
+ decimals: 10
227
+ });
228
+ }
229
+ // Parse assets array if present (MAYA and other assets)
230
+ if (accountInfo.assets && Array.isArray(accountInfo.assets)) {
231
+ for (_i = 0, _a = accountInfo.assets; _i < _a.length; _i++) {
232
+ asset = _a[_i];
233
+ if (asset.denom === 'maya') {
234
+ output.push({
235
+ denom: asset.denom,
236
+ amountBase: asset.amount,
237
+ amount: parseFloat(asset.amount) / 10000, // 4 decimals for MAYA
238
+ decimals: 4
239
+ });
240
+ }
241
+ else if (asset.denom === 'cacao') {
242
+ // Skip if already added from main balance
243
+ continue;
244
+ }
245
+ else {
246
+ output.push({
247
+ denom: asset.denom,
248
+ amountBase: asset.amount,
249
+ amount: parseFloat(asset.amount),
250
+ decimals: 0
251
+ });
252
+ }
253
+ }
254
+ }
255
+ return [2 /*return*/, output];
267
256
  case 3:
268
- e_4 = _a.sent();
269
- log.error(tag, "e: ", e_4);
257
+ e_4 = _b.sent();
258
+ log.error(tag, "Error:", e_4.message);
270
259
  throw e_4;
271
260
  case 4: return [2 /*return*/];
272
261
  }
273
262
  });
274
263
  });
275
264
  };
276
- var get_block_height = function () {
277
- return __awaiter(this, void 0, void 0, function () {
278
- var tag, lastBlock, e_5;
265
+ var get_txs_by_address = function (address_1, cursor_1) {
266
+ return __awaiter(this, arguments, void 0, function (address, cursor, pageSize) {
267
+ var tag, params, result, e_5;
268
+ if (pageSize === void 0) { pageSize = 50; }
279
269
  return __generator(this, function (_a) {
280
270
  switch (_a.label) {
281
271
  case 0:
282
- tag = TAG + " | get_block_height | ";
272
+ tag = TAG + " | get_txs_by_address | ";
283
273
  _a.label = 1;
284
274
  case 1:
285
275
  _a.trys.push([1, 3, , 4]);
286
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/blocks/latest' })];
276
+ params = { pageSize: pageSize };
277
+ if (cursor)
278
+ params.cursor = cursor;
279
+ return [4 /*yield*/, axiosInstance({
280
+ method: 'GET',
281
+ url: "".concat(UNCHAINED_API, "/api/v1/account/").concat(address, "/txs"),
282
+ params: params,
283
+ timeout: 10000
284
+ })];
287
285
  case 2:
288
- lastBlock = _a.sent();
289
- log.debug(tag, "lastBlock: ", lastBlock.data);
290
- return [2 /*return*/, lastBlock.data.block.header.height];
286
+ result = _a.sent();
287
+ return [2 /*return*/, result.data];
291
288
  case 3:
292
289
  e_5 = _a.sent();
293
- log.error(tag, "e: ", e_5);
290
+ log.error(tag, "Error:", e_5.message);
294
291
  throw e_5;
295
292
  case 4: return [2 /*return*/];
296
293
  }
@@ -299,471 +296,151 @@ var get_block_height = function () {
299
296
  };
300
297
  var get_transaction = function (txid) {
301
298
  return __awaiter(this, void 0, void 0, function () {
302
- var tag, txInfo, e_6, output;
299
+ var tag;
303
300
  return __generator(this, function (_a) {
304
- switch (_a.label) {
305
- case 0:
306
- tag = TAG + " | get_transaction | ";
307
- _a.label = 1;
308
- case 1:
309
- _a.trys.push([1, 3, , 4]);
310
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/txs/' + txid })];
311
- case 2:
312
- txInfo = _a.sent();
313
- log.debug(tag, "txInfo: ", txInfo.data);
314
- return [2 /*return*/, txInfo.data];
315
- case 3:
316
- e_6 = _a.sent();
317
- // log.error(tag,e.response.data)
318
- // log.error(tag,e.response.data.error)
319
- if (e_6.response.status === 404) {
320
- output = {};
321
- output.success = false;
322
- output.error = e_6.response.data.error;
323
- return [2 /*return*/, output];
324
- }
325
- else {
326
- throw Error(e_6);
327
- }
328
- return [3 /*break*/, 4];
329
- case 4: return [2 /*return*/];
301
+ tag = TAG + " | get_transaction | ";
302
+ try {
303
+ // Unchained doesn't have a direct tx lookup endpoint
304
+ // Would need to implement via account txs or use Midgard/node fallback
305
+ log.warn(tag, "Transaction lookup not implemented in Unchained API, use Midgard or node directly");
306
+ throw new Error("Transaction lookup not available in Unchained API");
330
307
  }
308
+ catch (e) {
309
+ log.error(tag, "Error:", e.message);
310
+ throw e;
311
+ }
312
+ return [2 /*return*/];
331
313
  });
332
314
  });
333
315
  };
334
316
  var broadcast_transaction = function (tx) {
335
317
  return __awaiter(this, void 0, void 0, function () {
336
- var tag, output, cosmosPayload, unchainedPayload, endpoints, lastError, i, endpoint, urlRemote, headers, payload, result2, errorMsg, e_7, e_8;
337
- return __generator(this, function (_a) {
338
- switch (_a.label) {
318
+ var tag, output, payload, result, e_6;
319
+ var _a;
320
+ return __generator(this, function (_b) {
321
+ switch (_b.label) {
339
322
  case 0:
340
323
  tag = TAG + " | broadcast_transaction | ";
341
- output = {};
342
- _a.label = 1;
324
+ output = { success: false };
325
+ _b.label = 1;
343
326
  case 1:
344
- _a.trys.push([1, 8, , 9]);
345
- log.debug(tag, "CHECKPOINT 1");
346
- output.success = false;
347
- cosmosPayload = {
348
- "tx_bytes": tx,
349
- "mode": "BROADCAST_MODE_SYNC"
327
+ _b.trys.push([1, 3, , 4]);
328
+ payload = {
329
+ rawTx: tx
350
330
  };
351
- unchainedPayload = {
352
- "rawTx": tx
353
- };
354
- endpoints = __spreadArray([
355
- { url: URL_THORNODE, type: 'cosmos', name: 'MayaNode' },
356
- { url: UNCHAINED_ENDPOINT, type: 'unchained', name: 'ShapeShift Unchained' }
357
- ], NOWNODES_ENDPOINTS.map(function (url) { return ({ url: url, type: 'cosmos', name: 'NowNodes' }); }), true);
358
- lastError = null;
359
- i = 0;
360
- _a.label = 2;
361
- case 2:
362
- if (!(i < endpoints.length)) return [3 /*break*/, 7];
363
- endpoint = endpoints[i];
364
- _a.label = 3;
365
- case 3:
366
- _a.trys.push([3, 5, , 6]);
367
- urlRemote = endpoint.type === 'unchained'
368
- ? endpoint.url + '/api/v1/send'
369
- : endpoint.url + '/cosmos/tx/v1beta1/txs';
370
- log.info(tag, "Attempting broadcast to ".concat(endpoint.name, " (").concat(i + 1, "/").concat(endpoints.length, "): ").concat(urlRemote));
371
- headers = {
372
- 'Content-Type': 'application/json'
373
- };
374
- // Add NowNodes API key if using NowNodes endpoint
375
- if (endpoint.url.includes('nownodes.io') && process.env['NOW_NODES_API']) {
376
- headers['api-key'] = process.env['NOW_NODES_API'];
377
- }
378
- payload = endpoint.type === 'unchained' ? unchainedPayload : cosmosPayload;
379
- return [4 /*yield*/, axios({
380
- url: urlRemote,
381
- headers: headers,
331
+ log.info(tag, "Broadcasting via Unchained API");
332
+ return [4 /*yield*/, axiosInstance({
333
+ url: "".concat(UNCHAINED_API, "/api/v1/send"),
382
334
  method: 'POST',
383
335
  data: payload,
384
- timeout: 10000 // 10 second timeout
336
+ timeout: 10000
385
337
  })];
386
- case 4:
387
- result2 = _a.sent();
388
- log.info(tag, '** Broadcast ** REMOTE: result: ', result2.data);
389
- log.info(tag, '** Broadcast ** REMOTE: result: ', JSON.stringify(result2.data));
390
- // Handle different response formats
391
- if (endpoint.type === 'unchained') {
392
- // Unchained API returns { txid: "hash" } on success
393
- // or throws error with response.data.message on failure
394
- if (result2.data.txid || result2.data.txHash) {
395
- output.txid = result2.data.txid || result2.data.txHash;
396
- output.success = true;
397
- output.endpoint = endpoint.name;
398
- log.info(tag, "\u2705 Broadcast SUCCESS via ".concat(endpoint.name, " - txid:"), output.txid);
399
- return [2 /*return*/, output];
400
- }
401
- else if (result2.data.message) {
402
- // Unchained error response
403
- throw new Error(result2.data.message);
404
- }
405
- }
406
- else {
407
- // Cosmos standard response format
408
- // CRITICAL: Check tx_response.code - Cosmos standard for success/error
409
- // code: 0 = success, any other code = error
410
- if (result2.data.tx_response && result2.data.tx_response.code !== 0) {
411
- errorMsg = result2.data.tx_response.raw_log || 'Transaction failed with unknown error';
412
- log.error(tag, "❌ Broadcast FAILED - code:", result2.data.tx_response.code);
413
- log.error(tag, " Error:", errorMsg);
414
- output.success = false;
415
- output.error = errorMsg;
416
- // Throw error to fail fast - don't let failed transactions proceed
417
- throw new Error("Broadcast failed (code ".concat(result2.data.tx_response.code, "): ").concat(errorMsg));
418
- }
419
- // Only set txid if transaction was successful (code === 0)
420
- if (result2.data.txhash)
421
- output.txid = result2.data.txhash;
422
- //tx_response
423
- if (result2.data.tx_response && result2.data.tx_response.txhash)
424
- output.txid = result2.data.tx_response.txhash;
338
+ case 2:
339
+ result = _b.sent();
340
+ log.info(tag, 'Broadcast response:', result.data);
341
+ // Unchained returns { txid: "hash" } on success
342
+ if (result.data.txid || result.data.txHash) {
343
+ output.txid = result.data.txid || result.data.txHash;
425
344
  output.success = true;
426
- output.endpoint = endpoint.name;
427
- log.info(tag, "\u2705 Broadcast SUCCESS via ".concat(endpoint.name, " - txid:"), output.txid);
428
- return [2 /*return*/, output];
345
+ output.endpoint = 'Unchained';
346
+ log.info(tag, "\u2705 Broadcast SUCCESS - txid: ".concat(output.txid));
429
347
  }
430
- return [3 /*break*/, 6];
431
- case 5:
432
- e_7 = _a.sent();
433
- lastError = e_7;
434
- log.error(tag, "Failed to broadcast via ".concat(endpoint.name, ":"), e_7.message);
435
- if (e_7.response) {
436
- log.error(tag, "Response status:", e_7.response.status);
437
- log.error(tag, "Response data:", e_7.response.data);
438
- // If this is a transaction validation error (not a network error), don't try other endpoints
439
- if (e_7.response.data && e_7.response.data.message &&
440
- (e_7.response.data.message.includes('insufficient') ||
441
- e_7.response.data.message.includes('invalid'))) {
442
- output.success = false;
443
- output.error = e_7.response.data.message || e_7.response.data.error;
444
- log.error(tag, "Transaction validation error - not retrying other endpoints");
445
- return [2 /*return*/, output];
446
- }
447
- }
448
- // If not last endpoint, try next one
449
- if (i < endpoints.length - 1) {
450
- log.info(tag, "Trying next endpoint...");
451
- return [3 /*break*/, 6];
348
+ else if (result.data.message) {
349
+ output.error = result.data.message;
350
+ log.error(tag, "❌ Broadcast FAILED:", result.data.message);
452
351
  }
453
- return [3 /*break*/, 6];
454
- case 6:
455
- i++;
456
- return [3 /*break*/, 2];
457
- case 7:
458
- // All endpoints failed
459
- output.success = false;
460
- if (lastError && lastError.response && lastError.response.data) {
461
- output.error = lastError.response.data.error || lastError.response.data.message || lastError.message;
352
+ return [2 /*return*/, output];
353
+ case 3:
354
+ e_6 = _b.sent();
355
+ log.error(tag, "Broadcast error:", e_6.message);
356
+ if ((_a = e_6.response) === null || _a === void 0 ? void 0 : _a.data) {
357
+ output.error = e_6.response.data.message || e_6.response.data.error || e_6.message;
358
+ log.error(tag, "Response data:", e_6.response.data);
462
359
  }
463
360
  else {
464
- output.error = (lastError === null || lastError === void 0 ? void 0 : lastError.message) || 'All broadcast endpoints failed';
361
+ output.error = e_6.message || 'Broadcast failed';
465
362
  }
466
- log.error(tag, "❌ All broadcast endpoints failed");
467
- return [2 /*return*/, output];
468
- case 8:
469
- e_8 = _a.sent();
470
- console.error(tag, "Unexpected error in broadcast: ", e_8);
471
- output.success = false;
472
- output.error = e_8.message || 'Unexpected broadcast error';
473
363
  return [2 /*return*/, output];
474
- case 9: return [2 /*return*/];
364
+ case 4: return [2 /*return*/];
475
365
  }
476
366
  });
477
367
  });
478
368
  };
479
- var get_account_info = function (address) {
369
+ // Pool endpoints use Midgard (not available in Unchained)
370
+ var get_pool = function (poolId) {
480
371
  return __awaiter(this, void 0, void 0, function () {
481
- var tag, txInfo, e_9;
372
+ var tag, params, result, e_7;
482
373
  return __generator(this, function (_a) {
483
374
  switch (_a.label) {
484
375
  case 0:
485
- tag = TAG + " | get_account_info | ";
376
+ tag = TAG + " | get_pool | ";
486
377
  _a.label = 1;
487
378
  case 1:
488
379
  _a.trys.push([1, 3, , 4]);
489
- //
490
- console.log("URL ", URL_THORNODE + '/auth/accounts/' + address);
491
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/auth/accounts/' + address })];
380
+ params = {
381
+ view: "full",
382
+ asset: poolId
383
+ };
384
+ return [4 /*yield*/, axiosInstance({
385
+ method: 'GET',
386
+ url: "".concat(MIDGARD_API, "/pools/detail"),
387
+ params: params,
388
+ timeout: 5000
389
+ })];
492
390
  case 2:
493
- txInfo = _a.sent();
494
- log.debug(tag, "txInfo: ", txInfo.data);
495
- return [2 /*return*/, txInfo.data];
391
+ result = _a.sent();
392
+ return [2 /*return*/, result.data];
496
393
  case 3:
497
- e_9 = _a.sent();
498
- log.error(tag, "e: ", e_9);
499
- throw e_9;
394
+ e_7 = _a.sent();
395
+ log.error(tag, "Error:", e_7.message);
396
+ throw e_7;
500
397
  case 4: return [2 /*return*/];
501
398
  }
502
399
  });
503
400
  });
504
401
  };
505
- var normalize_tx = function (tx, address) {
506
- var tag = TAG + " | normalize_tx | ";
507
- try {
508
- var output = {};
509
- var sender = void 0;
510
- var receiver = void 0;
511
- var memo = void 0;
512
- var amount = void 0;
513
- var rawlog = JSON.parse(tx.raw_log);
514
- rawlog = rawlog;
515
- //log.debug("rawlog: ",rawlog)
516
- //txTypes
517
- var txTypes = [
518
- 'send',
519
- 'receive',
520
- 'governence',
521
- 'swap',
522
- 'other'
523
- ];
524
- for (var i = 0; i < rawlog.length; i++) {
525
- var txEvents = rawlog[i];
526
- //log.debug(tag,"txEvents: ",txEvents)
527
- txEvents = txEvents.events;
528
- for (var j = 0; j < txEvents.length; j++) {
529
- var event_1 = txEvents[j];
530
- //
531
- //log.debug(tag,"event: ",event)
532
- //log.debug(tag,"attributes: ",prettyjson.render(event.attributes))
533
- //detect event type
534
- log.debug(tag, "type: ", event_1.type);
535
- switch (event_1.type) {
536
- case 'message':
537
- // ignore
538
- break;
539
- case 'transfer':
540
- log.debug(tag, "attributes: ", event_1.attributes);
541
- for (var k = 0; k < event_1.attributes.length; k++) {
542
- var attribute = event_1.attributes[k];
543
- if (attribute.key === 'recipient') {
544
- receiver = attribute.value;
545
- output.receiver = receiver;
546
- if (receiver === address)
547
- output.type = txTypes[1];
548
- }
549
- if (attribute.key === 'sender') {
550
- sender = attribute.value;
551
- output.sender = sender;
552
- if (sender === address)
553
- output.type = txTypes[0];
554
- }
555
- if (attribute.key === 'amount') {
556
- amount = attribute.value;
557
- amount = amount.replace('rune', '');
558
- output.amount = amount / 100000000;
559
- }
560
- }
561
- break;
562
- default:
563
- // code block
564
- }
565
- }
566
- // console.log("log: ",prettyjson.render(log))
567
- }
568
- return output;
569
- }
570
- catch (e) {
571
- log.error(tag, "e: ", e);
572
- throw e;
573
- }
574
- };
575
- var get_txs_by_address = function (address) {
402
+ var get_pools = function () {
576
403
  return __awaiter(this, void 0, void 0, function () {
577
- var tag, output, url, resultSends, sends, i, tx, resultRecieves, receives, i, tx, e_10;
404
+ var tag, result, e_8;
578
405
  return __generator(this, function (_a) {
579
406
  switch (_a.label) {
580
407
  case 0:
581
- tag = TAG + " | get_txs_by_address | ";
408
+ tag = TAG + " | get_pools | ";
582
409
  _a.label = 1;
583
410
  case 1:
584
- _a.trys.push([1, 4, , 5]);
585
- output = [];
586
- url = URL_THORNODE + '/txs?message.sender=' + address;
587
- log.debug(tag, "url: ", url);
588
- return [4 /*yield*/, axios({
589
- url: url,
590
- method: 'GET'
411
+ _a.trys.push([1, 3, , 4]);
412
+ return [4 /*yield*/, axiosInstance({
413
+ method: 'GET',
414
+ url: "".concat(MIDGARD_API, "/pools"),
415
+ timeout: 5000
591
416
  })];
592
417
  case 2:
593
- resultSends = _a.sent();
594
- sends = resultSends.data;
595
- log.debug('sends: ', sends);
596
- if (!sends.txs)
597
- sends.txs = [];
598
- // TODO//pagnation
599
- for (i = 0; i < (sends === null || sends === void 0 ? void 0 : sends.txs.length); i++) {
600
- tx = sends.txs[i];
601
- //pretty json
602
- //normalize
603
- tx = normalize_tx(tx, address);
604
- output.push(tx);
605
- }
606
- //receives
607
- url = URL_THORNODE + '/txs?transfer.recipient=' + address;
608
- console.log("URL_THORNODE: ", url);
609
- return [4 /*yield*/, axios({
610
- url: url,
611
- method: 'GET'
612
- })];
418
+ result = _a.sent();
419
+ return [2 /*return*/, result.data];
613
420
  case 3:
614
- resultRecieves = _a.sent();
615
- receives = resultRecieves.data;
616
- if (!receives.txs)
617
- receives.txs = [];
618
- log.debug('receives: ', receives);
619
- for (i = 0; i < (receives === null || receives === void 0 ? void 0 : receives.txs.length); i++) {
620
- tx = receives.txs[i];
621
- //normalize
622
- tx = normalize_tx(tx, address);
623
- output.push(tx);
624
- }
625
- return [2 /*return*/, output];
626
- case 4:
627
- e_10 = _a.sent();
628
- log.error(tag, "e: ", e_10);
629
- throw e_10;
630
- case 5: return [2 /*return*/];
631
- }
632
- });
633
- });
634
- };
635
- var get_balance = function (address) {
636
- return __awaiter(this, void 0, void 0, function () {
637
- var tag, output, accountInfo, i, entry, e_11, e_12;
638
- var _a;
639
- return __generator(this, function (_b) {
640
- switch (_b.label) {
641
- case 0:
642
- tag = TAG + " | get_balance | ";
643
- _b.label = 1;
644
- case 1:
645
- _b.trys.push([1, 6, , 7]);
646
- output = 0;
647
- _b.label = 2;
648
- case 2:
649
- _b.trys.push([2, 4, , 5]);
650
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/bank/balances/' + address })];
651
- case 3:
652
- accountInfo = _b.sent();
653
- log.info(tag, "accountInfo: ", accountInfo.data);
654
- //
655
- if ((_a = accountInfo.data) === null || _a === void 0 ? void 0 : _a.result) {
656
- for (i = 0; i < accountInfo.data.result.length; i++) {
657
- entry = accountInfo.data.result[i];
658
- if (entry.denom === 'cacao') {
659
- output = entry.amount;
660
- }
661
- }
662
- }
663
- output = output / BASE_THOR;
664
- return [3 /*break*/, 5];
665
- case 4:
666
- e_11 = _b.sent();
667
- return [3 /*break*/, 5];
668
- case 5: return [2 /*return*/, output];
669
- case 6:
670
- e_12 = _b.sent();
671
- log.error(tag, "e: ", e_12);
672
- throw e_12;
673
- case 7: return [2 /*return*/];
674
- }
675
- });
676
- });
677
- };
678
- var get_balances = function (address) {
679
- return __awaiter(this, void 0, void 0, function () {
680
- var tag, output, accountInfo, i, entry, e_13, e_14;
681
- var _a;
682
- return __generator(this, function (_b) {
683
- switch (_b.label) {
684
- case 0:
685
- tag = TAG + " | get_balances | ";
686
- _b.label = 1;
687
- case 1:
688
- _b.trys.push([1, 6, , 7]);
689
- output = [];
690
- _b.label = 2;
691
- case 2:
692
- _b.trys.push([2, 4, , 5]);
693
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/bank/balances/' + address })];
694
- case 3:
695
- accountInfo = _b.sent();
696
- log.info(tag, "accountInfo: ", accountInfo.data);
697
- //
698
- if ((_a = accountInfo.data) === null || _a === void 0 ? void 0 : _a.result) {
699
- for (i = 0; i < accountInfo.data.result.length; i++) {
700
- entry = accountInfo.data.result[i];
701
- if (entry.denom === 'cacao') {
702
- output.push({
703
- denom: entry.denom,
704
- amountBase: entry.amount,
705
- amount: entry.amount / 10000000000,
706
- decimals: 10
707
- });
708
- }
709
- if (entry.denom === 'maya') {
710
- output.push({
711
- denom: entry.denom,
712
- amountBase: entry.amount,
713
- amount: entry.amount / 10000,
714
- decimals: 4
715
- });
716
- }
717
- }
718
- }
719
- return [3 /*break*/, 5];
720
- case 4:
721
- e_13 = _b.sent();
722
- return [3 /*break*/, 5];
723
- case 5: return [2 /*return*/, output];
724
- case 6:
725
- e_14 = _b.sent();
726
- log.error(tag, "e: ", e_14);
727
- throw e_14;
728
- case 7: return [2 /*return*/];
421
+ e_8 = _a.sent();
422
+ log.error(tag, "Error:", e_8.message);
423
+ throw e_8;
424
+ case 4: return [2 /*return*/];
729
425
  }
730
426
  });
731
427
  });
732
428
  };
733
- var get_node_info_verbose = function () {
429
+ var get_pool_addresses = function () {
734
430
  return __awaiter(this, void 0, void 0, function () {
735
- var tag, output, syncInfo, nodeInfo, lastBlock, e_15;
431
+ var tag;
736
432
  return __generator(this, function (_a) {
737
- switch (_a.label) {
738
- case 0:
739
- tag = TAG + " | get_node_info | ";
740
- _a.label = 1;
741
- case 1:
742
- _a.trys.push([1, 5, , 6]);
743
- output = {};
744
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/syncing' })];
745
- case 2:
746
- syncInfo = _a.sent();
747
- log.debug(tag, "syncInfo: ", syncInfo.data);
748
- output.isSyncing = syncInfo.data;
749
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/node_info' })];
750
- case 3:
751
- nodeInfo = _a.sent();
752
- log.debug(tag, "nodeInfo: ", nodeInfo.data);
753
- output = nodeInfo.data;
754
- return [4 /*yield*/, axios({ method: 'GET', url: URL_THORNODE + '/blocks/latest' })];
755
- case 4:
756
- lastBlock = _a.sent();
757
- log.debug(tag, "lastBlock: ", lastBlock.data);
758
- //let height
759
- output.height = lastBlock.data.block.header.height;
760
- return [2 /*return*/, output];
761
- case 5:
762
- e_15 = _a.sent();
763
- log.error(tag, "e: ", e_15);
764
- throw e_15;
765
- case 6: return [2 /*return*/];
433
+ tag = TAG + " | get_pool_addresses | ";
434
+ try {
435
+ // This endpoint might not be available, would need node access
436
+ log.warn(tag, "Pool addresses endpoint may require direct node access");
437
+ throw new Error("Pool addresses not available in Unchained API");
438
+ }
439
+ catch (e) {
440
+ log.error(tag, "Error:", e.message);
441
+ throw e;
766
442
  }
443
+ return [2 /*return*/];
767
444
  });
768
445
  });
769
446
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pioneer-platform/maya-network",
3
- "version": "8.11.1",
3
+ "version": "8.12.0",
4
4
  "main": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "scripts": {