@phantom/browser-sdk 0.0.2 → 0.0.4
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 +168 -1
- package/dist/solana/index.d.ts +134 -2
- package/dist/solana/index.js +171 -1
- package/dist/solana/index.mjs +171 -1
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -1,3 +1,170 @@
|
|
|
1
1
|
# Phantom Browser SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Phantom Browser SDK allows you to interact with the Phantom wallet from your web application. It uses a plugin system to support different blockchains.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
You can install the SDK using npm or yarn:
|
|
8
|
+
|
|
9
|
+
**npm:**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @phantom/browser-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**yarn:**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn add @phantom/browser-sdk
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Here's an example of how to import and use the SDK with the Solana plugin:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createPhantom } from "@phantom/browser-sdk";
|
|
27
|
+
import { createSolanaPlugin } from "@phantom/browser-sdk/solana"; // Import the solana plugin
|
|
28
|
+
|
|
29
|
+
// Create a Phantom instance with the Solana plugin
|
|
30
|
+
const phantom = createPhantom({
|
|
31
|
+
chainPlugins: [createSolanaPlugin()],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Now you can use the Solana-specific methods
|
|
35
|
+
async function connectAndSign() {
|
|
36
|
+
try {
|
|
37
|
+
// Get the Solana provider (Phantom wallet instance)
|
|
38
|
+
const provider = phantom.solana.getProvider();
|
|
39
|
+
|
|
40
|
+
if (!provider) {
|
|
41
|
+
console.error("Phantom wallet not found. Please install Phantom.");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Attempt to connect to the wallet
|
|
46
|
+
const connectionResult = await phantom.solana.connect();
|
|
47
|
+
console.log("Connection Result:", connectionResult.address);
|
|
48
|
+
|
|
49
|
+
// Example: Sign in (if supported by the specific provider/plugin)
|
|
50
|
+
// Construct SolanaSignInData according to your needs
|
|
51
|
+
const signInData = { domain: window.location.host, statement: "Please sign in to access this dApp." };
|
|
52
|
+
const signInResult = await phantom.solana.signIn(signInData);
|
|
53
|
+
console.log("Sign In Result:", signInResult.address);
|
|
54
|
+
|
|
55
|
+
// Example: Sign a message
|
|
56
|
+
const message = new TextEncoder().encode("Hello from Phantom Browser SDK!");
|
|
57
|
+
const signedMessage = await phantom.solana.signMessage(message, "utf8");
|
|
58
|
+
console.log("Signed Message:", signedMessage);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("Error interacting with Phantom:", error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
connectAndSign();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Available Solana Methods
|
|
68
|
+
|
|
69
|
+
Once the `phantom.solana` object is initialized, you can access the following methods:
|
|
70
|
+
|
|
71
|
+
- `getProvider(): PhantomSolanaProvider | null`
|
|
72
|
+
- Retrieves the Phantom Solana provider instance.
|
|
73
|
+
- `connect(opts?: { onlyIfTrusted?: boolean }): Promise<string>`
|
|
74
|
+
- Connects to the Phantom wallet. Optionally, `onlyIfTrusted` can be set to true to only connect if the dApp is already trusted.
|
|
75
|
+
- `disconnect(): Promise<void>`
|
|
76
|
+
- Disconnects from the Phantom wallet.
|
|
77
|
+
- `getAccount(): { status: "connected" | "disconnected"; address: string | null }`
|
|
78
|
+
- Gets the current connected account state. When account is connected returns a public key, when it's not returns it as null.
|
|
79
|
+
- `signIn(): Promise<SignInResult>`
|
|
80
|
+
- Initiates a sign-in request to the wallet.
|
|
81
|
+
- `signMessage(message: Uint8Array | string, display?: 'utf8' | 'hex'): Promise<SignedMessage>`
|
|
82
|
+
- Prompts the user to sign a given message.
|
|
83
|
+
- `signAndSendTransaction(transaction: Transaction): Promise<{ signature: string; address?: string }>`
|
|
84
|
+
- Prompts the user to sign **and send** a Kit `Transaction` and returns the confirmed signature.
|
|
85
|
+
|
|
86
|
+
### Event Handling
|
|
87
|
+
|
|
88
|
+
The SDK also allows you to listen for `connect`, `disconnect`, and `accountChanged` events:
|
|
89
|
+
|
|
90
|
+
- `addEventListener(event: PhantomEventType, callback: PhantomEventCallback): () => void`
|
|
91
|
+
|
|
92
|
+
- Registers a callback that will be invoked when the specified event occurs.
|
|
93
|
+
- For the `connect` event, the callback receives the public key (as a string) of the connected account.
|
|
94
|
+
- For the `disconnect` event, the callback receives no arguments.
|
|
95
|
+
- For the `accountChanged` event, the callback receives the new public key (as a string).
|
|
96
|
+
- Returns a function that, when called, will unregister the callback.
|
|
97
|
+
- Multiple callbacks can be registered for the same event.
|
|
98
|
+
|
|
99
|
+
**Example:**
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const phantom = createPhantom({ chainPlugins: [createSolanaPlugin()] });
|
|
103
|
+
|
|
104
|
+
const handleConnect = (address: string) => {
|
|
105
|
+
console.log(`Wallet connected with public key: ${address}`);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const clearConnectListener = phantom.solana.addEventListener("connect", handleConnect);
|
|
109
|
+
|
|
110
|
+
const handleAccountChanged = (newAddress: string) => {
|
|
111
|
+
console.log(`Account changed to: ${newAddress}`);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const clearAccountChangedListener = phantom.solana.addEventListener("accountChanged", handleAccountChanged);
|
|
115
|
+
|
|
116
|
+
// To stop listening for a specific event:
|
|
117
|
+
// clearConnectListener();
|
|
118
|
+
// clearAccountChangedListener();
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- `removeEventListener(event: PhantomEventType, callback: PhantomEventCallback): void`
|
|
122
|
+
|
|
123
|
+
- Unregisters a previously registered callback for the specified event.
|
|
124
|
+
|
|
125
|
+
**Example:**
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const phantom = createPhantom({ chainPlugins: [createSolanaPlugin()] });
|
|
129
|
+
|
|
130
|
+
const handleDisconnect = () => {
|
|
131
|
+
console.log("Wallet disconnected");
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
phantom.solana.addEventListener("disconnect", handleDisconnect);
|
|
135
|
+
|
|
136
|
+
// To stop listening for this specific disconnect event:
|
|
137
|
+
// phantom.solana.removeEventListener("disconnect", handleDisconnect);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Creating a transaction
|
|
141
|
+
|
|
142
|
+
Phantom's SDK uses the `@solana/kit` library to create transactions. You can use the `createTransactionMessage` function to create a transaction message.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import {
|
|
146
|
+
createSolanaRpc,
|
|
147
|
+
pipe,
|
|
148
|
+
createTransactionMessage,
|
|
149
|
+
setTransactionMessageFeePayer,
|
|
150
|
+
setTransactionMessageLifetimeUsingBlockhash,
|
|
151
|
+
address,
|
|
152
|
+
compileTransaction,
|
|
153
|
+
} from "@solana/kit";
|
|
154
|
+
|
|
155
|
+
// Example: Sign and send a transaction
|
|
156
|
+
|
|
157
|
+
const rpc = createSolanaRpc("https://my-rpc-url.com"); // Replace with your own RPC URL
|
|
158
|
+
|
|
159
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
160
|
+
|
|
161
|
+
const transactionMessage = pipe(
|
|
162
|
+
createTransactionMessage({ version: 0 }),
|
|
163
|
+
tx => setTransactionMessageFeePayer(address(userPublicKey as string), tx),
|
|
164
|
+
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const transaction = compileTransaction(transactionMessage);
|
|
168
|
+
|
|
169
|
+
const { signature } = await phantomInstance.solana.signAndSendTransaction(transaction);
|
|
170
|
+
```
|
package/dist/solana/index.d.ts
CHANGED
|
@@ -1,7 +1,139 @@
|
|
|
1
1
|
import { ChainPlugin } from '../index.js';
|
|
2
|
+
import { Transaction as Transaction$1 } from '@solana/kit';
|
|
3
|
+
|
|
4
|
+
type Transaction = {
|
|
5
|
+
message: Uint8Array;
|
|
6
|
+
recentBlockhash: string;
|
|
7
|
+
feePayer: string;
|
|
8
|
+
instructions: any[];
|
|
9
|
+
signers: string[];
|
|
10
|
+
version: number;
|
|
11
|
+
};
|
|
12
|
+
type VersionedTransaction = {
|
|
13
|
+
signatures: Uint8Array[];
|
|
14
|
+
message: {
|
|
15
|
+
deserialize: (serializedTransaction: Uint8Array) => VersionedTransaction;
|
|
16
|
+
serialize: (transaction: VersionedTransaction) => Uint8Array;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
type SendOptions = {
|
|
20
|
+
skipPreflight?: boolean;
|
|
21
|
+
preflightCommitment?: string;
|
|
22
|
+
maxRetries?: number;
|
|
23
|
+
minContextSlot?: number;
|
|
24
|
+
};
|
|
25
|
+
type PublicKey = {
|
|
26
|
+
toString: () => string;
|
|
27
|
+
toBase58: () => string;
|
|
28
|
+
};
|
|
29
|
+
type SolanaSignInData = {
|
|
30
|
+
domain?: string;
|
|
31
|
+
address?: string;
|
|
32
|
+
statement?: string;
|
|
33
|
+
uri?: string;
|
|
34
|
+
version?: string;
|
|
35
|
+
chainId?: string;
|
|
36
|
+
nonce?: string;
|
|
37
|
+
issuedAt?: string;
|
|
38
|
+
expirationTime?: string;
|
|
39
|
+
notBefore?: string;
|
|
40
|
+
requestId?: string;
|
|
41
|
+
resources?: string[];
|
|
42
|
+
};
|
|
43
|
+
type DisplayEncoding = "utf8" | "hex";
|
|
44
|
+
type PhantomEventType = "connect" | "disconnect" | "accountChanged";
|
|
45
|
+
interface PhantomSolanaProvider {
|
|
46
|
+
isPhantom: boolean;
|
|
47
|
+
publicKey: PublicKey | null;
|
|
48
|
+
isConnected: boolean;
|
|
49
|
+
connect: (opts?: {
|
|
50
|
+
onlyIfTrusted?: boolean;
|
|
51
|
+
}) => Promise<{
|
|
52
|
+
publicKey: PublicKey;
|
|
53
|
+
}>;
|
|
54
|
+
disconnect: () => Promise<void>;
|
|
55
|
+
signMessage: (message: Uint8Array, display?: DisplayEncoding) => Promise<{
|
|
56
|
+
signature: Uint8Array;
|
|
57
|
+
publicKey: PublicKey;
|
|
58
|
+
}>;
|
|
59
|
+
signIn: (signInData: SolanaSignInData) => Promise<{
|
|
60
|
+
address: PublicKey;
|
|
61
|
+
signature: Uint8Array;
|
|
62
|
+
signedMessage: Uint8Array;
|
|
63
|
+
}>;
|
|
64
|
+
signAndSendTransaction: (transaction: Transaction | VersionedTransaction, options?: SendOptions) => Promise<{
|
|
65
|
+
signature: string;
|
|
66
|
+
publicKey?: string;
|
|
67
|
+
}>;
|
|
68
|
+
signAllTransactions: (transactions: (Transaction | VersionedTransaction)[]) => Promise<(Transaction | VersionedTransaction)[]>;
|
|
69
|
+
signTransaction: (transaction: Transaction | VersionedTransaction) => Promise<Transaction | VersionedTransaction>;
|
|
70
|
+
on: (event: "connect" | "disconnect" | "accountChanged", handler: (publicKey?: PublicKey) => void) => void;
|
|
71
|
+
off: (event: "connect" | "disconnect" | "accountChanged", handler: (publicKey?: PublicKey) => void) => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Signs a message using the Phantom provider.
|
|
76
|
+
* @param message The message to sign (as a Uint8Array).
|
|
77
|
+
* @param display The display encoding for the message (optional, defaults to utf8).
|
|
78
|
+
* @returns A promise that resolves with the signature and public key.
|
|
79
|
+
* @throws Error if Phantom provider is not found or if the operation fails.
|
|
80
|
+
*/
|
|
81
|
+
declare function signMessage(message: Uint8Array, display?: DisplayEncoding): Promise<{
|
|
82
|
+
signature: Uint8Array;
|
|
83
|
+
address: string;
|
|
84
|
+
}>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Signs in with Solana using the Phantom provider.
|
|
88
|
+
* @param signInData The sign-in data.
|
|
89
|
+
* @returns A promise that resolves with the address, signature, and signed message.
|
|
90
|
+
* @throws Error if Phantom provider is not found or if the operation fails.
|
|
91
|
+
*/
|
|
92
|
+
declare function signIn(signInData: SolanaSignInData): Promise<{
|
|
93
|
+
address: string;
|
|
94
|
+
signature: Uint8Array;
|
|
95
|
+
signedMessage: Uint8Array;
|
|
96
|
+
}>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Signs and sends a transaction using the Phantom provider.
|
|
100
|
+
* @param transaction The transaction to sign and send.
|
|
101
|
+
* @returns A promise that resolves with the transaction signature and optionally the public key.
|
|
102
|
+
* @throws Error if Phantom provider is not found or if the operation fails.
|
|
103
|
+
*/
|
|
104
|
+
declare function signAndSendTransaction(transaction: Transaction$1): Promise<{
|
|
105
|
+
signature: string;
|
|
106
|
+
address?: string;
|
|
107
|
+
}>;
|
|
108
|
+
|
|
109
|
+
declare function connect(): Promise<string | undefined>;
|
|
110
|
+
|
|
111
|
+
declare function disconnect(): Promise<void>;
|
|
112
|
+
|
|
113
|
+
type ConnectCallback = (publicKey: string) => void;
|
|
114
|
+
type DisconnectCallback = () => void;
|
|
115
|
+
type AccountChangedCallback = (publicKey: string) => void;
|
|
116
|
+
type PhantomEventCallback = ConnectCallback | DisconnectCallback | AccountChangedCallback;
|
|
117
|
+
|
|
118
|
+
type GetAccountResult = {
|
|
119
|
+
status: "connected";
|
|
120
|
+
address: string;
|
|
121
|
+
} | {
|
|
122
|
+
status: "disconnected";
|
|
123
|
+
address: null;
|
|
124
|
+
};
|
|
125
|
+
declare function getAccount(): GetAccountResult;
|
|
2
126
|
|
|
3
127
|
type Solana = {
|
|
4
|
-
getProvider: () =>
|
|
128
|
+
getProvider: () => PhantomSolanaProvider | null;
|
|
129
|
+
connect: typeof connect;
|
|
130
|
+
disconnect: typeof disconnect;
|
|
131
|
+
getAccount: typeof getAccount;
|
|
132
|
+
signMessage: typeof signMessage;
|
|
133
|
+
signIn: typeof signIn;
|
|
134
|
+
signAndSendTransaction: typeof signAndSendTransaction;
|
|
135
|
+
addEventListener: (event: PhantomEventType, callback: PhantomEventCallback) => () => void;
|
|
136
|
+
removeEventListener: (event: PhantomEventType, callback: PhantomEventCallback) => void;
|
|
5
137
|
};
|
|
6
138
|
declare function createSolanaPlugin(): ChainPlugin<Solana>;
|
|
7
139
|
|
|
@@ -11,4 +143,4 @@ declare module "../index" {
|
|
|
11
143
|
}
|
|
12
144
|
}
|
|
13
145
|
|
|
14
|
-
export { createSolanaPlugin };
|
|
146
|
+
export { PhantomSolanaProvider, SolanaSignInData, createSolanaPlugin };
|
package/dist/solana/index.js
CHANGED
|
@@ -29,9 +29,179 @@ function getProvider() {
|
|
|
29
29
|
return window.phantom?.solana ?? null;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// src/solana/eventListeners.ts
|
|
33
|
+
var eventCallbacks = /* @__PURE__ */ new Map();
|
|
34
|
+
function addEventListener(event, callback) {
|
|
35
|
+
if (!eventCallbacks.has(event)) {
|
|
36
|
+
eventCallbacks.set(event, /* @__PURE__ */ new Set());
|
|
37
|
+
}
|
|
38
|
+
eventCallbacks.get(event).add(callback);
|
|
39
|
+
return () => {
|
|
40
|
+
removeEventListener(event, callback);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function removeEventListener(event, callback) {
|
|
44
|
+
if (eventCallbacks.has(event)) {
|
|
45
|
+
eventCallbacks.get(event).delete(callback);
|
|
46
|
+
if (eventCallbacks.get(event).size === 0) {
|
|
47
|
+
eventCallbacks.delete(event);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function triggerEvent(event, ...args) {
|
|
52
|
+
if (eventCallbacks.has(event)) {
|
|
53
|
+
eventCallbacks.get(event).forEach((cb) => {
|
|
54
|
+
if (event === "connect" && args[0] && typeof args[0] === "string") {
|
|
55
|
+
cb(args[0]);
|
|
56
|
+
} else if (event === "disconnect") {
|
|
57
|
+
cb();
|
|
58
|
+
} else if (event === "accountChanged" && args[0] && typeof args[0] === "string") {
|
|
59
|
+
cb(args[0]);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/solana/connect.ts
|
|
66
|
+
async function connect() {
|
|
67
|
+
const provider = getProvider();
|
|
68
|
+
if (!provider) {
|
|
69
|
+
throw new Error("Phantom provider not found.");
|
|
70
|
+
}
|
|
71
|
+
if (provider.isConnected) {
|
|
72
|
+
return provider.publicKey?.toString();
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const eagerConnectResult = await provider.connect({ onlyIfTrusted: true });
|
|
76
|
+
if (eagerConnectResult.publicKey) {
|
|
77
|
+
const publicKeyStr = eagerConnectResult.publicKey.toString();
|
|
78
|
+
triggerEvent("connect", publicKeyStr);
|
|
79
|
+
return publicKeyStr;
|
|
80
|
+
}
|
|
81
|
+
} catch (error) {
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const connectResult = await provider.connect({ onlyIfTrusted: false });
|
|
85
|
+
if (connectResult.publicKey) {
|
|
86
|
+
const publicKeyStr = connectResult.publicKey.toString();
|
|
87
|
+
triggerEvent("connect", publicKeyStr);
|
|
88
|
+
return publicKeyStr;
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
}
|
|
92
|
+
throw new Error("Failed to connect to Phantom.");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/solana/signMessage.ts
|
|
96
|
+
async function signMessage(message, display) {
|
|
97
|
+
const provider = getProvider();
|
|
98
|
+
if (!provider) {
|
|
99
|
+
throw new Error("Phantom provider not found.");
|
|
100
|
+
}
|
|
101
|
+
if (!provider.isConnected) {
|
|
102
|
+
await connect();
|
|
103
|
+
}
|
|
104
|
+
if (!provider.signMessage) {
|
|
105
|
+
throw new Error("The connected provider does not support signMessage.");
|
|
106
|
+
}
|
|
107
|
+
if (!provider.isConnected) {
|
|
108
|
+
throw new Error("Provider is not connected even after attempting to connect.");
|
|
109
|
+
}
|
|
110
|
+
const result = await provider.signMessage(message, display);
|
|
111
|
+
return {
|
|
112
|
+
signature: result.signature,
|
|
113
|
+
address: result.publicKey.toString()
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/solana/signIn.ts
|
|
118
|
+
async function signIn(signInData) {
|
|
119
|
+
const provider = getProvider();
|
|
120
|
+
if (!provider) {
|
|
121
|
+
throw new Error("Phantom provider not found.");
|
|
122
|
+
}
|
|
123
|
+
if (!provider.signIn) {
|
|
124
|
+
throw new Error("The connected provider does not support signIn.");
|
|
125
|
+
}
|
|
126
|
+
const result = await provider.signIn(signInData);
|
|
127
|
+
return {
|
|
128
|
+
address: result.address.toString(),
|
|
129
|
+
signature: result.signature,
|
|
130
|
+
signedMessage: result.signedMessage
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/solana/utils/transactionToVersionedTransaction.ts
|
|
135
|
+
var import_transactions = require("@solana/transactions");
|
|
136
|
+
function transactionToVersionedTransaction(transaction) {
|
|
137
|
+
const serialized = (0, import_transactions.getTransactionEncoder)().encode(transaction);
|
|
138
|
+
const fakeVersioned = {
|
|
139
|
+
serialize() {
|
|
140
|
+
return new Uint8Array(serialized);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return fakeVersioned;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/solana/signAndSendTransaction.ts
|
|
147
|
+
async function signAndSendTransaction(transaction) {
|
|
148
|
+
const provider = getProvider();
|
|
149
|
+
if (!provider) {
|
|
150
|
+
throw new Error("Phantom provider not found.");
|
|
151
|
+
}
|
|
152
|
+
if (!provider.isConnected) {
|
|
153
|
+
await connect();
|
|
154
|
+
}
|
|
155
|
+
if (!provider.signAndSendTransaction) {
|
|
156
|
+
throw new Error("The connected provider does not support signAndSendTransaction.");
|
|
157
|
+
}
|
|
158
|
+
if (!provider.isConnected) {
|
|
159
|
+
throw new Error("Provider is not connected even after attempting to connect.");
|
|
160
|
+
}
|
|
161
|
+
const versionedTransaction = transactionToVersionedTransaction(transaction);
|
|
162
|
+
const result = await provider.signAndSendTransaction(versionedTransaction);
|
|
163
|
+
return {
|
|
164
|
+
signature: result.signature,
|
|
165
|
+
address: result.publicKey
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/solana/disconnect.ts
|
|
170
|
+
async function disconnect() {
|
|
171
|
+
const provider = getProvider();
|
|
172
|
+
if (!provider) {
|
|
173
|
+
throw new Error("Phantom provider not found.");
|
|
174
|
+
}
|
|
175
|
+
await provider.disconnect();
|
|
176
|
+
triggerEvent("disconnect");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/solana/getAccount.ts
|
|
180
|
+
function getAccount() {
|
|
181
|
+
const provider = getProvider();
|
|
182
|
+
if (provider && provider.isConnected && provider.publicKey) {
|
|
183
|
+
return {
|
|
184
|
+
status: "connected",
|
|
185
|
+
address: provider.publicKey.toString()
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
status: "disconnected",
|
|
190
|
+
address: null
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
32
194
|
// src/solana/plugin.ts
|
|
33
195
|
var solana = {
|
|
34
|
-
getProvider
|
|
196
|
+
getProvider,
|
|
197
|
+
connect,
|
|
198
|
+
disconnect,
|
|
199
|
+
getAccount,
|
|
200
|
+
signMessage,
|
|
201
|
+
signIn,
|
|
202
|
+
signAndSendTransaction,
|
|
203
|
+
addEventListener,
|
|
204
|
+
removeEventListener
|
|
35
205
|
};
|
|
36
206
|
function createSolanaPlugin() {
|
|
37
207
|
return {
|
package/dist/solana/index.mjs
CHANGED
|
@@ -3,9 +3,179 @@ function getProvider() {
|
|
|
3
3
|
return window.phantom?.solana ?? null;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
// src/solana/eventListeners.ts
|
|
7
|
+
var eventCallbacks = /* @__PURE__ */ new Map();
|
|
8
|
+
function addEventListener(event, callback) {
|
|
9
|
+
if (!eventCallbacks.has(event)) {
|
|
10
|
+
eventCallbacks.set(event, /* @__PURE__ */ new Set());
|
|
11
|
+
}
|
|
12
|
+
eventCallbacks.get(event).add(callback);
|
|
13
|
+
return () => {
|
|
14
|
+
removeEventListener(event, callback);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function removeEventListener(event, callback) {
|
|
18
|
+
if (eventCallbacks.has(event)) {
|
|
19
|
+
eventCallbacks.get(event).delete(callback);
|
|
20
|
+
if (eventCallbacks.get(event).size === 0) {
|
|
21
|
+
eventCallbacks.delete(event);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function triggerEvent(event, ...args) {
|
|
26
|
+
if (eventCallbacks.has(event)) {
|
|
27
|
+
eventCallbacks.get(event).forEach((cb) => {
|
|
28
|
+
if (event === "connect" && args[0] && typeof args[0] === "string") {
|
|
29
|
+
cb(args[0]);
|
|
30
|
+
} else if (event === "disconnect") {
|
|
31
|
+
cb();
|
|
32
|
+
} else if (event === "accountChanged" && args[0] && typeof args[0] === "string") {
|
|
33
|
+
cb(args[0]);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/solana/connect.ts
|
|
40
|
+
async function connect() {
|
|
41
|
+
const provider = getProvider();
|
|
42
|
+
if (!provider) {
|
|
43
|
+
throw new Error("Phantom provider not found.");
|
|
44
|
+
}
|
|
45
|
+
if (provider.isConnected) {
|
|
46
|
+
return provider.publicKey?.toString();
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const eagerConnectResult = await provider.connect({ onlyIfTrusted: true });
|
|
50
|
+
if (eagerConnectResult.publicKey) {
|
|
51
|
+
const publicKeyStr = eagerConnectResult.publicKey.toString();
|
|
52
|
+
triggerEvent("connect", publicKeyStr);
|
|
53
|
+
return publicKeyStr;
|
|
54
|
+
}
|
|
55
|
+
} catch (error) {
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const connectResult = await provider.connect({ onlyIfTrusted: false });
|
|
59
|
+
if (connectResult.publicKey) {
|
|
60
|
+
const publicKeyStr = connectResult.publicKey.toString();
|
|
61
|
+
triggerEvent("connect", publicKeyStr);
|
|
62
|
+
return publicKeyStr;
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
}
|
|
66
|
+
throw new Error("Failed to connect to Phantom.");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/solana/signMessage.ts
|
|
70
|
+
async function signMessage(message, display) {
|
|
71
|
+
const provider = getProvider();
|
|
72
|
+
if (!provider) {
|
|
73
|
+
throw new Error("Phantom provider not found.");
|
|
74
|
+
}
|
|
75
|
+
if (!provider.isConnected) {
|
|
76
|
+
await connect();
|
|
77
|
+
}
|
|
78
|
+
if (!provider.signMessage) {
|
|
79
|
+
throw new Error("The connected provider does not support signMessage.");
|
|
80
|
+
}
|
|
81
|
+
if (!provider.isConnected) {
|
|
82
|
+
throw new Error("Provider is not connected even after attempting to connect.");
|
|
83
|
+
}
|
|
84
|
+
const result = await provider.signMessage(message, display);
|
|
85
|
+
return {
|
|
86
|
+
signature: result.signature,
|
|
87
|
+
address: result.publicKey.toString()
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/solana/signIn.ts
|
|
92
|
+
async function signIn(signInData) {
|
|
93
|
+
const provider = getProvider();
|
|
94
|
+
if (!provider) {
|
|
95
|
+
throw new Error("Phantom provider not found.");
|
|
96
|
+
}
|
|
97
|
+
if (!provider.signIn) {
|
|
98
|
+
throw new Error("The connected provider does not support signIn.");
|
|
99
|
+
}
|
|
100
|
+
const result = await provider.signIn(signInData);
|
|
101
|
+
return {
|
|
102
|
+
address: result.address.toString(),
|
|
103
|
+
signature: result.signature,
|
|
104
|
+
signedMessage: result.signedMessage
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/solana/utils/transactionToVersionedTransaction.ts
|
|
109
|
+
import { getTransactionEncoder } from "@solana/transactions";
|
|
110
|
+
function transactionToVersionedTransaction(transaction) {
|
|
111
|
+
const serialized = getTransactionEncoder().encode(transaction);
|
|
112
|
+
const fakeVersioned = {
|
|
113
|
+
serialize() {
|
|
114
|
+
return new Uint8Array(serialized);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
return fakeVersioned;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/solana/signAndSendTransaction.ts
|
|
121
|
+
async function signAndSendTransaction(transaction) {
|
|
122
|
+
const provider = getProvider();
|
|
123
|
+
if (!provider) {
|
|
124
|
+
throw new Error("Phantom provider not found.");
|
|
125
|
+
}
|
|
126
|
+
if (!provider.isConnected) {
|
|
127
|
+
await connect();
|
|
128
|
+
}
|
|
129
|
+
if (!provider.signAndSendTransaction) {
|
|
130
|
+
throw new Error("The connected provider does not support signAndSendTransaction.");
|
|
131
|
+
}
|
|
132
|
+
if (!provider.isConnected) {
|
|
133
|
+
throw new Error("Provider is not connected even after attempting to connect.");
|
|
134
|
+
}
|
|
135
|
+
const versionedTransaction = transactionToVersionedTransaction(transaction);
|
|
136
|
+
const result = await provider.signAndSendTransaction(versionedTransaction);
|
|
137
|
+
return {
|
|
138
|
+
signature: result.signature,
|
|
139
|
+
address: result.publicKey
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/solana/disconnect.ts
|
|
144
|
+
async function disconnect() {
|
|
145
|
+
const provider = getProvider();
|
|
146
|
+
if (!provider) {
|
|
147
|
+
throw new Error("Phantom provider not found.");
|
|
148
|
+
}
|
|
149
|
+
await provider.disconnect();
|
|
150
|
+
triggerEvent("disconnect");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/solana/getAccount.ts
|
|
154
|
+
function getAccount() {
|
|
155
|
+
const provider = getProvider();
|
|
156
|
+
if (provider && provider.isConnected && provider.publicKey) {
|
|
157
|
+
return {
|
|
158
|
+
status: "connected",
|
|
159
|
+
address: provider.publicKey.toString()
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
status: "disconnected",
|
|
164
|
+
address: null
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
6
168
|
// src/solana/plugin.ts
|
|
7
169
|
var solana = {
|
|
8
|
-
getProvider
|
|
170
|
+
getProvider,
|
|
171
|
+
connect,
|
|
172
|
+
disconnect,
|
|
173
|
+
getAccount,
|
|
174
|
+
signMessage,
|
|
175
|
+
signIn,
|
|
176
|
+
signAndSendTransaction,
|
|
177
|
+
addEventListener,
|
|
178
|
+
removeEventListener
|
|
9
179
|
};
|
|
10
180
|
function createSolanaPlugin() {
|
|
11
181
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/browser-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,13 +22,20 @@
|
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "rm -rf dist && tsup src/index.ts src/solana/index.ts --format cjs,esm --dts",
|
|
25
|
+
"build:watch": "rm -rf dist && tsup src/index.ts src/solana/index.ts --format cjs,esm --dts --watch",
|
|
25
26
|
"dev": "rm -rf dist && tsup src/index.ts src/solana/index.ts --format cjs,esm --dts --watch",
|
|
26
27
|
"lint": "tsc --noEmit && eslint --cache . --ext .ts,.tsx",
|
|
27
28
|
"test": "jest"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
31
|
+
"@solana/web3.js": "^1.98.2",
|
|
30
32
|
"eslint": "8.53.0",
|
|
31
33
|
"tsup": "^6.7.0",
|
|
32
34
|
"typescript": "^5.0.4"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@solana/compat": "2.1.1",
|
|
38
|
+
"@solana/kit": "^2.1.1",
|
|
39
|
+
"@solana/transactions": "^2.1.1"
|
|
33
40
|
}
|
|
34
41
|
}
|