Browse Source

:sparkles: Added the `ephemeral-validator` to `bolt test`

Danilo Guanabara 7 months ago
parent
commit
8b89b4225c

+ 1 - 7
Anchor.toml

@@ -36,13 +36,7 @@ members = [
 ]
 ]
 
 
 [scripts]
 [scripts]
-test = """
-echo "Waiting for 5 seconds..."
-sleep 5
-yarn run ts-mocha -p ./tsconfig.json -t 1000000 clients/typescript/test/main.ts
-cd clients/csharp/Solana.Unity.Bolt.Test
-dotnet run --configuration Release
-"""
+test = "tests/script.sh"
 
 
 [test]
 [test]
 startup_wait = 15000
 startup_wait = 15000

+ 107 - 3
Cargo.lock

@@ -898,10 +898,14 @@ dependencies = [
  "anchor-lang-idl",
  "anchor-lang-idl",
  "anchor-syn",
  "anchor-syn",
  "anyhow",
  "anyhow",
+ "bytemuck_derive",
  "clap 4.5.22",
  "clap 4.5.22",
  "heck 0.5.0",
  "heck 0.5.0",
  "serde_json",
  "serde_json",
  "syn 1.0.109",
  "syn 1.0.109",
+ "sysinfo",
+ "tokio",
+ "which",
  "world",
  "world",
 ]
 ]
 
 
@@ -1138,9 +1142,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "bytemuck_derive"
 name = "bytemuck_derive"
-version = "1.7.1"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26"
+checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
 dependencies = [
 dependencies = [
  "proc-macro2",
  "proc-macro2",
  "quote",
  "quote",
@@ -1828,6 +1832,12 @@ dependencies = [
  "syn 2.0.79",
  "syn 2.0.79",
 ]
 ]
 
 
+[[package]]
+name = "env_home"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
+
 [[package]]
 [[package]]
 name = "env_logger"
 name = "env_logger"
 version = "0.9.3"
 version = "0.9.3"
@@ -2344,7 +2354,7 @@ dependencies = [
  "iana-time-zone-haiku",
  "iana-time-zone-haiku",
  "js-sys",
  "js-sys",
  "wasm-bindgen",
  "wasm-bindgen",
- "windows-core",
+ "windows-core 0.52.0",
 ]
 ]
 
 
 [[package]]
 [[package]]
@@ -2956,6 +2966,15 @@ dependencies = [
  "minimal-lexical",
  "minimal-lexical",
 ]
 ]
 
 
+[[package]]
+name = "ntapi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 [[package]]
 name = "num"
 name = "num"
 version = "0.2.1"
 version = "0.2.1"
@@ -5396,6 +5415,20 @@ dependencies = [
  "syn 2.0.79",
  "syn 2.0.79",
 ]
 ]
 
 
+[[package]]
+name = "sysinfo"
+version = "0.33.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+ "memchr",
+ "ntapi",
+ "rayon",
+ "windows",
+]
+
 [[package]]
 [[package]]
 name = "system-apply-velocity"
 name = "system-apply-velocity"
 version = "0.2.2"
 version = "0.2.2"
@@ -6115,6 +6148,18 @@ version = "0.25.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
 checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
 
 
+[[package]]
+name = "which"
+version = "7.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283"
+dependencies = [
+ "either",
+ "env_home",
+ "rustix",
+ "winsafe",
+]
+
 [[package]]
 [[package]]
 name = "winapi"
 name = "winapi"
 version = "0.3.9"
 version = "0.3.9"
@@ -6146,6 +6191,16 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 
+[[package]]
+name = "windows"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
+dependencies = [
+ "windows-core 0.57.0",
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 [[package]]
 name = "windows-core"
 name = "windows-core"
 version = "0.52.0"
 version = "0.52.0"
@@ -6155,6 +6210,49 @@ dependencies = [
  "windows-targets 0.52.6",
  "windows-targets 0.52.6",
 ]
 ]
 
 
+[[package]]
+name = "windows-core"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-result",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 [[package]]
 name = "windows-sys"
 name = "windows-sys"
 version = "0.48.0"
 version = "0.48.0"
@@ -6331,6 +6429,12 @@ dependencies = [
  "windows-sys 0.48.0",
  "windows-sys 0.48.0",
 ]
 ]
 
 
+[[package]]
+name = "winsafe"
+version = "0.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
+
 [[package]]
 [[package]]
 name = "world"
 name = "world"
 version = "0.2.2"
 version = "0.2.2"

+ 5 - 0
Cargo.toml

@@ -59,6 +59,11 @@ clap = { version = "4.2.4", features = ["derive"] }
 ahash = "=0.8.11"
 ahash = "=0.8.11"
 ephemeral-rollups-sdk = "=0.2.1"
 ephemeral-rollups-sdk = "=0.2.1"
 bincode = "=1.3.3"
 bincode = "=1.3.3"
+which = "7.0.2"
+tokio = { version = "1", features = ["full"] }
+sysinfo = "0.33.1"
+bytemuck_derive = "=1.8.1"
+
 
 
 [profile.release]
 [profile.release]
 overflow-checks = true
 overflow-checks = true

+ 9 - 0
README.md

