solana-messenger-sdk 1.5.2 → 1.5.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 +91 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,6 +62,97 @@ const messenger = new SolanaMessenger({
|
|
|
62
62
|
await messenger.init(); // no filesystem access needed
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
+
## Architecture: Keys & Roles
|
|
66
|
+
|
|
67
|
+
Every user has **two separate keypairs**:
|
|
68
|
+
|
|
69
|
+
| Key | Purpose | Who holds it |
|
|
70
|
+
|-----|---------|-------------|
|
|
71
|
+
| **Wallet key (A)** | Signs transactions | User, or custodial service (Privy, Turnkey) |
|
|
72
|
+
| **Encryption key (B)** | Encrypts/decrypts messages | User's device only — never shared |
|
|
73
|
+
|
|
74
|
+
`init()` generates key B, stores it locally (or accepts it via `encryptionKeypair` config), and registers the public part on-chain. Messages are encrypted with B — custodial services that hold A **cannot** read messages.
|
|
75
|
+
|
|
76
|
+
### Who needs what
|
|
77
|
+
|
|
78
|
+
| Role | Wallet key (A) | Encryption key (B) | Calls `init()`? |
|
|
79
|
+
|------|:-:|:-:|:-:|
|
|
80
|
+
| **End user** | ✅ | ✅ | Yes |
|
|
81
|
+
| **Relayer / backend** | ❌ | ❌ | **No** |
|
|
82
|
+
|
|
83
|
+
A **relayer** only forwards pre-signed transactions to the RPC — it doesn't instantiate `SolanaMessenger` or call `init()`. It just needs a Solana RPC connection:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Relayer — no SDK needed, just forward signed tx bytes
|
|
87
|
+
import { Connection } from "@solana/web3.js";
|
|
88
|
+
const conn = new Connection(rpcUrl);
|
|
89
|
+
const sig = await conn.sendRawTransaction(signedTxBytes);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Deployment Patterns
|
|
93
|
+
|
|
94
|
+
#### 1. Client-Side (True E2E Encryption)
|
|
95
|
+
|
|
96
|
+
Users hold their own encryption key B on-device. Server never sees plaintext. Maximum privacy.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
User Device Solana
|
|
100
|
+
├── Wallet key A (or Privy signer) ├── EncryptionRegistry (pubkey B)
|
|
101
|
+
├── Encryption key B (local) ├── Messages (encrypted)
|
|
102
|
+
├── SDK: encrypt → sign → send └── Channels, Servers...
|
|
103
|
+
└── SDK: read → decrypt → display
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### 2. Server-Managed (Slack/Discord Model)
|
|
107
|
+
|
|
108
|
+
Server holds both keys per user. Handles all encryption/decryption, pushes plaintext to clients. Users trust the platform.
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Server (Vercel, etc.) Solana
|
|
112
|
+
├── Per-user wallet key A (Privy) ├── EncryptionRegistry (pubkey B)
|
|
113
|
+
├── Per-user encryption key B (DB) ├── Messages (encrypted)
|
|
114
|
+
├── SDK: encrypt → sign → send └── Channels, Servers...
|
|
115
|
+
└── SDK: read → decrypt → push to client via WS/API
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// First-time user setup
|
|
120
|
+
const kp = SolanaMessenger.generateEncryptionKeypair();
|
|
121
|
+
await db.users.update(userId, {
|
|
122
|
+
encryptionSecret: Buffer.from(kp.secretKey).toString("base64"),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Per-request: create messenger for this user
|
|
126
|
+
const messenger = new SolanaMessenger({
|
|
127
|
+
apiKey: process.env.HELIUS_API_KEY!,
|
|
128
|
+
walletAddress: user.walletAddress,
|
|
129
|
+
signer: async (tx) => await privy.signTransaction(user.id, tx),
|
|
130
|
+
encryptionKeypair: Buffer.from(user.encryptionSecret, "base64"),
|
|
131
|
+
});
|
|
132
|
+
await messenger.init();
|
|
133
|
+
|
|
134
|
+
// Send on behalf of user
|
|
135
|
+
await messenger.send(recipient, "hello from server");
|
|
136
|
+
|
|
137
|
+
// Read, decrypt, push to client
|
|
138
|
+
const messages = await messenger.read({ since: lastSeen });
|
|
139
|
+
ws.send(JSON.stringify(messages)); // plaintext to client
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
> ⚠️ **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.
|
|
143
|
+
|
|
144
|
+
#### 3. Relayer Only (Gasless Transactions)
|
|
145
|
+
|
|
146
|
+
Server just pays gas. Users handle their own encryption client-side. Server never sees keys or plaintext.
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Relayer endpoint — no SDK, no keys
|
|
150
|
+
app.post("/relay", async (req, res) => {
|
|
151
|
+
const sig = await conn.sendRawTransaction(req.body.signedTx);
|
|
152
|
+
res.json({ signature: sig });
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
65
156
|
## API
|
|
66
157
|
|
|
67
158
|
### Direct Messages
|