solana-messenger-sdk 1.5.3 → 1.5.5
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 +99 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,6 +89,105 @@ const conn = new Connection(rpcUrl);
|
|
|
89
89
|
const sig = await conn.sendRawTransaction(signedTxBytes);
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
### Deployment Patterns
|
|
93
|
+
|
|
94
|
+
#### 1. Client-Side with Privy (True E2E Encryption)
|
|
95
|
+
|
|
96
|
+
Users hold their own encryption key B on-device. Server never sees plaintext. Maximum privacy. Privy handles wallet key A — user never manages raw keys.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Browser (Client) Solana
|
|
100
|
+
├── Privy embedded wallet (A) ├── EncryptionRegistry (pubkey B)
|
|
101
|
+
├── Encryption key B (localStorage) ├── Messages (encrypted)
|
|
102
|
+
├── SDK: encrypt → sign → send └── Channels, Servers...
|
|
103
|
+
└── SDK: read → decrypt → display
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { usePrivy, useWallets } from "@privy-io/react-auth";
|
|
108
|
+
import { SolanaMessenger } from "solana-messenger-sdk";
|
|
109
|
+
|
|
110
|
+
// On first login: generate encryption keypair, store in localStorage
|
|
111
|
+
function getOrCreateEncryptionKey(userId: string): Uint8Array {
|
|
112
|
+
const key = `enc_keypair_${userId}`;
|
|
113
|
+
const stored = localStorage.getItem(key);
|
|
114
|
+
if (stored) return new Uint8Array(JSON.parse(stored));
|
|
115
|
+
const kp = SolanaMessenger.generateEncryptionKeypair();
|
|
116
|
+
localStorage.setItem(key, JSON.stringify(Array.from(kp.secretKey)));
|
|
117
|
+
return kp.secretKey;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Create messenger with Privy signer + local encryption key
|
|
121
|
+
const { wallets } = useWallets();
|
|
122
|
+
const solWallet = wallets.find(w => w.walletClientType === "privy" && w.chainType === "solana");
|
|
123
|
+
|
|
124
|
+
const messenger = new SolanaMessenger({
|
|
125
|
+
apiKey: HELIUS_API_KEY,
|
|
126
|
+
walletAddress: solWallet.address,
|
|
127
|
+
signer: async (tx) => {
|
|
128
|
+
// Sign with Privy embedded wallet
|
|
129
|
+
return await solWallet.signTransaction(tx);
|
|
130
|
+
},
|
|
131
|
+
encryptionKeypair: getOrCreateEncryptionKey(user.id),
|
|
132
|
+
});
|
|
133
|
+
await messenger.init();
|
|
134
|
+
|
|
135
|
+
// Now send/read — Privy signs txs, encryption stays client-side
|
|
136
|
+
await messenger.send(recipient, "truly private message");
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> ✅ **Best privacy:** Privy holds wallet key A (signs txs) but never sees encryption key B. Your server never sees plaintext. Only the user's browser can decrypt messages.
|
|
140
|
+
|
|
141
|
+
#### 2. Server-Managed (Slack/Discord Model)
|
|
142
|
+
|
|
143
|
+
Server holds both keys per user. Handles all encryption/decryption, pushes plaintext to clients. Users trust the platform.
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Server (Vercel, etc.) Solana
|
|
147
|
+
├── Per-user wallet key A (Privy) ├── EncryptionRegistry (pubkey B)
|
|
148
|
+
├── Per-user encryption key B (DB) ├── Messages (encrypted)
|
|
149
|
+
├── SDK: encrypt → sign → send └── Channels, Servers...
|
|
150
|
+
└── SDK: read → decrypt → push to client via WS/API
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// First-time user setup
|
|
155
|
+
const kp = SolanaMessenger.generateEncryptionKeypair();
|
|
156
|
+
await db.users.update(userId, {
|
|
157
|
+
encryptionSecret: Buffer.from(kp.secretKey).toString("base64"),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Per-request: create messenger for this user
|
|
161
|
+
const messenger = new SolanaMessenger({
|
|
162
|
+
apiKey: process.env.HELIUS_API_KEY!,
|
|
163
|
+
walletAddress: user.walletAddress,
|
|
164
|
+
signer: async (tx) => await privy.signTransaction(user.id, tx),
|
|
165
|
+
encryptionKeypair: Buffer.from(user.encryptionSecret, "base64"),
|
|
166
|
+
});
|
|
167
|
+
await messenger.init();
|
|
168
|
+
|
|
169
|
+
// Send on behalf of user
|
|
170
|
+
await messenger.send(recipient, "hello from server");
|
|
171
|
+
|
|
172
|
+
// Read, decrypt, push to client
|
|
173
|
+
const messages = await messenger.read({ since: lastSeen });
|
|
174
|
+
ws.send(JSON.stringify(messages)); // plaintext to client
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
> ⚠️ **Trust tradeoff:** In this model, the server can read all messages. E2E encryption protects data on-chain and in transit, but not from the platform operator. This is the same model as Slack, Discord, and most chat platforms.
|
|
178
|
+
|
|
179
|
+
#### 3. Relayer Only (Gasless Transactions)
|
|
180
|
+
|
|
181
|
+
Server just pays gas. Users handle their own encryption client-side. Server never sees keys or plaintext.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Relayer endpoint — no SDK, no keys
|
|
185
|
+
app.post("/relay", async (req, res) => {
|
|
186
|
+
const sig = await conn.sendRawTransaction(req.body.signedTx);
|
|
187
|
+
res.json({ signature: sig });
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
92
191
|
## API
|
|
93
192
|
|
|
94
193
|
### Direct Messages
|