@@ -29,6 +29,7 @@ With Bolt, you can create games that live forever on the blockchain. These games
 | `bolt-cli`                  | CLI to support building and managing a Bolt workspace                            | [![Crates.io](https://img.shields.io/crates/v/bolt-cli?color=blue)](https://crates.io/crates/bolt-cli)                                 | [![Docs](https://img.shields.io/badge/docs-tutorials-blue)](https://book.boltengine.gg/getting_started/installation.html) |
 | `bolt-cli`                  | CLI to support building and managing a Bolt workspace                            | [![Crates.io](https://img.shields.io/crates/v/bolt-cli?color=blue)](https://crates.io/crates/bolt-cli)                                 | [![Docs](https://img.shields.io/badge/docs-tutorials-blue)](https://book.boltengine.gg/getting_started/installation.html) |
 | `bolt-lang`                 | Rust primitives for creating components, systems and writing programs on Solana | [![Crates.io](https://img.shields.io/crates/v/bolt-lang?color=blue)](https://crates.io/crates/bolt-lang)                                 | [![Docs.rs](https://img.shields.io/badge/docs-tutorials-blue)](https://book.boltengine.gg/)                                    |
 | `bolt-lang`                 | Rust primitives for creating components, systems and writing programs on Solana | [![Crates.io](https://img.shields.io/crates/v/bolt-lang?color=blue)](https://crates.io/crates/bolt-lang)                                 | [![Docs.rs](https://img.shields.io/badge/docs-tutorials-blue)](https://book.boltengine.gg/)                                    |
 | `@magicblock-labs/bolt-sdk` | TypeScript client for Anchor programs                                            | [![npm](https://img.shields.io/npm/v/@magicblock-labs/bolt-sdk.svg?color=blue)](https://www.npmjs.com/package/@magicblock-labs/bolt-sdk)         | [![Docs](https://img.shields.io/badge/docs-tutorials-blue)](https://book.boltengine.gg/getting_started/world_program.html#typescript-sdk-installation)     |
 | `@magicblock-labs/bolt-sdk` | TypeScript client for Anchor programs                                            | [![npm](https://img.shields.io/npm/v/@magicblock-labs/bolt-sdk.svg?color=blue)](https://www.npmjs.com/package/@magicblock-labs/bolt-sdk)         | [![Docs](https://img.shields.io/badge/docs-tutorials-blue)](https://book.boltengine.gg/getting_started/world_program.html#typescript-sdk-installation)     |
+| `@magicblock-labs/ephemeral-validator` | MagicBlock's extremely fast Solana compatible validator | [![npm](https://img.shields.io/npm/v/@magicblock-labs/ephemeral-validator.svg?color=blue)](https://www.npmjs.com/package/@magicblock-labs/ephemeral-validator) | [![Docs](https://img.shields.io/badge/docs-tutorials-blue)](https://book.boltengine.gg/getting_started/ephemeral_validator.html) |
 
 
 ## ⚡️ Installing the bolt-cli
 ## ⚡️ Installing the bolt-cli
 
 
@@ -36,6 +37,14 @@ With Bolt, you can create games that live forever on the blockchain. These games
 cargo install bolt-cli
 cargo install bolt-cli
 ```
 ```
 
 
+## ⚡️ (Optional) Installing the ephemeral-validator
+
+To enable transaction acceleration on LocalNet, you can install MagicBlock's `ephemeral-validator`:
+
+```bash
+npm install -g @magicblock-labs/ephemeral-validator
+```
+
 ## 🔩️ Getting Started
 ## 🔩️ Getting Started
 
 
 Create a project with the bolt-cli:
 Create a project with the bolt-cli:

+ 61 - 0
clients/csharp/Solana.Unity.Bolt.Test/AccelerationTest.cs

@@ -0,0 +1,61 @@
+using Solana.Unity.Bolt.Test;
+using Solana.Unity.Rpc.Models;
+using Solana.Unity.Wallet;
+using Solana.Unity.Bolt;
+using Solana.Unity.Rpc;
+using System;
+using System.Threading.Tasks;
+using Solana.Unity.Wallet.Bip39;
+using World.Program;
+using System.Diagnostics;
+using Solana.Unity.Rpc.Types;
+namespace AccelerationTest {
+    public class Test {
+        public static async Task Run(Framework framework) {
+            await Profiler.Run("AddAccelerationEntity", async () => {
+                await AddAccelerationEntity(framework);
+            });
+            await Profiler.Run("InitializePositionComponentOnAccelerationEntity", async () => {
+                await InitializePositionComponentOnAccelerationEntity(framework);
+            });
+            await Profiler.Run("DelegateComponent", async () => {
+                await DelegateComponent(framework);
+            });
+            await Profiler.Run("ApplySimpleMovementSystemOnAccelerator 10", async () => {
+                await ApplySimpleMovementSystemOnAccelerator(framework);
+            });
+        }
+
+        public static async Task AddAccelerationEntity(Framework framework) {
+            var addEntity = await Bolt.World.AddEntity(framework.Client, framework.WorldPda, framework.Wallet.Account.PublicKey, Commitment.Processed);
+            framework.AccelerationEntityPda = addEntity.Pda;
+            await framework.SendAndConfirmInstruction(addEntity.Instruction);
+        }
+
+        public static async Task InitializePositionComponentOnAccelerationEntity(Framework framework) {
+            var initializeComponent = await Bolt.World.InitializeComponent(framework.Wallet.Account.PublicKey, framework.AccelerationEntityPda, framework.ExampleComponentPosition);
+            framework.AccelerationComponentPositionPda = initializeComponent.Pda;
+            await framework.SendAndConfirmInstruction(initializeComponent.Instruction);
+        }
+
+        public static async Task DelegateComponent(Framework framework) {
+            var delegateComponent = await Bolt.World.DelegateComponent(framework.Wallet.Account.PublicKey, framework.AccelerationEntityPda, framework.ExampleComponentPosition);
+            await framework.SendAndConfirmInstruction(delegateComponent.Instruction);
+        }
+
+        public static async Task ApplySimpleMovementSystemOnAccelerator(Framework framework) {
+            for (int i = 0; i < 10; i++) {
+                var apply = new ApplyAccounts() {
+                    Authority = framework.Wallet.Account.PublicKey,
+                    BoltSystem = framework.SystemSimpleMovement,
+                    World = framework.WorldPda,
+                };
+                var instruction = WorldProgram.Apply(apply, Bolt.World.SerializeArgs(new { direction = "Up" }));
+                instruction.Keys.Add(AccountMeta.ReadOnly(framework.ExampleComponentPosition, false));
+                instruction.Keys.Add(AccountMeta.Writable(framework.AccelerationComponentPositionPda, false));
+                await framework.SendAndConfirmInstruction(framework.AcceleratorClient, instruction);
+                await Task.Delay(50);
+            }
+        }
+   }
+}

+ 20 - 7
clients/csharp/Solana.Unity.Bolt.Test/Framework.cs

@@ -33,6 +33,7 @@ namespace Solana.Unity.Bolt.Test
     {
     {
         public Wallet.Wallet Wallet { get; set; }
         public Wallet.Wallet Wallet { get; set; }
         public IRpcClient Client { get; set; }
         public IRpcClient Client { get; set; }
+        public IRpcClient AcceleratorClient { get; set; }
         public PublicKey WorldPda { get; set; }
         public PublicKey WorldPda { get; set; }
         public ulong WorldId { get; set; }
         public ulong WorldId { get; set; }
         public PublicKey RegistryPda { get; set; }
         public PublicKey RegistryPda { get; set; }
@@ -43,6 +44,7 @@ namespace Solana.Unity.Bolt.Test
         public PublicKey Entity1Pda { get; set; }
         public PublicKey Entity1Pda { get; set; }
         public PublicKey Entity2Pda { get; set; }
         public PublicKey Entity2Pda { get; set; }
         public PublicKey Entity4Pda { get; set; }
         public PublicKey Entity4Pda { get; set; }
+        public PublicKey AccelerationEntityPda { get; set; }
         public PublicKey ExampleComponentPosition { get; set; }
         public PublicKey ExampleComponentPosition { get; set; }
         public PublicKey ExampleComponentVelocity { get; set; }
         public PublicKey ExampleComponentVelocity { get; set; }
         public PublicKey ComponentPositionEntity1Pda { get; set; }
         public PublicKey ComponentPositionEntity1Pda { get; set; }
@@ -50,6 +52,7 @@ namespace Solana.Unity.Bolt.Test
         public PublicKey ComponentPositionEntity2Pda { get; set; }
         public PublicKey ComponentPositionEntity2Pda { get; set; }
         public PublicKey ComponentPositionEntity4Pda { get; set; }
         public PublicKey ComponentPositionEntity4Pda { get; set; }
         public PublicKey SystemSimpleMovement { get; set; }
         public PublicKey SystemSimpleMovement { get; set; }
+        public PublicKey AccelerationComponentPositionPda { get; set; }
 
 
         public PublicKey SessionToken { get; set; }
         public PublicKey SessionToken { get; set; }
 
 
@@ -60,7 +63,7 @@ namespace Solana.Unity.Bolt.Test
             Wallet = new Wallet.Wallet(new Mnemonic(WordList.English, WordCount.Twelve));
             Wallet = new Wallet.Wallet(new Mnemonic(WordList.English, WordCount.Twelve));
             SessionSigner = new Wallet.Wallet(new Mnemonic(WordList.English, WordCount.Twelve));
             SessionSigner = new Wallet.Wallet(new Mnemonic(WordList.English, WordCount.Twelve));
             Client = ClientFactory.GetClient("http://localhost:8899");
             Client = ClientFactory.GetClient("http://localhost:8899");
-
+            AcceleratorClient = ClientFactory.GetClient("http://localhost:7799");
             ExampleComponentPosition = new PublicKey(Position.Program.PositionProgram.ID);
             ExampleComponentPosition = new PublicKey(Position.Program.PositionProgram.ID);
             ExampleComponentVelocity = new PublicKey(Velocity.Program.VelocityProgram.ID);
             ExampleComponentVelocity = new PublicKey(Velocity.Program.VelocityProgram.ID);
             SystemSimpleMovement = new PublicKey("FSa6qoJXFBR3a7ThQkTAMrC15p6NkchPEjBdd4n6dXxA");
             SystemSimpleMovement = new PublicKey("FSa6qoJXFBR3a7ThQkTAMrC15p6NkchPEjBdd4n6dXxA");
@@ -78,12 +81,12 @@ namespace Solana.Unity.Bolt.Test
             });
             });
         }
         }
 
 
-        public async Task<string> SendAndConfirmInstruction(TransactionInstruction instruction, List<Account>? signers = null, PublicKey? payer = null)
+        public async Task<string> SendAndConfirmInstruction(IRpcClient client, TransactionInstruction instruction, List<Account>? signers = null, PublicKey? payer = null)
         {
         {
             if (signers == null) {
             if (signers == null) {
                 signers = new List<Account> { Wallet.Account };
                 signers = new List<Account> { Wallet.Account };
             }
             }
-            var blockHashResponse = await Client.GetLatestBlockHashAsync(Commitment.Processed);
+            var blockHashResponse = await client.GetLatestBlockHashAsync(Commitment.Processed);
             if (!blockHashResponse.WasSuccessful || blockHashResponse.Result?.Value?.Blockhash == null)
             if (!blockHashResponse.WasSuccessful || blockHashResponse.Result?.Value?.Blockhash == null)
                 throw new Exception("Failed to get latest blockhash");
                 throw new Exception("Failed to get latest blockhash");
             var blockhash = blockHashResponse.Result.Value.Blockhash;
             var blockhash = blockHashResponse.Result.Value.Blockhash;
@@ -93,8 +96,8 @@ namespace Solana.Unity.Bolt.Test
                 .AddInstruction(instruction)
                 .AddInstruction(instruction)
                 .Build(signers);
                 .Build(signers);
 
 
-            var signature = await Client.SendTransactionAsync(transaction, true, Commitment.Processed);
-            var confirmed = await Client.ConfirmTransaction(signature.Result, Commitment.Processed);
+            var signature = await client.SendTransactionAsync(transaction, true, Commitment.Processed);
+            var confirmed = await client.ConfirmTransaction(signature.Result, Commitment.Processed);
             if (signature.WasSuccessful && confirmed)
             if (signature.WasSuccessful && confirmed)
             {
             {
                 return signature.Result;
                 return signature.Result;
@@ -107,14 +110,24 @@ namespace Solana.Unity.Bolt.Test
             throw new Exception(errorMessage);
             throw new Exception(errorMessage);
         }
         }
 
 
-        public async Task<AccountInfo> GetAccountInfo(PublicKey publicKey)
+        public async Task<string> SendAndConfirmInstruction(TransactionInstruction instruction, List<Account>? signers = null, PublicKey? payer = null)
         {
         {
-            var accountInfo = await Client.GetAccountInfoAsync(publicKey, Commitment.Processed);
+            return await SendAndConfirmInstruction(Client, instruction, signers, payer);
+        }
+
+        public async Task<AccountInfo> GetAccountInfo(IRpcClient client, PublicKey publicKey)
+        {
+            var accountInfo = await client.GetAccountInfoAsync(publicKey, Commitment.Processed);
             if (accountInfo.WasSuccessful)
             if (accountInfo.WasSuccessful)
             {
             {
                 return accountInfo.Result.Value;
                 return accountInfo.Result.Value;
             }
             }
             throw new Exception(string.Join("\n", accountInfo.ErrorData.Logs));
             throw new Exception(string.Join("\n", accountInfo.ErrorData.Logs));
         }
         }
+
+        public async Task<AccountInfo> GetAccountInfo(PublicKey publicKey)
+        {
+            return await GetAccountInfo(Client, publicKey);
+        }
     }
     }
 }
 }

+ 1 - 1
clients/csharp/Solana.Unity.Bolt.Test/Program.cs

@@ -8,12 +8,12 @@ namespace Solana.Unity.Bolt.Test
     {
     {
         static async Task Main(string[] args)
         static async Task Main(string[] args)
         {
         {
-            Console.WriteLine("Running C# tests...");
             var framework = new Framework();
             var framework = new Framework();
             await framework.Initialize();
             await framework.Initialize();
             await WorldTest.Test.Run(framework);
             await WorldTest.Test.Run(framework);
             await ECSTest.Test.Run(framework);
             await ECSTest.Test.Run(framework);
             await SessionTest.Test.Run(framework);
             await SessionTest.Test.Run(framework);
+            await AccelerationTest.Test.Run(framework);
         }
         }
     }
     }
 }
 }

+ 1 - 0
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/AddEntity.cs

@@ -1,4 +1,5 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
+#pragma warning disable CS1998
 
 
 using Solana.Unity.Rpc;
 using Solana.Unity.Rpc;
 using Solana.Unity.Rpc.Models;
 using Solana.Unity.Rpc.Models;

+ 1 - 0
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs

@@ -1,4 +1,5 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
+#pragma warning disable CS0618
 
 
 using Solana.Unity.Wallet;
 using Solana.Unity.Wallet;
 using System;
 using System;

+ 61 - 0
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DelegateComponent.cs

@@ -0,0 +1,61 @@
+#pragma warning disable CS1591
+#pragma warning disable CS1998
+
+using Solana.Unity.Programs;
+using Solana.Unity.Rpc;
+using Solana.Unity.Rpc.Models;
+using Solana.Unity.Rpc.Types;
+using Solana.Unity.Wallet;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using World.Program;
+
+namespace Bolt {
+    public partial class World {
+        public class DelegateComponentInstruction {
+            public PublicKey Pda { get; set; }
+            public TransactionInstruction Instruction { get; set; }
+        }
+
+        public static async Task<DelegateComponentInstruction> DelegateComponent(PublicKey payer, PublicKey entity, PublicKey componentId, string seed = "") {
+            var account = WorldProgram.FindComponentPda(componentId, entity, seed);
+            var bufferPda = WorldProgram.FindBufferPda(account, componentId);
+            var delegationRecord = WorldProgram.FindDelegationProgramPda("delegation", account);
+            var delegationMetadata = WorldProgram.FindDelegationProgramPda("delegation-metadata", account);
+
+            byte[] discriminator = new byte[] { 90, 147, 75, 178, 85, 88, 4, 137 };
+            uint commitFrequencyMs = 0;
+            byte[] commitFrequencyBytes = BitConverter.GetBytes(commitFrequencyMs);
+            if (!BitConverter.IsLittleEndian) Array.Reverse(commitFrequencyBytes);
+            var validator = new byte[1];
+            validator[0] = 0;
+
+            var data = new byte[discriminator.Length + commitFrequencyBytes.Length + validator.Length];
+            Array.Copy(discriminator, data, discriminator.Length);
+            Array.Copy(commitFrequencyBytes, 0, data, discriminator.Length, commitFrequencyBytes.Length);
+            Array.Copy(validator, 0, data, discriminator.Length + commitFrequencyBytes.Length, validator.Length);
+
+            TransactionInstruction instruction = new TransactionInstruction() {
+                ProgramId = componentId,
+                Keys = new List<AccountMeta>() {
+                    AccountMeta.ReadOnly(payer, true),
+                    AccountMeta.ReadOnly(entity, false),
+                    AccountMeta.Writable(account, false),
+                    AccountMeta.ReadOnly(componentId, false),
+                    AccountMeta.Writable(bufferPda, false),
+                    AccountMeta.Writable(delegationRecord, false),
+                    AccountMeta.Writable(delegationMetadata, false),
+                    AccountMeta.ReadOnly(WorldProgram.DelegationProgram, false),
+                    AccountMeta.ReadOnly(SystemProgram.ProgramIdKey, false),
+                },
+                Data = data,
+            };
+            return new DelegateComponentInstruction() {
+                Pda = WorldProgram.FindDelegationProgramPda(seed, entity),
+                Instruction = instruction,
+            };
+        }
+    }
+}

+ 1 - 0
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DestroyComponent.cs

@@ -1,4 +1,5 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
+#pragma warning disable CS1998
 
 
 using Solana.Unity.Rpc.Models;
 using Solana.Unity.Rpc.Models;
 using Solana.Unity.Wallet;
 using Solana.Unity.Wallet;

+ 1 - 0
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs

@@ -1,4 +1,5 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
+#pragma warning disable CS1998
 
 
 using Solana.Unity.Rpc.Models;
 using Solana.Unity.Rpc.Models;
 using Solana.Unity.Wallet;
 using Solana.Unity.Wallet;

+ 21 - 0
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs

@@ -125,6 +125,27 @@ namespace World
                 return pda;
                 return pda;
             }
             }
 
 
+            public static readonly PublicKey DelegationProgram = new("DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh");
+
+            public static PublicKey FindDelegationProgramPda(string seed, PublicKey account)
+            {
+                PublicKey.TryFindProgramAddress(new[]
+                {
+                    Encoding.UTF8.GetBytes(seed), account.KeyBytes
+                }, DelegationProgram, out var pda, out _);
+                return pda;
+            }
+
+            public static PublicKey FindBufferPda(PublicKey account, PublicKey owner)
+            {
+                PublicKey.TryFindProgramAddress(new[]
+                {
+                    Encoding.UTF8.GetBytes("buffer"), account.KeyBytes
+                }, owner, out var pda, out _);
+                return pda;
+            }
+
+
             /// <summary>
             /// <summary>
             /// Convenience bundle for defining an entity and the associated components.
             /// Convenience bundle for defining an entity and the associated components.
             /// </summary>
             /// </summary>

+ 16 - 8
clients/typescript/test/framework.ts

@@ -6,16 +6,17 @@ export enum Direction {
 }
 }
 
 
 import { anchor, BN } from "../lib";
 import { anchor, BN } from "../lib";
-import { type World } from "../../../../target/types/world";
-import { type Position } from "../../../../target/types/position";
-import { type Velocity } from "../../../../target/types/velocity";
-import { type SystemSimpleMovement } from "../../../../target/types/system_simple_movement";
-import { type SystemFly } from "../../../../target/types/system_fly";
-import { type SystemApplyVelocity } from "../../../../target/types/system_apply_velocity";
-import { Keypair, PublicKey } from "@solana/web3.js";
+import { type World } from "../../../target/types/world";
+import { type Position } from "../../../target/types/position";
+import { type Velocity } from "../../../target/types/velocity";
+import { type SystemSimpleMovement } from "../../../target/types/system_simple_movement";
+import { type SystemFly } from "../../../target/types/system_fly";
+import { type SystemApplyVelocity } from "../../../target/types/system_apply_velocity";
+import { Connection, Keypair, PublicKey } from "@solana/web3.js";
 
 
 export class Framework {
 export class Framework {
   provider: anchor.AnchorProvider;
   provider: anchor.AnchorProvider;
+  acceleratorProvider: anchor.AnchorProvider;
   worldProgram: anchor.Program<World>;
   worldProgram: anchor.Program<World>;
   exampleComponentPosition: anchor.Program<Position>;
   exampleComponentPosition: anchor.Program<Position>;
   exampleComponentVelocity: anchor.Program<Velocity>;
   exampleComponentVelocity: anchor.Program<Velocity>;
@@ -31,7 +32,9 @@ export class Framework {
   entity1Pda: PublicKey;
   entity1Pda: PublicKey;
   entity2Pda: PublicKey;
   entity2Pda: PublicKey;
   entity4Pda: PublicKey;
   entity4Pda: PublicKey;
+  acceleratedEntityPda: PublicKey;
 
 
+  acceleratedComponentPositionPda: PublicKey;
   componentPositionEntity1Pda: PublicKey;
   componentPositionEntity1Pda: PublicKey;
   componentVelocityEntity1Pda: PublicKey;
   componentVelocityEntity1Pda: PublicKey;
 
 
@@ -46,7 +49,12 @@ export class Framework {
     this.systemFly = anchor.workspace.SystemFly;
     this.systemFly = anchor.workspace.SystemFly;
     this.systemApplyVelocity = anchor.workspace.SystemApplyVelocity;
     this.systemApplyVelocity = anchor.workspace.SystemApplyVelocity;
 
 
-    this.provider = anchor.AnchorProvider.env();
+    this.provider = anchor.AnchorProvider.local();
     anchor.setProvider(this.provider);
     anchor.setProvider(this.provider);
+
+    this.acceleratorProvider = new anchor.AnchorProvider(
+      new Connection("http://localhost:7799", "processed"),
+      anchor.Wallet.local(),
+    );
   }
   }
 }
 }

+ 75 - 3
clients/typescript/test/intermediate-level/acceleration.ts

@@ -1,12 +1,52 @@
-import { DelegateComponent, DELEGATION_PROGRAM_ID } from "../../lib";
+import {
+  AddEntity,
+  ApplySystem,
+  DelegateComponent,
+  DELEGATION_PROGRAM_ID,
+  InitializeComponent,
+} from "../../lib";
 import { expect } from "chai";
 import { expect } from "chai";
+import { Direction } from "../framework";
+import { convertIdlToCamelCase } from "@coral-xyz/anchor/dist/cjs/idl";
+import { sendAndConfirmTransaction, Keypair } from "@solana/web3.js";
+import fs from "fs";
+import { Framework } from "../framework";
 
 
-export function acceleration(framework) {
+export function acceleration(framework: Framework) {
   describe("Acceleration", () => {
   describe("Acceleration", () => {
+    it("Create accelerated entity", async () => {
+      const createAcceleratedEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+
+      framework.acceleratedEntityPda = createAcceleratedEntity.entityPda;
+
+      await framework.provider.sendAndConfirm(
+        createAcceleratedEntity.transaction,
+      );
+    });
+
+    it("Create accelerated component position", async () => {
+      const createAcceleratedComponentPosition = await InitializeComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: framework.acceleratedEntityPda,
+        componentId: framework.exampleComponentPosition.programId,
+      });
+
+      framework.acceleratedComponentPositionPda =
+        createAcceleratedComponentPosition.componentPda;
+
+      await framework.provider.sendAndConfirm(
+        createAcceleratedComponentPosition.transaction,
+      );
+    });
+
     it("Check component delegation to accelerator", async () => {
     it("Check component delegation to accelerator", async () => {
       const delegateComponent = await DelegateComponent({
       const delegateComponent = await DelegateComponent({
         payer: framework.provider.wallet.publicKey,
         payer: framework.provider.wallet.publicKey,
-        entity: framework.entity1Pda,
+        entity: framework.acceleratedEntityPda,
         componentId: framework.exampleComponentPosition.programId,
         componentId: framework.exampleComponentPosition.programId,
       });
       });
 
 
@@ -23,5 +63,37 @@ export function acceleration(framework) {
       );
       );
       expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
       expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
     });
     });
+
+    it("Apply Simple Movement System (Up) on Entity 1 on Accelerator 10 times", async () => {
+      for (let i = 0; i < 10; i++) {
+        let applySystem = await ApplySystem({
+          authority: framework.provider.wallet.publicKey,
+          systemId: framework.systemSimpleMovement.programId,
+          world: framework.worldPda,
+          entities: [
+            {
+              entity: framework.acceleratedEntityPda,
+              components: [
+                { componentId: framework.exampleComponentPosition.programId },
+              ],
+            },
+          ],
+          args: {
+            direction: Direction.Up,
+          },
+        });
+
+        await framework.acceleratorProvider.sendAndConfirm(
+          applySystem.transaction,
+          [],
+          {
+            skipPreflight: true,
+            commitment: "processed",
+          },
+        );
+        // Wait for 50ms
+        await new Promise((resolve) => setTimeout(resolve, 50));
+      }
+    });
   });
   });
 }
 }

