@pioneer-platform/solana-network 8.11.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/.turbo/turbo-build.log +2 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +403 -0
- package/package.json +31 -0
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Solana Network Module
|
|
4
|
+
|
|
5
|
+
Provides connectivity to the Solana blockchain network.
|
|
6
|
+
|
|
7
|
+
Network ID: solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
|
|
8
|
+
SLIP44: 501
|
|
9
|
+
Decimals: 9 (lamports)
|
|
10
|
+
|
|
11
|
+
Public RPC Endpoints:
|
|
12
|
+
- https://api.mainnet-beta.solana.com
|
|
13
|
+
- https://solana-api.projectserum.com
|
|
14
|
+
|
|
15
|
+
TODO: Implement full network functionality
|
|
16
|
+
- Transaction building
|
|
17
|
+
- Transaction signing coordination with KeepKey
|
|
18
|
+
- Balance fetching
|
|
19
|
+
- Token account queries (SPL tokens)
|
|
20
|
+
*/
|
|
21
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
22
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
23
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
24
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
25
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
26
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
27
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
31
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
32
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
33
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
34
|
+
function step(op) {
|
|
35
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
36
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
37
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
38
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
39
|
+
switch (op[0]) {
|
|
40
|
+
case 0: case 1: t = op; break;
|
|
41
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
42
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
43
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
44
|
+
default:
|
|
45
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
46
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
47
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
48
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
49
|
+
if (t[2]) _.ops.pop();
|
|
50
|
+
_.trys.pop(); continue;
|
|
51
|
+
}
|
|
52
|
+
op = body.call(thisArg, _);
|
|
53
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
54
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.DECIMALS = exports.CHAIN_SYMBOL = exports.NETWORK_ID = void 0;
|
|
59
|
+
var TAG = " | solana-network | ";
|
|
60
|
+
require("dotenv").config({ path: '../../../../.env' });
|
|
61
|
+
var axiosLib = require('axios');
|
|
62
|
+
var Axios = axiosLib.default || axiosLib;
|
|
63
|
+
var https = require('https');
|
|
64
|
+
var log = require('@pioneer-platform/loggerdog')();
|
|
65
|
+
// Default Solana mainnet RPC
|
|
66
|
+
var DEFAULT_RPC_URL = "https://api.mainnet-beta.solana.com";
|
|
67
|
+
// Network constants
|
|
68
|
+
exports.NETWORK_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
|
|
69
|
+
exports.CHAIN_SYMBOL = 'SOL';
|
|
70
|
+
exports.DECIMALS = 9;
|
|
71
|
+
// Create axios instance for RPC calls
|
|
72
|
+
var axios = Axios.create({
|
|
73
|
+
httpsAgent: new https.Agent({
|
|
74
|
+
rejectUnauthorized: false
|
|
75
|
+
}),
|
|
76
|
+
headers: {
|
|
77
|
+
'Content-Type': 'application/json'
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// Module state
|
|
81
|
+
var rpcUrl = DEFAULT_RPC_URL;
|
|
82
|
+
var isInitialized = false;
|
|
83
|
+
/**********************************
|
|
84
|
+
// Module Exports
|
|
85
|
+
//**********************************/
|
|
86
|
+
module.exports = {
|
|
87
|
+
/**
|
|
88
|
+
* Initialize the Solana network module
|
|
89
|
+
* @param url - Optional custom RPC URL
|
|
90
|
+
* @param settings - Optional settings object
|
|
91
|
+
*/
|
|
92
|
+
init: function (url, settings) {
|
|
93
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
94
|
+
var tag, testResult, versionResult, e_1;
|
|
95
|
+
return __generator(this, function (_a) {
|
|
96
|
+
switch (_a.label) {
|
|
97
|
+
case 0:
|
|
98
|
+
tag = TAG + " | init | ";
|
|
99
|
+
_a.label = 1;
|
|
100
|
+
case 1:
|
|
101
|
+
_a.trys.push([1, 6, , 7]);
|
|
102
|
+
rpcUrl = url || process.env['SOLANA_RPC_URL'] || DEFAULT_RPC_URL;
|
|
103
|
+
log.info(tag, "Initializing Solana network...");
|
|
104
|
+
log.info(tag, "RPC Endpoint:", rpcUrl);
|
|
105
|
+
return [4 /*yield*/, axios({
|
|
106
|
+
url: rpcUrl,
|
|
107
|
+
method: 'POST',
|
|
108
|
+
data: {
|
|
109
|
+
"jsonrpc": "2.0",
|
|
110
|
+
"id": 1,
|
|
111
|
+
"method": "getHealth"
|
|
112
|
+
}
|
|
113
|
+
})];
|
|
114
|
+
case 2:
|
|
115
|
+
testResult = _a.sent();
|
|
116
|
+
if (!(testResult.data && testResult.data.result === 'ok')) return [3 /*break*/, 3];
|
|
117
|
+
log.info(tag, "Successfully connected to Solana RPC");
|
|
118
|
+
isInitialized = true;
|
|
119
|
+
return [2 /*return*/, true];
|
|
120
|
+
case 3: return [4 /*yield*/, axios({
|
|
121
|
+
url: rpcUrl,
|
|
122
|
+
method: 'POST',
|
|
123
|
+
data: {
|
|
124
|
+
"jsonrpc": "2.0",
|
|
125
|
+
"id": 1,
|
|
126
|
+
"method": "getVersion"
|
|
127
|
+
}
|
|
128
|
+
})];
|
|
129
|
+
case 4:
|
|
130
|
+
versionResult = _a.sent();
|
|
131
|
+
if (versionResult.data && versionResult.data.result) {
|
|
132
|
+
log.info(tag, "Connected to Solana RPC, version:", versionResult.data.result['solana-core']);
|
|
133
|
+
isInitialized = true;
|
|
134
|
+
return [2 /*return*/, true];
|
|
135
|
+
}
|
|
136
|
+
throw new Error("Invalid response from Solana RPC");
|
|
137
|
+
case 5: return [3 /*break*/, 7];
|
|
138
|
+
case 6:
|
|
139
|
+
e_1 = _a.sent();
|
|
140
|
+
log.error(tag, "Failed to initialize:", e_1.message);
|
|
141
|
+
throw e_1;
|
|
142
|
+
case 7: return [2 /*return*/];
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* Check if the module is online and initialized
|
|
149
|
+
*/
|
|
150
|
+
isOnline: function () {
|
|
151
|
+
return isInitialized;
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* Get the balance of a Solana address
|
|
155
|
+
* @param address - Solana public key (base58 encoded)
|
|
156
|
+
* @returns Balance in SOL
|
|
157
|
+
*/
|
|
158
|
+
getBalance: function (address) {
|
|
159
|
+
return get_balance(address);
|
|
160
|
+
},
|
|
161
|
+
/**
|
|
162
|
+
* Get account info for a Solana address
|
|
163
|
+
* @param address - Solana public key (base58 encoded)
|
|
164
|
+
*/
|
|
165
|
+
getAccount: function (address) {
|
|
166
|
+
return get_account_info(address);
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* Get recent blockhash for transaction building
|
|
170
|
+
*/
|
|
171
|
+
getRecentBlockhash: function () {
|
|
172
|
+
return get_recent_blockhash();
|
|
173
|
+
},
|
|
174
|
+
/**
|
|
175
|
+
* Broadcast a signed transaction
|
|
176
|
+
* @param tx - Base64 encoded signed transaction
|
|
177
|
+
*/
|
|
178
|
+
broadcast: function (tx) {
|
|
179
|
+
return broadcast_transaction(tx);
|
|
180
|
+
},
|
|
181
|
+
/**
|
|
182
|
+
* Get transaction details
|
|
183
|
+
* @param signature - Transaction signature
|
|
184
|
+
*/
|
|
185
|
+
getTransaction: function (signature) {
|
|
186
|
+
return get_transaction(signature);
|
|
187
|
+
},
|
|
188
|
+
// Network constants
|
|
189
|
+
NETWORK_ID: exports.NETWORK_ID,
|
|
190
|
+
CHAIN_SYMBOL: exports.CHAIN_SYMBOL,
|
|
191
|
+
DECIMALS: exports.DECIMALS
|
|
192
|
+
};
|
|
193
|
+
/**********************************
|
|
194
|
+
// Implementation Functions
|
|
195
|
+
//**********************************/
|
|
196
|
+
function get_balance(address) {
|
|
197
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
198
|
+
var tag, response, balanceInLamports, balanceInSOL, e_2;
|
|
199
|
+
return __generator(this, function (_a) {
|
|
200
|
+
switch (_a.label) {
|
|
201
|
+
case 0:
|
|
202
|
+
tag = TAG + " | get_balance | ";
|
|
203
|
+
_a.label = 1;
|
|
204
|
+
case 1:
|
|
205
|
+
_a.trys.push([1, 3, , 4]);
|
|
206
|
+
log.debug(tag, "Getting balance for:", address);
|
|
207
|
+
return [4 /*yield*/, axios({
|
|
208
|
+
url: rpcUrl,
|
|
209
|
+
method: 'POST',
|
|
210
|
+
data: {
|
|
211
|
+
"jsonrpc": "2.0",
|
|
212
|
+
"id": 1,
|
|
213
|
+
"method": "getBalance",
|
|
214
|
+
"params": [address]
|
|
215
|
+
}
|
|
216
|
+
})];
|
|
217
|
+
case 2:
|
|
218
|
+
response = _a.sent();
|
|
219
|
+
if (response.data && response.data.result) {
|
|
220
|
+
balanceInLamports = response.data.result.value;
|
|
221
|
+
balanceInSOL = balanceInLamports / Math.pow(10, exports.DECIMALS);
|
|
222
|
+
log.debug(tag, "Balance retrieved:", balanceInSOL, "SOL");
|
|
223
|
+
return [2 /*return*/, balanceInSOL];
|
|
224
|
+
}
|
|
225
|
+
if (response.data && response.data.error) {
|
|
226
|
+
log.error(tag, "RPC error:", response.data.error.message);
|
|
227
|
+
return [2 /*return*/, 0];
|
|
228
|
+
}
|
|
229
|
+
return [2 /*return*/, 0];
|
|
230
|
+
case 3:
|
|
231
|
+
e_2 = _a.sent();
|
|
232
|
+
log.error(tag, "Error getting balance:", e_2.message);
|
|
233
|
+
return [2 /*return*/, 0];
|
|
234
|
+
case 4: return [2 /*return*/];
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function get_account_info(address) {
|
|
240
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
241
|
+
var tag, response, e_3;
|
|
242
|
+
return __generator(this, function (_a) {
|
|
243
|
+
switch (_a.label) {
|
|
244
|
+
case 0:
|
|
245
|
+
tag = TAG + " | get_account_info | ";
|
|
246
|
+
_a.label = 1;
|
|
247
|
+
case 1:
|
|
248
|
+
_a.trys.push([1, 3, , 4]);
|
|
249
|
+
log.debug(tag, "Getting account info for:", address);
|
|
250
|
+
return [4 /*yield*/, axios({
|
|
251
|
+
url: rpcUrl,
|
|
252
|
+
method: 'POST',
|
|
253
|
+
data: {
|
|
254
|
+
"jsonrpc": "2.0",
|
|
255
|
+
"id": 1,
|
|
256
|
+
"method": "getAccountInfo",
|
|
257
|
+
"params": [
|
|
258
|
+
address,
|
|
259
|
+
{ "encoding": "jsonParsed" }
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
})];
|
|
263
|
+
case 2:
|
|
264
|
+
response = _a.sent();
|
|
265
|
+
if (response.data && response.data.result) {
|
|
266
|
+
return [2 /*return*/, response.data.result.value];
|
|
267
|
+
}
|
|
268
|
+
if (response.data && response.data.error) {
|
|
269
|
+
log.error(tag, "RPC error:", response.data.error.message);
|
|
270
|
+
return [2 /*return*/, null];
|
|
271
|
+
}
|
|
272
|
+
return [2 /*return*/, null];
|
|
273
|
+
case 3:
|
|
274
|
+
e_3 = _a.sent();
|
|
275
|
+
log.error(tag, "Error getting account info:", e_3.message);
|
|
276
|
+
throw e_3;
|
|
277
|
+
case 4: return [2 /*return*/];
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function get_recent_blockhash() {
|
|
283
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
284
|
+
var tag, response, e_4;
|
|
285
|
+
return __generator(this, function (_a) {
|
|
286
|
+
switch (_a.label) {
|
|
287
|
+
case 0:
|
|
288
|
+
tag = TAG + " | get_recent_blockhash | ";
|
|
289
|
+
_a.label = 1;
|
|
290
|
+
case 1:
|
|
291
|
+
_a.trys.push([1, 3, , 4]);
|
|
292
|
+
return [4 /*yield*/, axios({
|
|
293
|
+
url: rpcUrl,
|
|
294
|
+
method: 'POST',
|
|
295
|
+
data: {
|
|
296
|
+
"jsonrpc": "2.0",
|
|
297
|
+
"id": 1,
|
|
298
|
+
"method": "getLatestBlockhash",
|
|
299
|
+
"params": [{ "commitment": "finalized" }]
|
|
300
|
+
}
|
|
301
|
+
})];
|
|
302
|
+
case 2:
|
|
303
|
+
response = _a.sent();
|
|
304
|
+
if (response.data && response.data.result) {
|
|
305
|
+
return [2 /*return*/, response.data.result.value];
|
|
306
|
+
}
|
|
307
|
+
throw new Error("Failed to get recent blockhash");
|
|
308
|
+
case 3:
|
|
309
|
+
e_4 = _a.sent();
|
|
310
|
+
log.error(tag, "Error getting blockhash:", e_4.message);
|
|
311
|
+
throw e_4;
|
|
312
|
+
case 4: return [2 /*return*/];
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
function broadcast_transaction(tx) {
|
|
318
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
319
|
+
var tag, output, response, e_5;
|
|
320
|
+
return __generator(this, function (_a) {
|
|
321
|
+
switch (_a.label) {
|
|
322
|
+
case 0:
|
|
323
|
+
tag = TAG + " | broadcast_transaction | ";
|
|
324
|
+
output = { success: false };
|
|
325
|
+
_a.label = 1;
|
|
326
|
+
case 1:
|
|
327
|
+
_a.trys.push([1, 3, , 4]);
|
|
328
|
+
log.debug(tag, "Broadcasting transaction...");
|
|
329
|
+
return [4 /*yield*/, axios({
|
|
330
|
+
url: rpcUrl,
|
|
331
|
+
method: 'POST',
|
|
332
|
+
data: {
|
|
333
|
+
"jsonrpc": "2.0",
|
|
334
|
+
"id": 1,
|
|
335
|
+
"method": "sendTransaction",
|
|
336
|
+
"params": [
|
|
337
|
+
tx,
|
|
338
|
+
{ "encoding": "base64" }
|
|
339
|
+
]
|
|
340
|
+
}
|
|
341
|
+
})];
|
|
342
|
+
case 2:
|
|
343
|
+
response = _a.sent();
|
|
344
|
+
if (response.data && response.data.result) {
|
|
345
|
+
output.success = true;
|
|
346
|
+
output.txid = response.data.result;
|
|
347
|
+
log.info(tag, "Transaction broadcast successful:", output.txid);
|
|
348
|
+
}
|
|
349
|
+
else if (response.data && response.data.error) {
|
|
350
|
+
output.success = false;
|
|
351
|
+
output.error = response.data.error.message;
|
|
352
|
+
log.error(tag, "Broadcast error:", output.error);
|
|
353
|
+
}
|
|
354
|
+
return [2 /*return*/, output];
|
|
355
|
+
case 3:
|
|
356
|
+
e_5 = _a.sent();
|
|
357
|
+
log.error(tag, "Broadcast error:", e_5.message);
|
|
358
|
+
output.error = e_5.message;
|
|
359
|
+
return [2 /*return*/, output];
|
|
360
|
+
case 4: return [2 /*return*/];
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
function get_transaction(signature) {
|
|
366
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
367
|
+
var tag, response, e_6;
|
|
368
|
+
return __generator(this, function (_a) {
|
|
369
|
+
switch (_a.label) {
|
|
370
|
+
case 0:
|
|
371
|
+
tag = TAG + " | get_transaction | ";
|
|
372
|
+
_a.label = 1;
|
|
373
|
+
case 1:
|
|
374
|
+
_a.trys.push([1, 3, , 4]);
|
|
375
|
+
log.debug(tag, "Getting transaction:", signature);
|
|
376
|
+
return [4 /*yield*/, axios({
|
|
377
|
+
url: rpcUrl,
|
|
378
|
+
method: 'POST',
|
|
379
|
+
data: {
|
|
380
|
+
"jsonrpc": "2.0",
|
|
381
|
+
"id": 1,
|
|
382
|
+
"method": "getTransaction",
|
|
383
|
+
"params": [
|
|
384
|
+
signature,
|
|
385
|
+
{ "encoding": "jsonParsed", "maxSupportedTransactionVersion": 0 }
|
|
386
|
+
]
|
|
387
|
+
}
|
|
388
|
+
})];
|
|
389
|
+
case 2:
|
|
390
|
+
response = _a.sent();
|
|
391
|
+
if (response.data && response.data.result) {
|
|
392
|
+
return [2 /*return*/, response.data.result];
|
|
393
|
+
}
|
|
394
|
+
return [2 /*return*/, null];
|
|
395
|
+
case 3:
|
|
396
|
+
e_6 = _a.sent();
|
|
397
|
+
log.error(tag, "Error getting transaction:", e_6.message);
|
|
398
|
+
throw e_6;
|
|
399
|
+
case 4: return [2 /*return*/];
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pioneer-platform/solana-network",
|
|
3
|
+
"version": "8.11.0",
|
|
4
|
+
"main": "./lib/index.js",
|
|
5
|
+
"types": "./lib/index.d.ts",
|
|
6
|
+
"description": "Pioneer Platform Solana Network module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"solana",
|
|
9
|
+
"sol",
|
|
10
|
+
"blockchain",
|
|
11
|
+
"pioneer"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"create": "pnpm run build && pnpm run test",
|
|
15
|
+
"build": "tsc -p .",
|
|
16
|
+
"test": "pnpm run build && node __tests__/test-module.js",
|
|
17
|
+
"prepublish": "rm -R lib && pnpm run build",
|
|
18
|
+
"refresh": "rm -rf ./node_modules ./package-lock.json && pnpm install"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@pioneer-platform/loggerdog": "^8.11.0",
|
|
22
|
+
"@solana/web3.js": "^1.95.0",
|
|
23
|
+
"axios": "^1.6.0",
|
|
24
|
+
"dotenv": "^16.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^18.16.0",
|
|
28
|
+
"typescript": "^5.0.4"
|
|
29
|
+
},
|
|
30
|
+
"gitHead": "aeae28273014ab69b42f22abec159c6693a56c40"
|
|
31
|
+
}
|