jaelis-node 1.1.0 → 1.2.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/lib/index.js +444 -23
- package/lib/vm/index.js +397 -0
- package/package.json +12 -3
package/lib/index.js
CHANGED
|
@@ -362,14 +362,26 @@ class BootstrapNode extends EventEmitter {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
// ============================================================
|
|
365
|
-
// EMBEDDED
|
|
365
|
+
// EMBEDDED IMPLEMENTATIONS WITH UNIFIED VM
|
|
366
366
|
// ============================================================
|
|
367
367
|
|
|
368
|
+
// Import VM Executor (UnifiedJaelisVM integration)
|
|
369
|
+
let VMExecutor;
|
|
370
|
+
try {
|
|
371
|
+
VMExecutor = require('./vm').VMExecutor;
|
|
372
|
+
} catch (e) {
|
|
373
|
+
console.log('[JAELIS] VM module not loaded - running in light mode');
|
|
374
|
+
}
|
|
375
|
+
|
|
368
376
|
class EmbeddedBlockchain {
|
|
369
377
|
constructor(options = {}) {
|
|
370
378
|
this.chainId = options.chainId || 4545;
|
|
371
379
|
this.chain = [];
|
|
372
380
|
this.state = new Map();
|
|
381
|
+
this.pendingTransactions = [];
|
|
382
|
+
|
|
383
|
+
// Initialize VM Executor (UnifiedJaelisVM - NO BRIDGES!)
|
|
384
|
+
this.vmExecutor = null;
|
|
373
385
|
}
|
|
374
386
|
|
|
375
387
|
async initialize() {
|
|
@@ -378,18 +390,139 @@ class EmbeddedBlockchain {
|
|
|
378
390
|
this.chain.push({
|
|
379
391
|
number: 0,
|
|
380
392
|
hash: '0x' + '0'.repeat(64),
|
|
393
|
+
parentHash: '0x' + '0'.repeat(64),
|
|
381
394
|
timestamp: Date.now(),
|
|
382
|
-
transactions: []
|
|
395
|
+
transactions: [],
|
|
396
|
+
stateRoot: '0x' + '0'.repeat(64)
|
|
383
397
|
});
|
|
384
398
|
}
|
|
399
|
+
|
|
400
|
+
// Initialize the Unified VM
|
|
401
|
+
if (VMExecutor) {
|
|
402
|
+
this.vmExecutor = new VMExecutor(this, {
|
|
403
|
+
debug: false
|
|
404
|
+
});
|
|
405
|
+
console.log('[BLOCKCHAIN] Unified VM initialized - TRUE cross-chain interop!');
|
|
406
|
+
}
|
|
385
407
|
}
|
|
386
408
|
|
|
387
409
|
getHeight() {
|
|
388
410
|
return this.chain.length - 1;
|
|
389
411
|
}
|
|
390
412
|
|
|
413
|
+
getLatestBlock() {
|
|
414
|
+
return this.chain[this.chain.length - 1];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
getBlock(numberOrHash) {
|
|
418
|
+
if (typeof numberOrHash === 'number') {
|
|
419
|
+
return this.chain[numberOrHash];
|
|
420
|
+
}
|
|
421
|
+
return this.chain.find(b => b.hash === numberOrHash);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Deploy a smart contract (ANY language!)
|
|
426
|
+
*/
|
|
427
|
+
async deployContract(source, language, options = {}) {
|
|
428
|
+
if (!this.vmExecutor) {
|
|
429
|
+
throw new Error('VM not available - initialize blockchain first');
|
|
430
|
+
}
|
|
431
|
+
return this.vmExecutor.deployContract(source, language, options);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Execute a contract call
|
|
436
|
+
*/
|
|
437
|
+
async executeContract(to, functionName, args = [], options = {}) {
|
|
438
|
+
if (!this.vmExecutor) {
|
|
439
|
+
throw new Error('VM not available');
|
|
440
|
+
}
|
|
441
|
+
return this.vmExecutor.executeCall(to, functionName, args, options);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Cross-contract call (NO BRIDGES!)
|
|
446
|
+
*/
|
|
447
|
+
async crossContractCall(from, to, functionName, args = []) {
|
|
448
|
+
if (!this.vmExecutor) {
|
|
449
|
+
throw new Error('VM not available');
|
|
450
|
+
}
|
|
451
|
+
return this.vmExecutor.crossContractCall(from, to, functionName, args);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Process a transaction
|
|
456
|
+
*/
|
|
457
|
+
async processTransaction(tx) {
|
|
458
|
+
if (this.vmExecutor) {
|
|
459
|
+
return this.vmExecutor.processTransaction(tx);
|
|
460
|
+
}
|
|
461
|
+
// Fallback: just store in pending
|
|
462
|
+
this.pendingTransactions.push(tx);
|
|
463
|
+
return { status: 'pending' };
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Create a new block with pending transactions
|
|
468
|
+
*/
|
|
469
|
+
async createBlock(validator) {
|
|
470
|
+
const crypto = require('crypto');
|
|
471
|
+
const parentBlock = this.getLatestBlock();
|
|
472
|
+
|
|
473
|
+
const block = {
|
|
474
|
+
number: parentBlock.number + 1,
|
|
475
|
+
hash: null,
|
|
476
|
+
parentHash: parentBlock.hash,
|
|
477
|
+
timestamp: Date.now(),
|
|
478
|
+
validator: validator || '0x0',
|
|
479
|
+
transactions: [...this.pendingTransactions],
|
|
480
|
+
stateRoot: this._computeStateRoot(),
|
|
481
|
+
gasUsed: 0 // ZERO FEES!
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
// Compute block hash
|
|
485
|
+
block.hash = '0x' + crypto.createHash('sha256')
|
|
486
|
+
.update(JSON.stringify({
|
|
487
|
+
number: block.number,
|
|
488
|
+
parentHash: block.parentHash,
|
|
489
|
+
timestamp: block.timestamp,
|
|
490
|
+
stateRoot: block.stateRoot
|
|
491
|
+
}))
|
|
492
|
+
.digest('hex');
|
|
493
|
+
|
|
494
|
+
// Add to chain
|
|
495
|
+
this.chain.push(block);
|
|
496
|
+
this.pendingTransactions = [];
|
|
497
|
+
|
|
498
|
+
console.log(`[BLOCKCHAIN] Block #${block.number} created with ${block.transactions.length} txs`);
|
|
499
|
+
|
|
500
|
+
return block;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
_computeStateRoot() {
|
|
504
|
+
const crypto = require('crypto');
|
|
505
|
+
const stateData = JSON.stringify(Array.from(this.state.entries()));
|
|
506
|
+
return '0x' + crypto.createHash('sha256').update(stateData).digest('hex');
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Get VM stats
|
|
511
|
+
*/
|
|
512
|
+
getVMStats() {
|
|
513
|
+
return this.vmExecutor?.getStats?.() || { vmAvailable: false };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Get all deployed contracts
|
|
518
|
+
*/
|
|
519
|
+
getContracts() {
|
|
520
|
+
return this.vmExecutor?.getAllContracts?.() || [];
|
|
521
|
+
}
|
|
522
|
+
|
|
391
523
|
async save() {
|
|
392
|
-
//
|
|
524
|
+
// Save blockchain state to disk
|
|
525
|
+
// TODO: Implement persistent storage
|
|
393
526
|
}
|
|
394
527
|
}
|
|
395
528
|
|
|
@@ -529,34 +662,44 @@ class EmbeddedRpcServer {
|
|
|
529
662
|
|
|
530
663
|
this.app = express();
|
|
531
664
|
this.app.use(cors());
|
|
532
|
-
this.app.use(express.json());
|
|
665
|
+
this.app.use(express.json({ limit: '50mb' })); // Allow large contract deployments
|
|
533
666
|
|
|
534
|
-
//
|
|
535
|
-
this.app.post('/', (req, res) => {
|
|
667
|
+
// Main RPC endpoint
|
|
668
|
+
this.app.post('/', async (req, res) => {
|
|
536
669
|
const { method, params, id } = req.body;
|
|
537
670
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
case 'eth_blockNumber':
|
|
548
|
-
result = '0x' + (this.blockchain?.getHeight?.() || 0).toString(16);
|
|
549
|
-
break;
|
|
550
|
-
default:
|
|
551
|
-
error = { code: -32601, message: 'Method not found' };
|
|
671
|
+
try {
|
|
672
|
+
const result = await this._handleMethod(method, params || []);
|
|
673
|
+
res.json({ jsonrpc: '2.0', id, result });
|
|
674
|
+
} catch (error) {
|
|
675
|
+
res.json({
|
|
676
|
+
jsonrpc: '2.0',
|
|
677
|
+
id,
|
|
678
|
+
error: { code: -32000, message: error.message }
|
|
679
|
+
});
|
|
552
680
|
}
|
|
553
|
-
|
|
554
|
-
res.json({ jsonrpc: '2.0', id, result, error });
|
|
555
681
|
});
|
|
556
682
|
|
|
557
683
|
// Health check
|
|
558
684
|
this.app.get('/', (req, res) => {
|
|
559
|
-
|
|
685
|
+
const vmStats = this.blockchain?.getVMStats?.() || {};
|
|
686
|
+
res.json({
|
|
687
|
+
status: 'online',
|
|
688
|
+
service: 'JAELIS Node',
|
|
689
|
+
chainId: this.blockchain?.chainId,
|
|
690
|
+
blockHeight: this.blockchain?.getHeight?.() || 0,
|
|
691
|
+
vm: {
|
|
692
|
+
available: vmStats.vmAvailable || false,
|
|
693
|
+
contractsDeployed: vmStats.contractsDeployed || 0,
|
|
694
|
+
crossContractCalls: vmStats.crossContractCalls || 0
|
|
695
|
+
},
|
|
696
|
+
features: [
|
|
697
|
+
'ZERO_FEES',
|
|
698
|
+
'UNIFIED_VM',
|
|
699
|
+
'NO_BRIDGES',
|
|
700
|
+
'CROSS_CHAIN_INTEROP'
|
|
701
|
+
]
|
|
702
|
+
});
|
|
560
703
|
});
|
|
561
704
|
|
|
562
705
|
return new Promise((resolve) => {
|
|
@@ -566,6 +709,284 @@ class EmbeddedRpcServer {
|
|
|
566
709
|
});
|
|
567
710
|
}
|
|
568
711
|
|
|
712
|
+
async _handleMethod(method, params) {
|
|
713
|
+
switch (method) {
|
|
714
|
+
// ═══════════════════════════════════════════════════════════════
|
|
715
|
+
// STANDARD ETHEREUM-COMPATIBLE METHODS
|
|
716
|
+
// ═══════════════════════════════════════════════════════════════
|
|
717
|
+
case 'eth_chainId':
|
|
718
|
+
return '0x' + (this.blockchain?.chainId || 4545).toString(16);
|
|
719
|
+
|
|
720
|
+
case 'eth_blockNumber':
|
|
721
|
+
case 'jaelis_blockNumber':
|
|
722
|
+
return '0x' + (this.blockchain?.getHeight?.() || 0).toString(16);
|
|
723
|
+
|
|
724
|
+
case 'eth_getBlockByNumber':
|
|
725
|
+
const blockNum = parseInt(params[0], 16);
|
|
726
|
+
return this.blockchain?.getBlock?.(blockNum) || null;
|
|
727
|
+
|
|
728
|
+
case 'eth_sendTransaction':
|
|
729
|
+
case 'eth_sendRawTransaction':
|
|
730
|
+
return this._sendTransaction(params[0]);
|
|
731
|
+
|
|
732
|
+
case 'eth_call':
|
|
733
|
+
return this._call(params[0], params[1]);
|
|
734
|
+
|
|
735
|
+
case 'eth_getTransactionReceipt':
|
|
736
|
+
return this.blockchain?.vmExecutor?.getReceipt?.(params[0]) || null;
|
|
737
|
+
|
|
738
|
+
// ═══════════════════════════════════════════════════════════════
|
|
739
|
+
// JAELIS-SPECIFIC METHODS (Unified VM)
|
|
740
|
+
// ═══════════════════════════════════════════════════════════════
|
|
741
|
+
case 'jaelis_getHealth':
|
|
742
|
+
return {
|
|
743
|
+
status: 'healthy',
|
|
744
|
+
chainId: this.blockchain?.chainId,
|
|
745
|
+
blockHeight: this.blockchain?.getHeight?.() || 0,
|
|
746
|
+
vmActive: !!this.blockchain?.vmExecutor
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
case 'jaelis_deployContract':
|
|
750
|
+
// Deploy contract in ANY language!
|
|
751
|
+
// params: [source, language, options]
|
|
752
|
+
return this._deployContract(params[0], params[1], params[2] || {});
|
|
753
|
+
|
|
754
|
+
case 'jaelis_executeContract':
|
|
755
|
+
// Execute contract call
|
|
756
|
+
// params: [to, functionName, args, options]
|
|
757
|
+
return this._executeContract(params[0], params[1], params[2] || [], params[3] || {});
|
|
758
|
+
|
|
759
|
+
case 'jaelis_crossContractCall':
|
|
760
|
+
// Cross-contract call (NO BRIDGES!)
|
|
761
|
+
// params: [fromContract, toContract, functionName, args]
|
|
762
|
+
return this._crossContractCall(params[0], params[1], params[2], params[3] || []);
|
|
763
|
+
|
|
764
|
+
case 'jaelis_getContracts':
|
|
765
|
+
return this.blockchain?.getContracts?.() || [];
|
|
766
|
+
|
|
767
|
+
case 'jaelis_getVMStats':
|
|
768
|
+
return this.blockchain?.getVMStats?.() || { vmAvailable: false };
|
|
769
|
+
|
|
770
|
+
case 'jaelis_getSupportedLanguages':
|
|
771
|
+
return ['solidity', 'rust', 'move', 'func', 'cairo', 'vyper'];
|
|
772
|
+
|
|
773
|
+
// ═══════════════════════════════════════════════════════════════
|
|
774
|
+
// CROSS-CHAIN SETTLEMENT METHODS (Universal State Layer!)
|
|
775
|
+
// ═══════════════════════════════════════════════════════════════
|
|
776
|
+
|
|
777
|
+
case 'jaelis_crossChain_getChains':
|
|
778
|
+
// Get all registered chains
|
|
779
|
+
return this._getCrossChainRegistry();
|
|
780
|
+
|
|
781
|
+
case 'jaelis_crossChain_getChainInfo':
|
|
782
|
+
// Get info for specific chain ID
|
|
783
|
+
return this._getCrossChainInfo(params[0]);
|
|
784
|
+
|
|
785
|
+
case 'jaelis_crossChain_readState':
|
|
786
|
+
// Read settled state from external chain
|
|
787
|
+
// params: [chainId, contractAddress, variableName]
|
|
788
|
+
return this._readCrossChainState(params[0], params[1], params[2]);
|
|
789
|
+
|
|
790
|
+
case 'jaelis_crossChain_settleState':
|
|
791
|
+
// Settle external chain state with proof
|
|
792
|
+
// params: [chainId, contractAddress, variableName, value, proof]
|
|
793
|
+
return this._settleCrossChainState(params[0], params[1], params[2], params[3], params[4]);
|
|
794
|
+
|
|
795
|
+
case 'jaelis_crossChain_getStateDiff':
|
|
796
|
+
// Get state diff between two chains
|
|
797
|
+
// params: [chainId1, chainId2, contractAddress, variableNames]
|
|
798
|
+
return this._getCrossChainStateDiff(params[0], params[1], params[2], params[3]);
|
|
799
|
+
|
|
800
|
+
case 'jaelis_crossChain_computeSlot':
|
|
801
|
+
// Compute namespaced storage slot
|
|
802
|
+
// params: [chainId, contractAddress, variableName]
|
|
803
|
+
return this._computeCrossChainSlot(params[0], params[1], params[2]);
|
|
804
|
+
|
|
805
|
+
case 'jaelis_crossChain_getLightClientStatus':
|
|
806
|
+
// Get light client status for a chain
|
|
807
|
+
return this._getLightClientStatus(params[0]);
|
|
808
|
+
|
|
809
|
+
case 'jaelis_crossChain_getSettlements':
|
|
810
|
+
// Get all settlements for a contract
|
|
811
|
+
// params: [chainId, contractAddress]
|
|
812
|
+
return this._getSettlements(params[0], params[1]);
|
|
813
|
+
|
|
814
|
+
case 'jaelis_crossChain_getStats':
|
|
815
|
+
// Get cross-chain stats
|
|
816
|
+
return this._getCrossChainStats();
|
|
817
|
+
|
|
818
|
+
default:
|
|
819
|
+
throw new Error(`Method not found: ${method}`);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
async _sendTransaction(tx) {
|
|
824
|
+
if (!this.blockchain) throw new Error('Blockchain not available');
|
|
825
|
+
const result = await this.blockchain.processTransaction(tx);
|
|
826
|
+
return result.transactionHash || '0x0';
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
async _call(callObject) {
|
|
830
|
+
if (!this.blockchain?.vmExecutor) throw new Error('VM not available');
|
|
831
|
+
const result = await this.blockchain.vmExecutor.executeCall(
|
|
832
|
+
callObject.to,
|
|
833
|
+
callObject.data?.functionName || 'call',
|
|
834
|
+
callObject.data?.args || [],
|
|
835
|
+
{ from: callObject.from }
|
|
836
|
+
);
|
|
837
|
+
return result.returnValue;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
async _deployContract(source, language, options) {
|
|
841
|
+
if (!this.blockchain) throw new Error('Blockchain not available');
|
|
842
|
+
console.log(`[RPC] Deploying ${language} contract...`);
|
|
843
|
+
const result = await this.blockchain.deployContract(source, language, options);
|
|
844
|
+
return {
|
|
845
|
+
address: result.address,
|
|
846
|
+
language,
|
|
847
|
+
gasUsed: 0 // ZERO FEES!
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
async _executeContract(to, functionName, args, options) {
|
|
852
|
+
if (!this.blockchain) throw new Error('Blockchain not available');
|
|
853
|
+
return this.blockchain.executeContract(to, functionName, args, options);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
async _crossContractCall(from, to, functionName, args) {
|
|
857
|
+
if (!this.blockchain) throw new Error('Blockchain not available');
|
|
858
|
+
console.log(`[RPC] Cross-call: ${from.substring(0, 10)}... → ${to.substring(0, 10)}...::${functionName}`);
|
|
859
|
+
return this.blockchain.crossContractCall(from, to, functionName, args);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// ═══════════════════════════════════════════════════════════════
|
|
863
|
+
// CROSS-CHAIN SETTLEMENT IMPLEMENTATIONS
|
|
864
|
+
// ═══════════════════════════════════════════════════════════════
|
|
865
|
+
|
|
866
|
+
_getCrossChainRegistry() {
|
|
867
|
+
// Return the VM's cross-chain registry if available
|
|
868
|
+
if (this.blockchain?.vmExecutor?.vm?.getAllChains) {
|
|
869
|
+
return this.blockchain.vmExecutor.vm.getAllChains();
|
|
870
|
+
}
|
|
871
|
+
// Fallback: return hardcoded registry
|
|
872
|
+
return {
|
|
873
|
+
JAELIS_MAINNET: { id: 4547, name: 'JAELIS Mainnet', type: 'native', status: 'upcoming' },
|
|
874
|
+
JAELIS_TESTNET: { id: 4545, name: 'JAELIS Testnet', type: 'native', status: 'live' },
|
|
875
|
+
ETH_MAINNET: { id: 1, name: 'Ethereum Mainnet', type: 'evm' },
|
|
876
|
+
ETH_SEPOLIA: { id: 11155111, name: 'Ethereum Sepolia', type: 'evm' },
|
|
877
|
+
POLYGON: { id: 137, name: 'Polygon PoS', type: 'evm' },
|
|
878
|
+
ARBITRUM_ONE: { id: 42161, name: 'Arbitrum One', type: 'evm' },
|
|
879
|
+
OPTIMISM: { id: 10, name: 'OP Mainnet', type: 'evm' },
|
|
880
|
+
BASE: { id: 8453, name: 'Base', type: 'evm' },
|
|
881
|
+
AVALANCHE_C: { id: 43114, name: 'Avalanche C-Chain', type: 'evm' },
|
|
882
|
+
BSC: { id: 56, name: 'BNB Smart Chain', type: 'evm' },
|
|
883
|
+
SOLANA_MAINNET: { id: 101, name: 'Solana Mainnet', type: 'svm', cluster: 'mainnet-beta' },
|
|
884
|
+
SOLANA_DEVNET: { id: 102, name: 'Solana Devnet', type: 'svm', cluster: 'devnet' },
|
|
885
|
+
APTOS_MAINNET: { id: 1, name: 'Aptos Mainnet', type: 'move', network: 'aptos' },
|
|
886
|
+
SUI_MAINNET: { id: 1, name: 'Sui Mainnet', type: 'move', network: 'sui' },
|
|
887
|
+
TON_MAINNET: { id: -1, name: 'TON Mainnet', type: 'tvm', workchain: -1 }
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
_getCrossChainInfo(chainId) {
|
|
892
|
+
const chains = this._getCrossChainRegistry();
|
|
893
|
+
const chain = Object.values(chains).find(c => c.id === chainId);
|
|
894
|
+
return chain || { error: 'Chain not found', chainId };
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
async _readCrossChainState(chainId, contractAddress, variableName) {
|
|
898
|
+
if (this.blockchain?.vmExecutor?.vm?.readCrossChainState) {
|
|
899
|
+
const value = this.blockchain.vmExecutor.vm.readCrossChainState(chainId, contractAddress, variableName);
|
|
900
|
+
return {
|
|
901
|
+
chainId,
|
|
902
|
+
contractAddress,
|
|
903
|
+
variableName,
|
|
904
|
+
value: value ? '0x' + value.toString('hex') : '0x0',
|
|
905
|
+
settled: value ? true : false
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
return { error: 'Cross-chain state not available', chainId, contractAddress, variableName };
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
async _settleCrossChainState(chainId, contractAddress, variableName, value, proof) {
|
|
912
|
+
if (this.blockchain?.vmExecutor?.vm?.settleExternalState) {
|
|
913
|
+
const valueBuffer = Buffer.from(value.replace('0x', ''), 'hex');
|
|
914
|
+
const result = await this.blockchain.vmExecutor.vm.settleExternalState(
|
|
915
|
+
chainId, contractAddress, variableName, valueBuffer, proof
|
|
916
|
+
);
|
|
917
|
+
console.log(`[RPC] Cross-chain settlement: Chain ${chainId} → ${variableName}`);
|
|
918
|
+
return {
|
|
919
|
+
success: true,
|
|
920
|
+
chainId,
|
|
921
|
+
contractAddress,
|
|
922
|
+
variableName,
|
|
923
|
+
slot: result.slot ? '0x' + result.slot.toString('hex') : null,
|
|
924
|
+
settlement: result.settlement
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
return { error: 'Cross-chain settlement not available' };
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
_getCrossChainStateDiff(chainId1, chainId2, contractAddress, variableNames) {
|
|
931
|
+
if (this.blockchain?.vmExecutor?.vm?.getCrossChainStateDiff) {
|
|
932
|
+
return this.blockchain.vmExecutor.vm.getCrossChainStateDiff(
|
|
933
|
+
chainId1, chainId2, contractAddress, variableNames
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
return { error: 'State diff not available', chainId1, chainId2 };
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
_computeCrossChainSlot(chainId, contractAddress, variableName) {
|
|
940
|
+
if (this.blockchain?.vmExecutor?.vm?.computeCrossChainSlot) {
|
|
941
|
+
const slot = this.blockchain.vmExecutor.vm.computeCrossChainSlot(chainId, contractAddress, variableName);
|
|
942
|
+
return '0x' + slot.toString('hex');
|
|
943
|
+
}
|
|
944
|
+
// Fallback: compute locally
|
|
945
|
+
const crypto = require('crypto');
|
|
946
|
+
const data = Buffer.concat([
|
|
947
|
+
Buffer.alloc(4), // chainId placeholder
|
|
948
|
+
Buffer.from(contractAddress.replace('0x', ''), 'hex'),
|
|
949
|
+
Buffer.from(variableName, 'utf8')
|
|
950
|
+
]);
|
|
951
|
+
data.writeUInt32LE(chainId, 0);
|
|
952
|
+
return '0x' + crypto.createHash('sha256').update(data).digest('hex');
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
_getLightClientStatus(chainId) {
|
|
956
|
+
if (this.blockchain?.vmExecutor?.vm?.crossChainManager?.stateStore?.lightClients) {
|
|
957
|
+
const client = this.blockchain.vmExecutor.vm.crossChainManager.stateStore.lightClients.get(chainId);
|
|
958
|
+
if (client) {
|
|
959
|
+
return {
|
|
960
|
+
chainId,
|
|
961
|
+
synced: client.synced || false,
|
|
962
|
+
latestBlock: client.latestBlock || 0,
|
|
963
|
+
stateRoot: client.latestStateRoot ? '0x' + client.latestStateRoot.toString('hex') : null
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
return { chainId, synced: false, error: 'Light client not available' };
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
_getSettlements(chainId, contractAddress) {
|
|
971
|
+
if (this.blockchain?.vmExecutor?.vm?.crossChainManager?.stateStore?.settlementLog) {
|
|
972
|
+
const log = this.blockchain.vmExecutor.vm.crossChainManager.stateStore.settlementLog;
|
|
973
|
+
return log.filter(s => s.chainId === chainId && s.contractAddress === contractAddress);
|
|
974
|
+
}
|
|
975
|
+
return [];
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
_getCrossChainStats() {
|
|
979
|
+
if (this.blockchain?.vmExecutor?.vm?.crossChainManager?.getStats) {
|
|
980
|
+
return this.blockchain.vmExecutor.vm.crossChainManager.getStats();
|
|
981
|
+
}
|
|
982
|
+
return {
|
|
983
|
+
totalSettlements: 0,
|
|
984
|
+
chainsActive: 0,
|
|
985
|
+
lightClientsRegistered: 0,
|
|
986
|
+
stateSize: 0
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
|
|
569
990
|
async stop() {
|
|
570
991
|
if (this.server) {
|
|
571
992
|
this.server.close();
|
package/lib/vm/index.js
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JAELIS UNIFIED VM INTEGRATION
|
|
3
|
+
*
|
|
4
|
+
* Wires the UnifiedJaelisVM (NO BRIDGES, NO ADAPTERS!) into the JAELIS blockchain
|
|
5
|
+
* for smart contract execution.
|
|
6
|
+
*
|
|
7
|
+
* This is THE execution engine - all contracts from ALL languages run here:
|
|
8
|
+
* - Solidity (EVM)
|
|
9
|
+
* - Rust (Solana)
|
|
10
|
+
* - Move (Aptos/Sui)
|
|
11
|
+
* - FunC (TON)
|
|
12
|
+
* - Cairo (Starknet)
|
|
13
|
+
*
|
|
14
|
+
* Key Features:
|
|
15
|
+
* - TRUE cross-chain interoperability (NO BRIDGES!)
|
|
16
|
+
* - Dynamic contracts (auto-update when VMs change)
|
|
17
|
+
* - JAELIS ABI (ONE encoding for all)
|
|
18
|
+
* - ZERO FEES (ENE system)
|
|
19
|
+
*
|
|
20
|
+
* @version 1.0.0
|
|
21
|
+
* @author Mario Papaleo - JAELIS Foundation
|
|
22
|
+
* @patent PATENT PENDING - Unified Cross-Chain Virtual Machine
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const path = require('path');
|
|
26
|
+
const EventEmitter = require('events');
|
|
27
|
+
|
|
28
|
+
// Import the Unified VM from JAELIS-VM
|
|
29
|
+
let UnifiedJaelisVM, JaelisABI, DynamicContractManager;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const vmPath = path.resolve(__dirname, '../../../JAELIS-VM/lib/unified');
|
|
33
|
+
const unified = require(vmPath);
|
|
34
|
+
UnifiedJaelisVM = unified.UnifiedJaelisVM;
|
|
35
|
+
JaelisABI = unified.JaelisABI;
|
|
36
|
+
DynamicContractManager = unified.DynamicContractManager;
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.warn('[JAELIS-VM] Could not load UnifiedJaelisVM from relative path, trying npm...');
|
|
39
|
+
try {
|
|
40
|
+
const unified = require('jaelis-vm/lib/unified');
|
|
41
|
+
UnifiedJaelisVM = unified.UnifiedJaelisVM;
|
|
42
|
+
JaelisABI = unified.JaelisABI;
|
|
43
|
+
DynamicContractManager = unified.DynamicContractManager;
|
|
44
|
+
} catch (e2) {
|
|
45
|
+
console.warn('[JAELIS-VM] UnifiedJaelisVM not available, using fallback');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* VMExecutor - Executes smart contracts on the JAELIS blockchain
|
|
51
|
+
*
|
|
52
|
+
* This wraps the UnifiedJaelisVM and provides blockchain-specific functionality:
|
|
53
|
+
* - Transaction processing
|
|
54
|
+
* - State commitment to blockchain
|
|
55
|
+
* - Event emission for block inclusion
|
|
56
|
+
* - Gas-less execution (ENE system)
|
|
57
|
+
*/
|
|
58
|
+
class VMExecutor extends EventEmitter {
|
|
59
|
+
constructor(blockchain, options = {}) {
|
|
60
|
+
super();
|
|
61
|
+
|
|
62
|
+
this.blockchain = blockchain;
|
|
63
|
+
this.options = options;
|
|
64
|
+
|
|
65
|
+
// Initialize the Unified VM (NO BRIDGES!)
|
|
66
|
+
if (UnifiedJaelisVM) {
|
|
67
|
+
this.vm = new UnifiedJaelisVM({
|
|
68
|
+
...options,
|
|
69
|
+
enableLogging: options.debug || false
|
|
70
|
+
});
|
|
71
|
+
console.log('[VMExecutor] Unified VM initialized - NO BRIDGES, NO ADAPTERS!');
|
|
72
|
+
} else {
|
|
73
|
+
this.vm = null;
|
|
74
|
+
console.log('[VMExecutor] Running in light mode (no VM)');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Contract address mapping
|
|
78
|
+
this.contracts = new Map();
|
|
79
|
+
|
|
80
|
+
// Pending state changes (committed on block finalization)
|
|
81
|
+
this.pendingStateChanges = [];
|
|
82
|
+
|
|
83
|
+
// Transaction receipts
|
|
84
|
+
this.receipts = new Map();
|
|
85
|
+
|
|
86
|
+
// Stats
|
|
87
|
+
this.stats = {
|
|
88
|
+
contractsDeployed: 0,
|
|
89
|
+
transactionsExecuted: 0,
|
|
90
|
+
crossContractCalls: 0,
|
|
91
|
+
totalGasUsed: 0 // Always 0 - ZERO FEES!
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Deploy a smart contract
|
|
97
|
+
*
|
|
98
|
+
* Supports ANY language:
|
|
99
|
+
* - Solidity, Vyper (EVM)
|
|
100
|
+
* - Rust/Anchor (Solana)
|
|
101
|
+
* - Move (Aptos/Sui)
|
|
102
|
+
* - FunC (TON)
|
|
103
|
+
* - Cairo (Starknet)
|
|
104
|
+
*/
|
|
105
|
+
async deployContract(source, language, options = {}) {
|
|
106
|
+
if (!this.vm) {
|
|
107
|
+
throw new Error('VM not available - run in full node mode');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const deployer = options.from || options.deployer || '0x0';
|
|
111
|
+
|
|
112
|
+
console.log(`[VMExecutor] Deploying ${language} contract...`);
|
|
113
|
+
|
|
114
|
+
// Deploy through Unified VM
|
|
115
|
+
const result = await this.vm.deploy(source, language, {
|
|
116
|
+
...options,
|
|
117
|
+
deployer
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Store in local registry
|
|
121
|
+
this.contracts.set(result.address, {
|
|
122
|
+
address: result.address,
|
|
123
|
+
language,
|
|
124
|
+
deployedAt: Date.now(),
|
|
125
|
+
deployer,
|
|
126
|
+
bytecodeHash: result.bytecode ?
|
|
127
|
+
require('crypto').createHash('sha256').update(result.bytecode).digest('hex') : null
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
this.stats.contractsDeployed++;
|
|
131
|
+
|
|
132
|
+
// Emit event for block inclusion
|
|
133
|
+
this.emit('contractDeployed', {
|
|
134
|
+
address: result.address,
|
|
135
|
+
language,
|
|
136
|
+
deployer,
|
|
137
|
+
blockNumber: this.blockchain?.getHeight?.() || 0
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
console.log(`[VMExecutor] Contract deployed: ${result.address.substring(0, 20)}...`);
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
address: result.address,
|
|
144
|
+
abi: result.abi,
|
|
145
|
+
language,
|
|
146
|
+
gasUsed: 0 // ZERO FEES!
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Execute a contract call
|
|
152
|
+
*/
|
|
153
|
+
async executeCall(to, functionName, args = [], options = {}) {
|
|
154
|
+
if (!this.vm) {
|
|
155
|
+
throw new Error('VM not available');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const from = options.from || '0x0';
|
|
159
|
+
const value = options.value || 0;
|
|
160
|
+
|
|
161
|
+
console.log(`[VMExecutor] Executing ${functionName} on ${to.substring(0, 16)}...`);
|
|
162
|
+
|
|
163
|
+
// Execute through Unified VM
|
|
164
|
+
const result = await this.vm.execute(to, functionName, args, {
|
|
165
|
+
from,
|
|
166
|
+
value,
|
|
167
|
+
blockNumber: this.blockchain?.getHeight?.() || 0,
|
|
168
|
+
timestamp: Date.now()
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
this.stats.transactionsExecuted++;
|
|
172
|
+
|
|
173
|
+
// Create receipt
|
|
174
|
+
const receipt = {
|
|
175
|
+
transactionHash: this._generateTxHash(to, functionName, args, from),
|
|
176
|
+
blockNumber: this.blockchain?.getHeight?.() || 0,
|
|
177
|
+
from,
|
|
178
|
+
to,
|
|
179
|
+
status: result.success ? 1 : 0,
|
|
180
|
+
gasUsed: 0, // ZERO FEES!
|
|
181
|
+
logs: result.logs || [],
|
|
182
|
+
returnValue: result.returnValue
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
this.receipts.set(receipt.transactionHash, receipt);
|
|
186
|
+
|
|
187
|
+
// Emit for block inclusion
|
|
188
|
+
this.emit('transactionExecuted', receipt);
|
|
189
|
+
|
|
190
|
+
return receipt;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Cross-contract call (NO BRIDGES!)
|
|
195
|
+
*
|
|
196
|
+
* This is THE key innovation - contracts from ANY VM can call each other DIRECTLY
|
|
197
|
+
*/
|
|
198
|
+
async crossContractCall(fromContract, toContract, functionName, args = [], options = {}) {
|
|
199
|
+
if (!this.vm) {
|
|
200
|
+
throw new Error('VM not available');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
console.log(`[VMExecutor] Cross-call: ${fromContract.substring(0, 10)}... → ${toContract.substring(0, 10)}...::${functionName}`);
|
|
204
|
+
console.log(`[VMExecutor] NO BRIDGE! NO ADAPTER! Direct execution.`);
|
|
205
|
+
|
|
206
|
+
// Execute through Unified VM's cross-call
|
|
207
|
+
const result = await this.vm.crossCall(fromContract, toContract, functionName, args);
|
|
208
|
+
|
|
209
|
+
this.stats.crossContractCalls++;
|
|
210
|
+
|
|
211
|
+
// Emit event
|
|
212
|
+
this.emit('crossContractCall', {
|
|
213
|
+
from: fromContract,
|
|
214
|
+
to: toContract,
|
|
215
|
+
function: functionName,
|
|
216
|
+
success: result.success,
|
|
217
|
+
blockNumber: this.blockchain?.getHeight?.() || 0
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Process a transaction
|
|
225
|
+
*
|
|
226
|
+
* This is called by the blockchain when a new transaction arrives
|
|
227
|
+
*/
|
|
228
|
+
async processTransaction(tx) {
|
|
229
|
+
// Validate transaction
|
|
230
|
+
if (!tx.to && !tx.data) {
|
|
231
|
+
throw new Error('Invalid transaction: no target or data');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Contract deployment (no 'to' address)
|
|
235
|
+
if (!tx.to && tx.data) {
|
|
236
|
+
// Detect language from data or metadata
|
|
237
|
+
const language = tx.language || this._detectLanguage(tx.data);
|
|
238
|
+
return this.deployContract(tx.data, language, {
|
|
239
|
+
from: tx.from,
|
|
240
|
+
value: tx.value
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Contract call
|
|
245
|
+
if (tx.to && tx.data) {
|
|
246
|
+
const { functionName, args } = this._decodeCalldata(tx.data);
|
|
247
|
+
return this.executeCall(tx.to, functionName, args, {
|
|
248
|
+
from: tx.from,
|
|
249
|
+
value: tx.value
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Simple transfer (no data)
|
|
254
|
+
return this._processTransfer(tx);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Get contract information
|
|
259
|
+
*/
|
|
260
|
+
getContract(address) {
|
|
261
|
+
return this.contracts.get(address) || null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Get all deployed contracts
|
|
266
|
+
*/
|
|
267
|
+
getAllContracts() {
|
|
268
|
+
return Array.from(this.contracts.values());
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Get transaction receipt
|
|
273
|
+
*/
|
|
274
|
+
getReceipt(txHash) {
|
|
275
|
+
return this.receipts.get(txHash) || null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Get VM stats
|
|
280
|
+
*/
|
|
281
|
+
getStats() {
|
|
282
|
+
const vmStats = this.vm?.getStats?.() || {};
|
|
283
|
+
return {
|
|
284
|
+
...this.stats,
|
|
285
|
+
...vmStats,
|
|
286
|
+
vmAvailable: !!this.vm
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Encode function call using JAELIS ABI
|
|
292
|
+
*/
|
|
293
|
+
encodeCall(functionName, args, types) {
|
|
294
|
+
if (JaelisABI) {
|
|
295
|
+
return JaelisABI.encodeFunctionCall(functionName, args, types);
|
|
296
|
+
}
|
|
297
|
+
// Fallback encoding
|
|
298
|
+
return Buffer.from(JSON.stringify({ functionName, args }));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Decode function call
|
|
303
|
+
*/
|
|
304
|
+
decodeCall(data) {
|
|
305
|
+
if (JaelisABI) {
|
|
306
|
+
return JaelisABI.decodeFunctionCall(data);
|
|
307
|
+
}
|
|
308
|
+
// Fallback decoding
|
|
309
|
+
try {
|
|
310
|
+
return JSON.parse(data.toString());
|
|
311
|
+
} catch {
|
|
312
|
+
return { functionName: 'unknown', args: [] };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ═══════════════════════════════════════════════════════════════
|
|
317
|
+
// PRIVATE METHODS
|
|
318
|
+
// ═══════════════════════════════════════════════════════════════
|
|
319
|
+
|
|
320
|
+
_generateTxHash(to, functionName, args, from) {
|
|
321
|
+
const crypto = require('crypto');
|
|
322
|
+
return '0x' + crypto.createHash('sha256')
|
|
323
|
+
.update(JSON.stringify({ to, functionName, args, from, timestamp: Date.now() }))
|
|
324
|
+
.digest('hex');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
_detectLanguage(data) {
|
|
328
|
+
const code = typeof data === 'string' ? data : data.toString();
|
|
329
|
+
|
|
330
|
+
// Detect by patterns
|
|
331
|
+
if (code.includes('contract ') && code.includes('function ')) return 'solidity';
|
|
332
|
+
if (code.includes('#[program]') || code.includes('pub mod ')) return 'rust';
|
|
333
|
+
if (code.includes('module ') && code.includes('public fun ')) return 'move';
|
|
334
|
+
if (code.includes('recv_internal') || code.includes('method_id')) return 'func';
|
|
335
|
+
if (code.includes('#[contract]') && code.includes('fn ')) return 'cairo';
|
|
336
|
+
|
|
337
|
+
return 'solidity'; // Default
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
_decodeCalldata(data) {
|
|
341
|
+
// If it's already JSON
|
|
342
|
+
if (typeof data === 'object' && data.functionName) {
|
|
343
|
+
return data;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Try JAELIS ABI decode
|
|
347
|
+
if (JaelisABI && Buffer.isBuffer(data)) {
|
|
348
|
+
try {
|
|
349
|
+
return JaelisABI.decodeFunctionCall(data);
|
|
350
|
+
} catch {
|
|
351
|
+
// Fall through
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Try JSON
|
|
356
|
+
try {
|
|
357
|
+
return JSON.parse(data.toString());
|
|
358
|
+
} catch {
|
|
359
|
+
return { functionName: 'fallback', args: [] };
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async _processTransfer(tx) {
|
|
364
|
+
// Simple value transfer (no contract execution)
|
|
365
|
+
const receipt = {
|
|
366
|
+
transactionHash: this._generateTxHash(tx.to, 'transfer', [tx.value], tx.from),
|
|
367
|
+
blockNumber: this.blockchain?.getHeight?.() || 0,
|
|
368
|
+
from: tx.from,
|
|
369
|
+
to: tx.to,
|
|
370
|
+
value: tx.value,
|
|
371
|
+
status: 1,
|
|
372
|
+
gasUsed: 0 // ZERO FEES!
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
this.receipts.set(receipt.transactionHash, receipt);
|
|
376
|
+
this.emit('transfer', receipt);
|
|
377
|
+
|
|
378
|
+
return receipt;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Factory function to create VM executor
|
|
384
|
+
*/
|
|
385
|
+
function createVMExecutor(blockchain, options = {}) {
|
|
386
|
+
return new VMExecutor(blockchain, options);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
module.exports = {
|
|
390
|
+
VMExecutor,
|
|
391
|
+
createVMExecutor,
|
|
392
|
+
|
|
393
|
+
// Re-export VM components
|
|
394
|
+
UnifiedJaelisVM,
|
|
395
|
+
JaelisABI,
|
|
396
|
+
DynamicContractManager
|
|
397
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jaelis-node",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Official JAELIS Blockchain Node - Run a full node, validator, or bootstrap node
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Official JAELIS Blockchain Node - Run a full node, validator, or bootstrap node with Cross-Chain Settlement (30+ chains!)",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"jaelis-node": "./bin/jaelis-node.js"
|
|
@@ -35,7 +35,16 @@
|
|
|
35
35
|
"mcp",
|
|
36
36
|
"full-node",
|
|
37
37
|
"bootstrap-node",
|
|
38
|
-
"rpc-server"
|
|
38
|
+
"rpc-server",
|
|
39
|
+
"cross-chain",
|
|
40
|
+
"settlement",
|
|
41
|
+
"light-client",
|
|
42
|
+
"interoperability",
|
|
43
|
+
"universal-state",
|
|
44
|
+
"solana",
|
|
45
|
+
"arbitrum",
|
|
46
|
+
"polygon",
|
|
47
|
+
"optimism"
|
|
39
48
|
],
|
|
40
49
|
"author": "JAELIS Foundation",
|
|
41
50
|
"license": "MIT",
|