+ 1 - 1
clients/typescript/test/intermediate-level/index.ts

@@ -10,6 +10,6 @@ describe("Intermediate level API", () => {
   world(framework);
   world(framework);
   ecs(framework);
   ecs(framework);
   session(framework);
   session(framework);
-  permissioning(framework);
   acceleration(framework);
   acceleration(framework);
+  permissioning(framework);
 });
 });

+ 0 - 24
clients/typescript/test/low-level/acceleration.ts

@@ -1,24 +0,0 @@
-import { anchor, DelegateComponent, DELEGATION_PROGRAM_ID } from "../../lib";
-import { expect } from "chai";
-
-export function acceleration(framework) {
-  describe("Acceleration", () => {
-    it("Check component delegation to accelerator", async () => {
-      const delegateComponent = await DelegateComponent({
-        payer: framework.provider.wallet.publicKey,
-        entity: framework.entity1Pda,
-        componentId: framework.exampleComponentPosition.programId,
-      });
-      const instruction = delegateComponent.transaction;
-      const transaction = new anchor.web3.Transaction().add(instruction);
-      await framework.provider.sendAndConfirm(transaction, [], {
-        skipPreflight: true,
-        commitment: "confirmed",
-      });
-      const acc = await framework.provider.connection.getAccountInfo(
-        delegateComponent.componentPda,
-      );
-      expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
-    });
-  });
-}

