@tuwaio/pulsar-solana 0.4.0 → 0.5.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/README.md CHANGED
@@ -4,13 +4,13 @@
4
4
  [![License](https://img.shields.io/npm/l/@tuwaio/pulsar-solana.svg)](./LICENSE)
5
5
  [![Build Status](https://img.shields.io/github/actions/workflow/status/TuwaIO/pulsar-core/release.yml?branch=main)](https://github.com/TuwaIO/pulsar-core/actions)
6
6
 
7
- An advanced toolkit for the Pulsar Engine that adds comprehensive support for tracking transactions on the Solana blockchain. It is built to be **wallet-library agnostic**, integrating with any setup via a simple configuration object, and uses **`gill-sdk`** for modern blockchain interaction.
7
+ An advanced toolkit for the Pulsar Engine that adds comprehensive support for tracking transactions on the Solana blockchain. It is built to leverage **Wallet Standard**, integrating seamlessly with modern Solana wallet ecosystems, and uses **`gill`** for modern blockchain interaction.
8
8
 
9
9
  -----
10
10
 
11
11
  ## 🏛️ What is `@tuwaio/pulsar-solana`?
12
12
 
13
- This package is a powerful, official adapter for `@tuwaio/pulsar-core`. It's designed to be universally compatible with any wallet connection library. By providing a simple wallet state object, you can leverage Pulsar's powerful transaction tracking engine without being locked into a specific ecosystem like the Wallet Standard.
13
+ This package is a powerful, official adapter for `@tuwaio/pulsar-core`. It's designed to be compatible with wallets that follow the **Wallet Standard**. By leveraging standard wallet interfaces, you can utilize Pulsar's powerful transaction tracking engine across a wide range of Solana wallets.
14
14
 
15
15
  The architecture is designed for multi-chain robustness. You can provide RPC endpoints for different Solana clusters (e.g., Mainnet Beta, Devnet), and the adapter will automatically use the correct one based on the user's connected wallet state.
16
16
 
@@ -18,27 +18,19 @@ The architecture is designed for multi-chain robustness. You can provide RPC end
18
18
 
19
19
  ## ✨ Core Features
20
20
 
21
- - **🔌 Universal Integration:** A single `solanaAdapter` factory that works with **any wallet library**.
21
+ - **🔌 Wallet Standard Integration:** A single `pulsarSolanaAdapter` factory that works with any wallet supporting the **Wallet Standard**.
22
22
  - **🔗 Multi-Chain RPC:** Configure with a map of RPC URLs for different clusters; the adapter intelligently selects the correct one.
23
23
  - **🛰️ Robust Polling Tracker:** A durable transaction tracker that polls for signature statuses until finality.
24
- - **🌐 Network Verification:** Includes a utility (`checkSolanaChain`) to robustly verify that the connected wallet's cluster matches the one required by the transaction.
24
+ - **🌐 Network Verification:** Includes a utility (`checkSolanaChain`) to verify that the connected wallet's cluster matches the one required by the transaction.
25
25
  - **💡 Optional Wallet:** The adapter can be initialized without a wallet for read-only operations, such as displaying transaction history.
26
26
 
27
27
  -----
28
28
 
29
29
  ## 💾 Installation
30
30
 
31
- The package has minimal dependencies, requiring only `gill-sdk` for core functionality.
32
-
33
31
  ```bash
34
- # Using pnpm
35
- pnpm add @tuwaio/pulsar-solana @tuwaio/pulsar-core gill @tuwaio/orbit-core @tuwaio/orbit-solana zustand immer dayjs @wallet-standard/app @wallet-standard/ui-registry
36
-
37
- # Using npm
38
- npm install @tuwaio/pulsar-solana @tuwaio/pulsar-core gill @tuwaio/orbit-core @tuwaio/orbit-solana zustand immer dayjs @wallet-standard/app @wallet-standard/ui-registry
39
-
40
- # Using yarn
41
- yarn add @tuwaio/pulsar-solana @tuwaio/pulsar-core gill @tuwaio/orbit-core @tuwaio/orbit-solana zustand immer dayjs @wallet-standard/app @wallet-standard/ui-registry
32
+ # Using pnpm (recommended), but you can use npm, yarn or bun as well
33
+ pnpm add @tuwaio/pulsar-solana @tuwaio/pulsar-core gill @tuwaio/orbit-core @tuwaio/orbit-solana zustand immer dayjs @wallet-standard/app @wallet-standard/ui-registry @wallet-standard/ui-core
42
34
  ```
43
35
 
44
36
  -----
@@ -47,10 +39,10 @@ yarn add @tuwaio/pulsar-solana @tuwaio/pulsar-core gill @tuwaio/orbit-core @tuwa
47
39
 
48
40
  ### 1. Primary Usage: Integrating with `@tuwaio/nova-connect`
49
41
 
50
- The key to using Pulsar with Solana is to leverage the `solanaAdapter`, which seamlessly integrates with the `@tuwaio/nova-connect` state for example. This removes the need for manual wallet state management, as the adapter automatically reacts to changes in the active wallet, cluster, and connection status.
42
+ The key to using Pulsar with Solana is to leverage the `pulsarSolanaAdapter`, which seamlessly integrates with the `@tuwaio/nova-connect` state. This removes the need for manual wallet state management, as the adapter automatically reacts to changes in the active wallet, cluster, and connection status via **Wallet Standard** interfaces.
51
43
 
52
44
  **Example: Creating a Pulsar Store**
53
- Here's how to create and initialize the central Pulsar store using the `solanaAdapter`.
45
+ Here's how to create and initialize the central Pulsar store using the `pulsarSolanaAdapter`.
54
46
 
55
47
  ```typescript
56
48
  // src/hooks/pulsarStoreHook.ts
@@ -127,13 +119,13 @@ function MyTransactionButton() {
127
119
  const executeTxAction = usePulsarStore((state) => state.executeTxAction);
128
120
  const transactionsPool = usePulsarStore((state) => state.transactionsPool);
129
121
  const getLastTxKey = usePulsarStore((state) => state.getLastTxKey);
130
- const activeWallet = useSatelliteConnectStore((state) => state.activeWallet);
122
+ const activeConnection = useSatelliteConnectStore((state) => state.activeConnection);
131
123
 
132
- const activeWalletSolana = activeWallet as SolanaWallet;
124
+ const activeWalletSolana = activeConnection as SolanaWallet;
133
125
 
134
126
  const signer = useWalletAccountTransactionSendingSigner(
135
127
  activeWalletSolana.connectedAccount as UiWalletAccount,
136
- `${OrbitAdapter.SOLANA}:${activeWallet?.chainId ?? 'devnet'}`,
128
+ `${OrbitAdapter.SOLANA}:${activeConnection?.chainId ?? 'devnet'}`,
137
129
  );
138
130
 
139
131
  const handleClick = async () => {
@@ -143,14 +135,14 @@ function MyTransactionButton() {
143
135
  client: createSolanaClientWithCache({ rpcUrlOrMoniker: 'devnet' }),
144
136
  signer,
145
137
  }),
146
- onSuccessCallback: async () => {
138
+ onSuccess: async () => {
147
139
  console.log('action executed')
148
140
  },
149
141
  params: {
150
142
  type: 'example',
151
143
  adapter: OrbitAdapter.SOLANA,
152
144
  // The RPC URL must be provided for the tracker to work after a page reload
153
- rpcUrl: activeWallet?.rpcURL,
145
+ rpcUrl: activeConnection?.rpcURL,
154
146
  desiredChainID: 'devnet', // The cluster name for the pre-flight check
155
147
  title: 'Example',
156
148
  description: 'Example tx',
@@ -164,29 +156,6 @@ function MyTransactionButton() {
164
156
 
165
157
  -----
166
158
 
167
- ### 3. Using Standalone Utilities
168
-
169
- You can use the helper functions, such as `getSolanaExplorerLink` and `checkSolanaChain`, independently of the Pulsar store. These utilities are particularly useful for enhancing UI components and performing pre-transaction checks.
170
-
171
- **Example: Displaying a user's Solana explorer link**
172
-
173
- ```tsx
174
- // src/components/ExplorerLink.tsx
175
- import { getSolanaExplorerLink } from '@tuwaio/pulsar-solana';
176
-
177
- function ExplorerLink({ txSignature, txCluster }: { txSignature: string, txCluster: string }) {
178
- const explorerUrl = getSolanaExplorerLink(`/tx/${txSignature}`, txCluster);
179
-
180
- return (
181
- <a href={explorerUrl} target="_blank" rel="noopener noreferrer">
182
- View on Explorer
183
- </a>
184
- );
185
- }
186
- ```
187
-
188
- -----
189
-
190
159
  ## 🤝 Contributing & Support
191
160
 
192
161
  Contributions are welcome! Please read our main **[Contribution Guidelines](https://github.com/TuwaIO/workflows/blob/main/CONTRIBUTING.md)**.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var orbitCore=require('@tuwaio/orbit-core'),orbitSolana=require('@tuwaio/orbit-solana'),pulsarCore=require('@tuwaio/pulsar-core'),f=require('dayjs'),gill=require('gill');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var f__default=/*#__PURE__*/_interopDefault(f);var l=class extends Error{name="SolanaChainMismatchError";requiredChain;currentChain;constructor(a,r){let e=`Wrong chain. The transaction requires ${a}, but you are connected to ${r}.`;super(e),this.requiredChain=a,this.currentChain=r;}};async function F({tx:t,stopPolling:a,onSuccess:r,onFailure:e,onIntervalTick:n}){if(t.adapter!==orbitCore.OrbitAdapter.SOLANA)throw new Error('Tx adapter is not Solana. Please set the adapter to "solana" in the transaction object.');try{let o=orbitSolana.createSolanaRPC({rpcUrlOrMoniker:t.rpcUrl??orbitSolana.getCluster({cluster:t.chainId})}),s=(await o.getSignatureStatuses([t.txKey]).send())?.value?.[0];if(!s)return;let{fee:u,recentBlockhash:c,instructions:d}=t;if(!u||!c||!d){let A=await o.getTransaction(t.txKey,{encoding:"json",maxSupportedTransactionVersion:0}).send(),{meta:T,transaction:p}=A||{};if(!T||!p)return;u=Number(T.fee??0),c=p.message.recentBlockhash?.toString(),d=p.message.instructions;}let i={...s,slot:Number(s.slot),confirmations:Number(s.confirmations??0),fee:u,recentBlockhash:c,instructions:d};if(n?.(i),i.err){e(i),a({withoutRemoving:!0});return}if(i.confirmationStatus==="finalized"){r(i),a({withoutRemoving:!0});return}f__default.default().diff(f__default.default.unix(t.localTimestamp),"hour")>=1&&(e(i),a());}catch(o){console.error("Error in solanaFetcher:",o),e({err:o}),a();}}async function h({tx:t,onSuccess:a,onError:r,...e}){return pulsarCore.initializePollingTracker({tx:t,fetcher:F,removeTxFromPool:e.removeTxFromPool,pollingInterval:2500,maxRetries:10,onSuccess:n=>{e.updateTxParams(t.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,finishedTimestamp:f__default.default().unix(),fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash,confirmations:"MAX",slot:n.slot});let o=e.transactionsPool[t.txKey];a&&o&&a(o);},onIntervalTick:n=>{e.updateTxParams(t.txKey,{confirmations:n.confirmations??0,slot:n.slot,fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash});},onFailure:n=>{let o=n?.err?`Transaction failed: ${JSON.stringify(n.err)}`:"Transaction tracking timed out or the transaction was not found.";e.updateTxParams(t.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,errorMessage:o,finishedTimestamp:f__default.default().unix()});let m=e.transactionsPool[t.txKey];r&&m&&r(new Error(o),m);}})}async function S({tx:t,tracker:a,onSuccess:r,onError:e,...n}){a===pulsarCore.TransactionTracker.Solana?await h({tx:t,onSuccess:r,onError:e,...n}):(console.error(`Unknown tracker type for Solana adapter: ${a}`),n.updateTxParams(t.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,errorMessage:`Unsupported tracker type: "${a}"`}));}var k=(t,a)=>{if(a!==t)throw new l(t,a)};function pr(t){let{rpcUrls:a}=t;return {key:orbitCore.OrbitAdapter.SOLANA,getConnectorInfo:()=>{let r=orbitSolana.getConnectedSolanaConnector();return {walletAddress:orbitCore.lastConnectedConnectorHelpers.getLastConnectedConnector()?.address??r.accounts[0].address??"0x0",connectorType:orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.SOLANA,r.name)}},checkChainForTx:async r=>{if(!orbitSolana.getConnectedSolanaConnector())throw new Error("Wallet not provided. Cannot perform chain check.");try{k(r,orbitCore.lastConnectedConnectorHelpers.getLastConnectedConnector()?.chainId??"");}catch(n){throw n instanceof l?n:new Error(`Chain check failed: ${n instanceof Error?n.message:String(n)}`)}},checkTransactionsTracker:r=>({tracker:pulsarCore.TransactionTracker.Solana,txKey:r}),checkAndInitializeTrackerInStore:({tx:r,...e})=>S({tracker:r.tracker,tx:r,...e}),getExplorerUrl:(r,e)=>orbitSolana.getSolanaExplorerLink(r,e),getExplorerTxUrl:r=>orbitSolana.getSolanaExplorerLink(`/tx/${r.txKey}`,r.chainId),retryTxAction:async({onClose:r,txKey:e,executeTxAction:n,tx:o})=>{r(e);let s=orbitSolana.getAvailableSolanaConnectors().filter(i=>i.accounts.length>0)[0];if(!s||!s.accounts[0].address||s.accounts[0].address==="0x0")throw new Error("Retry failed: A wallet must be connected.");if(!n)throw new Error("Retry failed: executeTxAction function is not provided.");let u=orbitSolana.getCluster({cluster:o?.desiredChainID}),c=o.rpcUrl??orbitSolana.getRpcUrlForCluster({cluster:u,rpcUrls:a});if(!c)throw new Error("Retry failed: Could not determine RPC endpoint for the transaction chain.");let d=orbitSolana.createSolanaClientWithCache({rpcUrlOrMoniker:c,rpcUrls:a});await n({actionFunction:()=>o.actionFunction({client:d,...o.payload}),params:o,defaultTracker:pulsarCore.TransactionTracker.Solana});}}}async function hr({client:t,signer:a,instruction:r}){let{value:e}=await t.rpc.getLatestBlockhash().send(),n=gill.createTransaction({feePayer:a,version:0,latestBlockhash:e,instructions:Array.isArray(r)?r:[r]}),o=await gill.signAndSendTransactionMessageWithSigners(n);return gill.getBase58Decoder().decode(o)}exports.SolanaChainMismatchError=l;exports.checkAndInitializeTrackerInStore=S;exports.checkSolanaChain=k;exports.pulsarSolanaAdapter=pr;exports.signAndSendSolanaTx=hr;exports.solanaFetcher=F;exports.solanaTrackerForStore=h;
1
+ 'use strict';var orbitCore=require('@tuwaio/orbit-core'),orbitSolana=require('@tuwaio/orbit-solana'),pulsarCore=require('@tuwaio/pulsar-core'),d=require('dayjs'),gill=require('gill');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var d__default=/*#__PURE__*/_interopDefault(d);var l=class extends Error{name="SolanaChainMismatchError";requiredChain;currentChain;constructor(o,r){let e=`Wrong chain. The transaction requires ${o}, but you are connected to ${r}.`;super(e),this.requiredChain=o,this.currentChain=r;}};async function R({tx:t,stopPolling:o,onSuccess:r,onFailure:e,onIntervalTick:n}){if(t.adapter!==orbitCore.OrbitAdapter.SOLANA)throw new Error('Tx adapter is not Solana. Please set the adapter to "solana" in the transaction object.');try{let a=orbitSolana.createSolanaRPC({rpcUrlOrMoniker:t.rpcUrl??orbitSolana.getCluster({cluster:t.chainId})}),i=(await a.getSignatureStatuses([t.txKey]).send())?.value?.[0];if(!i)return;let{fee:u,recentBlockhash:c,instructions:m}=t;if(!u||!c||!m){let A=await a.getTransaction(t.txKey,{encoding:"json",maxSupportedTransactionVersion:0}).send(),{meta:p,transaction:f}=A||{};if(!p||!f)return;u=Number(p.fee??0),c=f.message.recentBlockhash?.toString(),m=f.message.instructions;}let s={...i,slot:Number(i.slot),confirmations:Number(i.confirmations??0),fee:u,recentBlockhash:c,instructions:m};if(n?.(s),s.err){e(s),o({withoutRemoving:!0});return}if(s.confirmationStatus==="finalized"){r(s),o({withoutRemoving:!0});return}d__default.default().diff(d__default.default.unix(t.localTimestamp),"hour")>=1&&(e(s),o());}catch(a){console.error("Error in solanaFetcher:",a),e({err:a}),o();}}async function h({tx:t,onSuccess:o,onError:r,...e}){return pulsarCore.initializePollingTracker({tx:t,fetcher:R,removeTxFromPool:e.removeTxFromPool,pollingInterval:2500,maxRetries:10,onSuccess:n=>{e.updateTxParams(t.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,finishedTimestamp:d__default.default().unix(),fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash,confirmations:"MAX",slot:n.slot});let a=e.transactionsPool[t.txKey];o&&a&&o(a);},onIntervalTick:n=>{e.updateTxParams(t.txKey,{confirmations:n.confirmations??0,slot:n.slot,fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash});},onFailure:n=>{e.updateTxParams(t.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,error:orbitCore.normalizeError(n?.err??new Error("Transaction tracking timed out or the transaction was not found.")),finishedTimestamp:d__default.default().unix()});let a=e.transactionsPool[t.txKey];r&&a&&r(n?.err??new Error("Transaction tracking timed out or the transaction was not found."),a);}})}async function g({tx:t,tracker:o,onSuccess:r,onError:e,...n}){o===pulsarCore.TransactionTracker.Solana?await h({tx:t,onSuccess:r,onError:e,...n}):(console.error(`Unknown tracker type for Solana adapter: ${o}`),n.updateTxParams(t.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,error:orbitCore.normalizeError(new Error(`Unsupported tracker type: "${o}"`))}));}var S=(t,o)=>{if(o!==t)throw new l(t,o)};function gr(t){let{rpcUrls:o}=t;return {key:orbitCore.OrbitAdapter.SOLANA,getConnectorInfo:()=>{let r=orbitSolana.getConnectedSolanaConnector();return {walletAddress:orbitCore.lastConnectedConnectorHelpers.getLastConnectedConnector()?.address??r.accounts[0].address??"0x0",connectorType:orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.SOLANA,r.name)}},checkChainForTx:async r=>{if(!orbitSolana.getConnectedSolanaConnector())throw new Error("Wallet not provided. Cannot perform chain check.");try{S(r,orbitCore.lastConnectedConnectorHelpers.getLastConnectedConnector()?.chainId??"");}catch(n){throw n instanceof l?n:new Error(`Chain check failed: ${n instanceof Error?n.message:String(n)}`)}},checkTransactionsTracker:r=>({tracker:pulsarCore.TransactionTracker.Solana,txKey:r}),checkAndInitializeTrackerInStore:({tx:r,...e})=>g({tracker:r.tracker,tx:r,...e}),getExplorerUrl:(r,e)=>orbitSolana.getSolanaExplorerLink(r,e),getExplorerTxUrl:r=>orbitSolana.getSolanaExplorerLink(`/tx/${r.txKey}`,r.chainId),retryTxAction:async({onClose:r,txKey:e,executeTxAction:n,tx:a})=>{r(e);let i=orbitSolana.getAvailableSolanaConnectors().filter(s=>s.accounts.length>0)[0];if(!i||!i.accounts[0].address||i.accounts[0].address==="0x0")throw new Error("Retry failed: A wallet must be connected.");if(!n)throw new Error("Retry failed: executeTxAction function is not provided.");let u=orbitSolana.getCluster({cluster:a?.desiredChainID}),c=a.rpcUrl??orbitSolana.getRpcUrlForCluster({cluster:u,rpcUrls:o});if(!c)throw new Error("Retry failed: Could not determine RPC endpoint for the transaction chain.");let m=orbitSolana.createSolanaClientWithCache({rpcUrlOrMoniker:c,rpcUrls:o});await n({actionFunction:()=>a.actionFunction({client:m,...a.payload}),params:a,defaultTracker:pulsarCore.TransactionTracker.Solana});}}}async function xr({client:t,signer:o,instruction:r}){let{value:e}=await t.rpc.getLatestBlockhash().send(),n=gill.createTransaction({feePayer:o,version:0,latestBlockhash:e,instructions:Array.isArray(r)?r:[r]}),a=await gill.signAndSendTransactionMessageWithSigners(n);return gill.getBase58Decoder().decode(a)}exports.SolanaChainMismatchError=l;exports.checkAndInitializeTrackerInStore=g;exports.checkSolanaChain=S;exports.pulsarSolanaAdapter=gr;exports.signAndSendSolanaTx=xr;exports.solanaFetcher=R;exports.solanaTrackerForStore=h;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {OrbitAdapter,lastConnectedConnectorHelpers,getConnectorTypeFromName}from'@tuwaio/orbit-core';import {createSolanaRPC,getCluster,getAvailableSolanaConnectors,getRpcUrlForCluster,createSolanaClientWithCache,getSolanaExplorerLink,getConnectedSolanaConnector}from'@tuwaio/orbit-solana';import {initializePollingTracker,TransactionStatus,TransactionTracker}from'@tuwaio/pulsar-core';import f from'dayjs';import {createTransaction,signAndSendTransactionMessageWithSigners,getBase58Decoder}from'gill';var l=class extends Error{name="SolanaChainMismatchError";requiredChain;currentChain;constructor(a,r){let e=`Wrong chain. The transaction requires ${a}, but you are connected to ${r}.`;super(e),this.requiredChain=a,this.currentChain=r;}};async function F({tx:t,stopPolling:a,onSuccess:r,onFailure:e,onIntervalTick:n}){if(t.adapter!==OrbitAdapter.SOLANA)throw new Error('Tx adapter is not Solana. Please set the adapter to "solana" in the transaction object.');try{let o=createSolanaRPC({rpcUrlOrMoniker:t.rpcUrl??getCluster({cluster:t.chainId})}),s=(await o.getSignatureStatuses([t.txKey]).send())?.value?.[0];if(!s)return;let{fee:u,recentBlockhash:c,instructions:d}=t;if(!u||!c||!d){let A=await o.getTransaction(t.txKey,{encoding:"json",maxSupportedTransactionVersion:0}).send(),{meta:T,transaction:p}=A||{};if(!T||!p)return;u=Number(T.fee??0),c=p.message.recentBlockhash?.toString(),d=p.message.instructions;}let i={...s,slot:Number(s.slot),confirmations:Number(s.confirmations??0),fee:u,recentBlockhash:c,instructions:d};if(n?.(i),i.err){e(i),a({withoutRemoving:!0});return}if(i.confirmationStatus==="finalized"){r(i),a({withoutRemoving:!0});return}f().diff(f.unix(t.localTimestamp),"hour")>=1&&(e(i),a());}catch(o){console.error("Error in solanaFetcher:",o),e({err:o}),a();}}async function h({tx:t,onSuccess:a,onError:r,...e}){return initializePollingTracker({tx:t,fetcher:F,removeTxFromPool:e.removeTxFromPool,pollingInterval:2500,maxRetries:10,onSuccess:n=>{e.updateTxParams(t.txKey,{status:TransactionStatus.Success,pending:false,isError:false,finishedTimestamp:f().unix(),fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash,confirmations:"MAX",slot:n.slot});let o=e.transactionsPool[t.txKey];a&&o&&a(o);},onIntervalTick:n=>{e.updateTxParams(t.txKey,{confirmations:n.confirmations??0,slot:n.slot,fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash});},onFailure:n=>{let o=n?.err?`Transaction failed: ${JSON.stringify(n.err)}`:"Transaction tracking timed out or the transaction was not found.";e.updateTxParams(t.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,errorMessage:o,finishedTimestamp:f().unix()});let m=e.transactionsPool[t.txKey];r&&m&&r(new Error(o),m);}})}async function S({tx:t,tracker:a,onSuccess:r,onError:e,...n}){a===TransactionTracker.Solana?await h({tx:t,onSuccess:r,onError:e,...n}):(console.error(`Unknown tracker type for Solana adapter: ${a}`),n.updateTxParams(t.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,errorMessage:`Unsupported tracker type: "${a}"`}));}var k=(t,a)=>{if(a!==t)throw new l(t,a)};function pr(t){let{rpcUrls:a}=t;return {key:OrbitAdapter.SOLANA,getConnectorInfo:()=>{let r=getConnectedSolanaConnector();return {walletAddress:lastConnectedConnectorHelpers.getLastConnectedConnector()?.address??r.accounts[0].address??"0x0",connectorType:getConnectorTypeFromName(OrbitAdapter.SOLANA,r.name)}},checkChainForTx:async r=>{if(!getConnectedSolanaConnector())throw new Error("Wallet not provided. Cannot perform chain check.");try{k(r,lastConnectedConnectorHelpers.getLastConnectedConnector()?.chainId??"");}catch(n){throw n instanceof l?n:new Error(`Chain check failed: ${n instanceof Error?n.message:String(n)}`)}},checkTransactionsTracker:r=>({tracker:TransactionTracker.Solana,txKey:r}),checkAndInitializeTrackerInStore:({tx:r,...e})=>S({tracker:r.tracker,tx:r,...e}),getExplorerUrl:(r,e)=>getSolanaExplorerLink(r,e),getExplorerTxUrl:r=>getSolanaExplorerLink(`/tx/${r.txKey}`,r.chainId),retryTxAction:async({onClose:r,txKey:e,executeTxAction:n,tx:o})=>{r(e);let s=getAvailableSolanaConnectors().filter(i=>i.accounts.length>0)[0];if(!s||!s.accounts[0].address||s.accounts[0].address==="0x0")throw new Error("Retry failed: A wallet must be connected.");if(!n)throw new Error("Retry failed: executeTxAction function is not provided.");let u=getCluster({cluster:o?.desiredChainID}),c=o.rpcUrl??getRpcUrlForCluster({cluster:u,rpcUrls:a});if(!c)throw new Error("Retry failed: Could not determine RPC endpoint for the transaction chain.");let d=createSolanaClientWithCache({rpcUrlOrMoniker:c,rpcUrls:a});await n({actionFunction:()=>o.actionFunction({client:d,...o.payload}),params:o,defaultTracker:TransactionTracker.Solana});}}}async function hr({client:t,signer:a,instruction:r}){let{value:e}=await t.rpc.getLatestBlockhash().send(),n=createTransaction({feePayer:a,version:0,latestBlockhash:e,instructions:Array.isArray(r)?r:[r]}),o=await signAndSendTransactionMessageWithSigners(n);return getBase58Decoder().decode(o)}export{l as SolanaChainMismatchError,S as checkAndInitializeTrackerInStore,k as checkSolanaChain,pr as pulsarSolanaAdapter,hr as signAndSendSolanaTx,F as solanaFetcher,h as solanaTrackerForStore};
1
+ import {OrbitAdapter,normalizeError,lastConnectedConnectorHelpers,getConnectorTypeFromName}from'@tuwaio/orbit-core';import {createSolanaRPC,getCluster,getAvailableSolanaConnectors,getRpcUrlForCluster,createSolanaClientWithCache,getSolanaExplorerLink,getConnectedSolanaConnector}from'@tuwaio/orbit-solana';import {initializePollingTracker,TransactionStatus,TransactionTracker}from'@tuwaio/pulsar-core';import d from'dayjs';import {createTransaction,signAndSendTransactionMessageWithSigners,getBase58Decoder}from'gill';var l=class extends Error{name="SolanaChainMismatchError";requiredChain;currentChain;constructor(o,r){let e=`Wrong chain. The transaction requires ${o}, but you are connected to ${r}.`;super(e),this.requiredChain=o,this.currentChain=r;}};async function R({tx:t,stopPolling:o,onSuccess:r,onFailure:e,onIntervalTick:n}){if(t.adapter!==OrbitAdapter.SOLANA)throw new Error('Tx adapter is not Solana. Please set the adapter to "solana" in the transaction object.');try{let a=createSolanaRPC({rpcUrlOrMoniker:t.rpcUrl??getCluster({cluster:t.chainId})}),i=(await a.getSignatureStatuses([t.txKey]).send())?.value?.[0];if(!i)return;let{fee:u,recentBlockhash:c,instructions:m}=t;if(!u||!c||!m){let A=await a.getTransaction(t.txKey,{encoding:"json",maxSupportedTransactionVersion:0}).send(),{meta:p,transaction:f}=A||{};if(!p||!f)return;u=Number(p.fee??0),c=f.message.recentBlockhash?.toString(),m=f.message.instructions;}let s={...i,slot:Number(i.slot),confirmations:Number(i.confirmations??0),fee:u,recentBlockhash:c,instructions:m};if(n?.(s),s.err){e(s),o({withoutRemoving:!0});return}if(s.confirmationStatus==="finalized"){r(s),o({withoutRemoving:!0});return}d().diff(d.unix(t.localTimestamp),"hour")>=1&&(e(s),o());}catch(a){console.error("Error in solanaFetcher:",a),e({err:a}),o();}}async function h({tx:t,onSuccess:o,onError:r,...e}){return initializePollingTracker({tx:t,fetcher:R,removeTxFromPool:e.removeTxFromPool,pollingInterval:2500,maxRetries:10,onSuccess:n=>{e.updateTxParams(t.txKey,{status:TransactionStatus.Success,pending:false,isError:false,finishedTimestamp:d().unix(),fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash,confirmations:"MAX",slot:n.slot});let a=e.transactionsPool[t.txKey];o&&a&&o(a);},onIntervalTick:n=>{e.updateTxParams(t.txKey,{confirmations:n.confirmations??0,slot:n.slot,fee:n.fee,instructions:n.instructions,recentBlockhash:n.recentBlockhash});},onFailure:n=>{e.updateTxParams(t.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,error:normalizeError(n?.err??new Error("Transaction tracking timed out or the transaction was not found.")),finishedTimestamp:d().unix()});let a=e.transactionsPool[t.txKey];r&&a&&r(n?.err??new Error("Transaction tracking timed out or the transaction was not found."),a);}})}async function g({tx:t,tracker:o,onSuccess:r,onError:e,...n}){o===TransactionTracker.Solana?await h({tx:t,onSuccess:r,onError:e,...n}):(console.error(`Unknown tracker type for Solana adapter: ${o}`),n.updateTxParams(t.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,error:normalizeError(new Error(`Unsupported tracker type: "${o}"`))}));}var S=(t,o)=>{if(o!==t)throw new l(t,o)};function gr(t){let{rpcUrls:o}=t;return {key:OrbitAdapter.SOLANA,getConnectorInfo:()=>{let r=getConnectedSolanaConnector();return {walletAddress:lastConnectedConnectorHelpers.getLastConnectedConnector()?.address??r.accounts[0].address??"0x0",connectorType:getConnectorTypeFromName(OrbitAdapter.SOLANA,r.name)}},checkChainForTx:async r=>{if(!getConnectedSolanaConnector())throw new Error("Wallet not provided. Cannot perform chain check.");try{S(r,lastConnectedConnectorHelpers.getLastConnectedConnector()?.chainId??"");}catch(n){throw n instanceof l?n:new Error(`Chain check failed: ${n instanceof Error?n.message:String(n)}`)}},checkTransactionsTracker:r=>({tracker:TransactionTracker.Solana,txKey:r}),checkAndInitializeTrackerInStore:({tx:r,...e})=>g({tracker:r.tracker,tx:r,...e}),getExplorerUrl:(r,e)=>getSolanaExplorerLink(r,e),getExplorerTxUrl:r=>getSolanaExplorerLink(`/tx/${r.txKey}`,r.chainId),retryTxAction:async({onClose:r,txKey:e,executeTxAction:n,tx:a})=>{r(e);let i=getAvailableSolanaConnectors().filter(s=>s.accounts.length>0)[0];if(!i||!i.accounts[0].address||i.accounts[0].address==="0x0")throw new Error("Retry failed: A wallet must be connected.");if(!n)throw new Error("Retry failed: executeTxAction function is not provided.");let u=getCluster({cluster:a?.desiredChainID}),c=a.rpcUrl??getRpcUrlForCluster({cluster:u,rpcUrls:o});if(!c)throw new Error("Retry failed: Could not determine RPC endpoint for the transaction chain.");let m=createSolanaClientWithCache({rpcUrlOrMoniker:c,rpcUrls:o});await n({actionFunction:()=>a.actionFunction({client:m,...a.payload}),params:a,defaultTracker:TransactionTracker.Solana});}}}async function xr({client:t,signer:o,instruction:r}){let{value:e}=await t.rpc.getLatestBlockhash().send(),n=createTransaction({feePayer:o,version:0,latestBlockhash:e,instructions:Array.isArray(r)?r:[r]}),a=await signAndSendTransactionMessageWithSigners(n);return getBase58Decoder().decode(a)}export{l as SolanaChainMismatchError,g as checkAndInitializeTrackerInStore,S as checkSolanaChain,gr as pulsarSolanaAdapter,xr as signAndSendSolanaTx,R as solanaFetcher,h as solanaTrackerForStore};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/pulsar-solana",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
@@ -38,9 +38,9 @@
38
38
  }
39
39
  ],
40
40
  "peerDependencies": {
41
- "@tuwaio/orbit-core": ">=0.2",
42
- "@tuwaio/orbit-solana": ">=0.2",
43
- "@tuwaio/pulsar-core": ">=0.3",
41
+ "@tuwaio/orbit-core": ">=0.2.7",
42
+ "@tuwaio/orbit-solana": ">=0.2.3",
43
+ "@tuwaio/pulsar-core": ">=0.5",
44
44
  "@wallet-standard/app": "1.x.x",
45
45
  "@wallet-standard/ui-core": "1.x.x",
46
46
  "@wallet-standard/ui-registry": "1.x.x",
@@ -50,20 +50,20 @@
50
50
  "zustand": "5.x.x"
51
51
  },
52
52
  "devDependencies": {
53
- "@tuwaio/orbit-core": "^0.2.4",
54
- "@tuwaio/orbit-solana": "^0.2.2",
53
+ "@tuwaio/orbit-core": "^0.2.7",
54
+ "@tuwaio/orbit-solana": "^0.2.3",
55
55
  "@wallet-standard/app": "^1.1.0",
56
56
  "@wallet-standard/ui-core": "^1.0.0",
57
57
  "@wallet-standard/ui-registry": "^1.0.1",
58
58
  "dayjs": "^1.11.19",
59
59
  "gill": "^0.14.0",
60
60
  "immer": "^11.1.3",
61
- "jsdom": "^27.4.0",
61
+ "jsdom": "^28.0.0",
62
62
  "tsup": "^8.5.1",
63
63
  "typescript": "^5.9.3",
64
64
  "vitest": "^4.0.18",
65
- "zustand": "^5.0.10",
66
- "@tuwaio/pulsar-core": "^0.4.0"
65
+ "zustand": "^5.0.11",
66
+ "@tuwaio/pulsar-core": "^0.5.0"
67
67
  },
68
68
  "scripts": {
69
69
  "start": "tsup src/index.ts --watch",