+ 0 - 2
clients/typescript/test/low-level/index.ts

@@ -3,7 +3,6 @@ import { world } from "./world";
 import { ecs } from "./ecs";
 import { ecs } from "./ecs";
 import { session } from "./session";
 import { session } from "./session";
 import { permissioning } from "./permissioning";
 import { permissioning } from "./permissioning";
-import { acceleration } from "./acceleration";
 
 
 describe("Low level API", () => {
 describe("Low level API", () => {
   const framework: Framework = new Framework();
   const framework: Framework = new Framework();
@@ -11,5 +10,4 @@ describe("Low level API", () => {
   ecs(framework);
   ecs(framework);
   session(framework);
   session(framework);
   permissioning(framework);
   permissioning(framework);
-  acceleration(framework);
 });
 });

+ 5 - 1
crates/bolt-cli/Cargo.toml

@@ -26,4 +26,8 @@ serde_json = { workspace = true }
 heck = { workspace = true }
 heck = { workspace = true }
 clap = { workspace = true }
 clap = { workspace = true }
 syn = { workspace = true, features = ["full", "extra-traits"] }
 syn = { workspace = true, features = ["full", "extra-traits"] }
-world = { workspace = true }
+world = { workspace = true }
+which = { workspace = true }
+tokio = { workspace = true }
+sysinfo = { workspace = true }
+bytemuck_derive = { workspace = true }

+ 3 - 2
crates/bolt-cli/src/bin/main.rs

@@ -1,6 +1,7 @@
 use anyhow::Result;
 use anyhow::Result;
 use clap::Parser;
 use clap::Parser;
 
 
-fn main() -> Result<()> {
-    bolt_cli::entry(bolt_cli::Opts::parse())
+#[tokio::main]
+async fn main() -> Result<()> {
+    bolt_cli::entry(bolt_cli::Opts::parse()).await
 }
 }

+ 3 - 0
crates/bolt-cli/src/commands/mod.rs

@@ -0,0 +1,3 @@
+mod test;
+
+pub use test::*;

+ 27 - 0
crates/bolt-cli/src/commands/test.rs

@@ -0,0 +1,27 @@
+use anchor_cli::config::ConfigOverride;
+use anyhow::Result;
+
+use crate::EphemeralValidator;
+
+#[allow(clippy::too_many_arguments)]
+pub async fn test(
+    cfg_override: ConfigOverride,
+    command: anchor_cli::Command,
+    skip_local_validator: bool,
+) -> Result<()> {
+    let anchor = tokio::spawn(async move {
+        let opts = anchor_cli::Opts {
+            cfg_override,
+            command,
+        };
+        anchor_cli::entry(opts).ok();
+    });
+    if !skip_local_validator {
+        if let Ok(_ephemeral_validator) = EphemeralValidator::start().await {
+            anchor.await.ok();
+            return Ok(());
+        }
+    }
+    anchor.await.expect("Failed to run anchor");
+    Ok(())
+}

+ 78 - 0
crates/bolt-cli/src/ephemeral_validator.rs

@@ -0,0 +1,78 @@
+use anyhow::Result;
+use std::process::Stdio;
+
+pub struct EphemeralValidator;
+
+impl EphemeralValidator {
+    pub fn is_available() -> bool {
+        which::which("ephemeral-validator").is_ok()
+    }
+
+    async fn wait_for_basenet() -> Result<()> {
+        let balance = tokio::spawn(async move {
+            loop {
+                let status = std::process::Command::new("solana")
+                    .arg("balance")
+                    .stdout(Stdio::null())
+                    .stderr(Stdio::null())
+                    .status()
+                    .expect("Failed to check solana balance");
+                if status.success() {
+                    break;
+                }
+                std::thread::sleep(std::time::Duration::from_secs(1));
+            }
+        });
+        balance.await.expect("Failed to check solana balance");
+        Ok(())
+    }
+
+    pub async fn start() -> Result<Self> {
+        if !Self::is_available() {
+            return Err(anyhow::anyhow!("ephemeral-validator not available"));
+        }
+        Self::wait_for_basenet().await?;
+        Self::cleanup()?;
+        let temp_file = std::env::temp_dir().join("ephemeral-validator.toml");
+        std::fs::write(
+            &temp_file,
+            include_str!("templates/ephemeral-validator.toml"),
+        )
+        .expect("Failed to write ephemeral validator config");
+        tokio::process::Command::new("ephemeral-validator")
+            .arg(temp_file)
+            .spawn()
+            .expect("Failed to start ephemeral validator");
+        println!("Ephemeral validator started");
+
+        Ok(Self)
+    }
+
+    pub fn cleanup() -> Result<()> {
+        let mut system = sysinfo::System::new_all();
+        system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
+        let processes = system.processes();
+        for process in processes.values() {
+            if let Some(name) = process
+                .exe()
+                .and_then(|path| path.file_name())
+                .and_then(|name| name.to_str())
+            {
+                if name == "ephemeral-validator" {
+                    process
+                        .kill_with(sysinfo::Signal::Term)
+                        .expect("Failed to kill ephemeral validator");
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+impl Drop for EphemeralValidator {
+    fn drop(&mut self) {
+        if EphemeralValidator::is_available() {
+            EphemeralValidator::cleanup().expect("Failed to cleanup ephemeral validator");
+        }
+    }
+}

+ 10 - 1
crates/bolt-cli/src/lib.rs

@@ -1,3 +1,6 @@
+mod commands;
+mod ephemeral_validator;
+
 mod component;
 mod component;
 mod instructions;
 mod instructions;
 mod rust_template;
 mod rust_template;
@@ -5,6 +8,8 @@ mod system;
 mod templates;
 mod templates;
 mod workspace;
 mod workspace;
 
 
+pub use ephemeral_validator::EphemeralValidator;
+
 use crate::component::new_component;
 use crate::component::new_component;
 use crate::instructions::{
 use crate::instructions::{
     approve_system, authorize, create_registry, create_world, deauthorize, remove_system,
     approve_system, authorize, create_registry, create_world, deauthorize, remove_system,
@@ -111,7 +116,7 @@ pub struct Opts {
     pub command: BoltCommand,
     pub command: BoltCommand,
 }
 }
 
 
-pub fn entry(opts: Opts) -> Result<()> {
+pub async fn entry(opts: Opts) -> Result<()> {
     match opts.command {
     match opts.command {
         BoltCommand::Anchor(command) => match command {
         BoltCommand::Anchor(command) => match command {
             anchor_cli::Command::Init {
             anchor_cli::Command::Init {
@@ -134,6 +139,10 @@ pub fn entry(opts: Opts) -> Result<()> {
                 test_template,
                 test_template,
                 force,
                 force,
             ),
             ),
+            anchor_cli::Command::Test {
+                skip_local_validator,
+                ..
+            } => commands::test(opts.cfg_override, command, skip_local_validator).await,
             anchor_cli::Command::Build {
             anchor_cli::Command::Build {
                 idl,
                 idl,
                 no_idl,
                 no_idl,

+ 12 - 0
crates/bolt-cli/src/templates/ephemeral-validator.toml

@@ -0,0 +1,12 @@
+[accounts]
+remote = "http://localhost:8899"
+lifecycle = "ephemeral"
+commit = { frequency_millis = 50_000 }
+payer = { init_sol = 1_000 }
+
+[rpc]
+addr = "0.0.0.0"
+port = 7799
+
+[validator]
+millis_per_slot = 50

+ 1 - 0
package.json

@@ -4,6 +4,7 @@
         "lint": "node_modules/.bin/prettier */*.js \"*/**/*{.js,.ts}\" --check"
         "lint": "node_modules/.bin/prettier */*.js \"*/**/*{.js,.ts}\" --check"
     },
     },
     "devDependencies": {
     "devDependencies": {
+        "@magicblock-labs/ephemeral-validator": "^0.1.0",
         "@metaplex-foundation/beet": "^0.7.1",
         "@metaplex-foundation/beet": "^0.7.1",
         "@metaplex-foundation/beet-solana": "^0.4.0",
         "@metaplex-foundation/beet-solana": "^0.4.0",
         "@types/bn.js": "^5.1.0",
         "@types/bn.js": "^5.1.0",

+ 15 - 0
tests/script.sh

@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -euo pipefail
+
+echo "Waiting for 5 seconds..."
+sleep 5
+
+echo "Running TypeScript tests..."
+yarn run ts-mocha -p ./tsconfig.json -t 1000000 clients/typescript/test/main.ts
+
+echo "Running C# tests..."
+cd clients/csharp/Solana.Unity.Bolt.Test
+dotnet run --configuration Release
+
+echo "Tests completed."

+ 89 - 53
yarn.lock

@@ -9,6 +9,42 @@
   dependencies:
   dependencies:
     regenerator-runtime "^0.14.0"
     regenerator-runtime "^0.14.0"
 
 
+"@magicblock-labs/ephemeral-validator-darwin-arm64@^0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-validator-darwin-arm64/-/ephemeral-validator-darwin-arm64-0.1.0.tgz#1ef3bf1388d34cdd184ed05a9d059a7959de7e4b"
+  integrity sha512-LFezO9sWfVHWhJ5FggAw1UXoPo9wReDxIsXfs6H0lioM+dsjhib6XZMBQJ/BIAnjuImQ1ZKlAJcqt5uJjCGPDw==
+
+"@magicblock-labs/ephemeral-validator-darwin-x64@0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-validator-darwin-x64/-/ephemeral-validator-darwin-x64-0.1.0.tgz#be97cef596cc38dac2344811e8ee28ac75a49417"
+  integrity sha512-glyVSgZu5YW7X1QxSayTTy1wKO5mc2SgAG5tTsfuCVfKJ77UVNovCb/I1PH8Q6dGXLYJ2YE6Dn2vhpBqaW85aw==
+
+"@magicblock-labs/ephemeral-validator-linux-arm64@0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-validator-linux-arm64/-/ephemeral-validator-linux-arm64-0.1.0.tgz#c8dd28623384b3644f28003bf2ed0a8401fc020e"
+  integrity sha512-BHk1FbvMtJQLK45d9jVIhdfc1Ho+9CB15IETRZskINnE+dtsd22yWRBYGopXnDRTxhrN62k5Qr9JmUqw/D0SGQ==
+
+"@magicblock-labs/ephemeral-validator-linux-x64@0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-validator-linux-x64/-/ephemeral-validator-linux-x64-0.1.0.tgz#35a543743d9c08c280a9d89fe1d11392feaff066"
+  integrity sha512-sF2iKAySeCUGtvwmnuGabK9K3EeNctFitJjSMUWwgQRogfd1RoEHQLXy+pJX95Z90ShYNnOsoU9x8FrElAWHPQ==
+
+"@magicblock-labs/ephemeral-validator-windows-x64@0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-validator-windows-x64/-/ephemeral-validator-windows-x64-0.1.0.tgz#71266dc5c1d08787597ecb1f5e213ffb8e8c809f"
+  integrity sha512-8P/4lhVLKYL4yuz1sROan2rlQIiux+4jcw4d+++CYwwyUhHrPdNUdPQXwSo4/Xcf4+D+FUSGVyb4aZbGb0dlPQ==
+
+"@magicblock-labs/ephemeral-validator@^0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-validator/-/ephemeral-validator-0.1.0.tgz#69d5561eaedcd38c44bbc32631c790b1e5a6d9f8"
+  integrity sha512-J9/hIGs/K8kCVSTJCApTJC/z+L1pTLA1hXpXqY+XXf2dfHzoUJg4j2XyyAv68dxQSFP1u++CrLNX+cdVJo1OIg==
+  optionalDependencies:
+    "@magicblock-labs/ephemeral-validator-darwin-arm64" "^0.1.0"
+    "@magicblock-labs/ephemeral-validator-darwin-x64" "0.1.0"
+    "@magicblock-labs/ephemeral-validator-linux-arm64" "0.1.0"
+    "@magicblock-labs/ephemeral-validator-linux-x64" "0.1.0"
+    "@magicblock-labs/ephemeral-validator-windows-x64" "0.1.0"
+
 "@metaplex-foundation/beet-solana@^0.4.0":
 "@metaplex-foundation/beet-solana@^0.4.0":
   version "0.4.1"
   version "0.4.1"
   resolved "https://registry.npmjs.org/@metaplex-foundation/beet-solana/-/beet-solana-0.4.1.tgz"
   resolved "https://registry.npmjs.org/@metaplex-foundation/beet-solana/-/beet-solana-0.4.1.tgz"
@@ -19,7 +55,7 @@
     bs58 "^5.0.0"
     bs58 "^5.0.0"
     debug "^4.3.4"
     debug "^4.3.4"
 
 
-"@metaplex-foundation/beet@^0.7.1", "@metaplex-foundation/beet@>=0.1.0":
+"@metaplex-foundation/beet@>=0.1.0", "@metaplex-foundation/beet@^0.7.1":
   version "0.7.2"
   version "0.7.2"
   resolved "https://registry.npmjs.org/@metaplex-foundation/beet/-/beet-0.7.2.tgz"
   resolved "https://registry.npmjs.org/@metaplex-foundation/beet/-/beet-0.7.2.tgz"
   integrity sha512-K+g3WhyFxKPc0xIvcIjNyV1eaTVJTiuaHZpig7Xx0MuYRMoJLLvhLTnUXhFdR5Tu2l2QSyKwfyXDgZlzhULqFg==
   integrity sha512-K+g3WhyFxKPc0xIvcIjNyV1eaTVJTiuaHZpig7Xx0MuYRMoJLLvhLTnUXhFdR5Tu2l2QSyKwfyXDgZlzhULqFg==
@@ -36,7 +72,7 @@
   dependencies:
   dependencies:
     "@noble/hashes" "1.5.0"
     "@noble/hashes" "1.5.0"
 
 
-"@noble/hashes@^1.4.0", "@noble/hashes@1.5.0":
+"@noble/hashes@1.5.0", "@noble/hashes@^1.4.0":
   version "1.5.0"
   version "1.5.0"
   resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz"
   resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz"
   integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==
   integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==
@@ -141,6 +177,14 @@
   resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz"
   resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz"
   integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
   integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
 
 
+JSONStream@^1.3.5:
+  version "1.3.5"
+  resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz"
+  integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
+  dependencies:
+    jsonparse "^1.2.0"
+    through ">=2.2.7 <3"
+
 agentkeepalive@^4.5.0:
 agentkeepalive@^4.5.0:
   version "4.5.0"
   version "4.5.0"
   resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz"
   resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz"
@@ -303,7 +347,7 @@ buffer-from@^1.0.0, buffer-from@^1.1.0:
   resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
   resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
 
 
-buffer@^6.0.3, buffer@~6.0.3, buffer@6.0.3:
+buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3:
   version "6.0.3"
   version "6.0.3"
   resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
   resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
   integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
   integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
@@ -406,13 +450,6 @@ concat-map@0.0.1:
   resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
   resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
   integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
   integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
 
 
-debug@^4.3.3, debug@^4.3.4:
-  version "4.3.4"
-  resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
-  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
-  dependencies:
-    ms "2.1.2"
-
 debug@4.3.3:
 debug@4.3.3:
   version "4.3.3"
   version "4.3.3"
   resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz"
   resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz"
@@ -420,6 +457,13 @@ debug@4.3.3:
   dependencies:
   dependencies:
     ms "2.1.2"
     ms "2.1.2"
 
 
+debug@^4.3.3, debug@^4.3.4:
+  version "4.3.4"
+  resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
+  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+  dependencies:
+    ms "2.1.2"
+
 decamelize@^4.0.0:
 decamelize@^4.0.0:
   version "4.0.0"
   version "4.0.0"
   resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz"
   resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz"
@@ -455,16 +499,16 @@ delay@^5.0.0:
   resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz"
   resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz"
   integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==
   integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==
 
 
-diff@^3.1.0:
-  version "3.5.0"
-  resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz"
-  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
-
 diff@5.0.0:
 diff@5.0.0:
   version "5.0.0"
   version "5.0.0"
   resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz"
   resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz"
   integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
   integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
 
 
+diff@^3.1.0:
+  version "3.5.0"
+  resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz"
+  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+
 emoji-regex@^8.0.0:
 emoji-regex@^8.0.0:
   version "8.0.0"
   version "8.0.0"
   resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
   resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
@@ -544,6 +588,11 @@ fs.realpath@^1.0.0:
   resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
   resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
   integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
   integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
 
 
+fsevents@~2.3.2:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+  integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
 function-bind@^1.1.2:
 function-bind@^1.1.2:
   version "1.1.2"
   version "1.1.2"
   resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
   resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
@@ -661,7 +710,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     once "^1.3.0"
     wrappy "1"
     wrappy "1"
 
 
-inherits@^2.0.3, inherits@2:
+inherits@2, inherits@^2.0.3:
   version "2.0.4"
   version "2.0.4"
   resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
   resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -758,13 +807,13 @@ jayson@^4.1.1:
     "@types/connect" "^3.4.33"
     "@types/connect" "^3.4.33"
     "@types/node" "^12.12.54"
     "@types/node" "^12.12.54"
     "@types/ws" "^7.4.4"
     "@types/ws" "^7.4.4"
+    JSONStream "^1.3.5"
     commander "^2.20.3"
     commander "^2.20.3"
     delay "^5.0.0"
     delay "^5.0.0"
     es6-promisify "^5.0.0"
     es6-promisify "^5.0.0"
     eyes "^0.1.8"
     eyes "^0.1.8"
     isomorphic-ws "^4.0.1"
     isomorphic-ws "^4.0.1"
     json-stringify-safe "^5.0.1"
     json-stringify-safe "^5.0.1"
-    JSONStream "^1.3.5"
     uuid "^8.3.2"
     uuid "^8.3.2"
     ws "^7.5.10"
     ws "^7.5.10"
 
 
@@ -792,14 +841,6 @@ jsonparse@^1.2.0:
   resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz"
   resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz"
   integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
   integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
 
 
-JSONStream@^1.3.5:
-  version "1.3.5"
-  resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz"
-  integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
-  dependencies:
-    jsonparse "^1.2.0"
-    through ">=2.2.7 <3"
-
 locate-path@^6.0.0:
 locate-path@^6.0.0:
   version "6.0.0"
   version "6.0.0"
   resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
   resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
@@ -827,13 +868,6 @@ make-error@^1.1.1:
   resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
   resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
   integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
   integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
 
 
-minimatch@^3.0.4:
-  version "3.1.2"
-  resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
-  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
-  dependencies:
-    brace-expansion "^1.1.7"
-
 minimatch@4.2.1:
 minimatch@4.2.1:
   version "4.2.1"
   version "4.2.1"
   resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz"
   resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz"
@@ -841,6 +875,13 @@ minimatch@4.2.1:
   dependencies:
   dependencies:
     brace-expansion "^1.1.7"
     brace-expansion "^1.1.7"
 
 
+minimatch@^3.0.4:
+  version "3.1.2"
+  resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+  dependencies:
+    brace-expansion "^1.1.7"
+
 minimist@^1.2.0, minimist@^1.2.6:
 minimist@^1.2.0, minimist@^1.2.6:
   version "1.2.8"
   version "1.2.8"
   resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
   resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
@@ -853,7 +894,7 @@ mkdirp@^0.5.1:
   dependencies:
   dependencies:
     minimist "^1.2.6"
     minimist "^1.2.6"
 
 
-"mocha@^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", mocha@^9.0.3:
+mocha@^9.0.3:
   version "9.2.2"
   version "9.2.2"
   resolved "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz"
   resolved "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz"
   integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==
   integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==
@@ -883,17 +924,12 @@ mkdirp@^0.5.1:
     yargs-parser "20.2.4"
     yargs-parser "20.2.4"
     yargs-unparser "2.0.0"
     yargs-unparser "2.0.0"
 
 
-ms@^2.0.0:
-  version "2.1.3"
-  resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
-  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
 ms@2.1.2:
 ms@2.1.2:
   version "2.1.2"
   version "2.1.2"
   resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
   resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
 
-ms@2.1.3:
+ms@2.1.3, ms@^2.0.0:
   version "2.1.3"
   version "2.1.3"
   resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
   resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
   integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
   integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -1095,13 +1131,6 @@ superstruct@^2.0.2:
   resolved "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz"
   resolved "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz"
   integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==
   integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==
 
 
-supports-color@^7.1.0:
-  version "7.2.0"
-  resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
-  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
-  dependencies:
-    has-flag "^4.0.0"
-
 supports-color@8.1.1:
 supports-color@8.1.1:
   version "8.1.1"
   version "8.1.1"
   resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
   resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
@@ -1109,6 +1138,13 @@ supports-color@8.1.1:
   dependencies:
   dependencies:
     has-flag "^4.0.0"
     has-flag "^4.0.0"
 
 
+supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+  dependencies:
+    has-flag "^4.0.0"
+
 text-encoding-utf-8@^1.0.2:
 text-encoding-utf-8@^1.0.2:
   version "1.0.2"
   version "1.0.2"
   resolved "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz"
   resolved "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz"
@@ -1184,7 +1220,7 @@ undici-types@~5.25.1:
   resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz"
   resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz"
   integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==
   integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==
 
 
-utf-8-validate@^5.0.2, utf-8-validate@>=5.0.2:
+utf-8-validate@^5.0.2:
   version "5.0.10"
   version "5.0.10"
   resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz"
   resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz"
   integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==
   integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==
@@ -1257,7 +1293,7 @@ wrappy@1:
   resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
   resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
   integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
   integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
 
 
-ws@*, ws@^7.5.10:
+ws@^7.5.10:
   version "7.5.10"
   version "7.5.10"
   resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz"
   resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz"
   integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
   integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
@@ -1272,16 +1308,16 @@ y18n@^5.0.5:
   resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
   resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
   integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
   integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
 
 
-yargs-parser@^20.2.2:
-  version "20.2.9"
-  resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz"
-  integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
-
 yargs-parser@20.2.4:
 yargs-parser@20.2.4:
   version "20.2.4"
   version "20.2.4"
   resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz"
   resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz"
   integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
   integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
 
 
+yargs-parser@^20.2.2:
+  version "20.2.9"
+  resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz"
+  integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
 yargs-unparser@2.0.0:
 yargs-unparser@2.0.0:
   version "2.0.0"
   version "2.0.0"
   resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz"
   resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz"