@rockerone/xprnkit 0.4.0 → 0.4.2
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 +571 -834
- package/build/components/identity/xprn-identity.js +1 -1
- package/build/global.css +4 -4
- package/build/interfaces/identity-proof.d.ts +2 -0
- package/build/providers/xprnkit-provider.js +2 -2
- package/build/services/identity-proof/authenticate-identity-proof.d.ts +1 -1
- package/build/services/identity-proof/authenticate-identity-proof.js +4 -1
- package/build/services/identity-proof/verify-identity-proof.d.ts +1 -1
- package/build/services/identity-proof/verify-identity-proof.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,86 +1,27 @@
|
|
|
1
|
-
# xprnkit
|
|
1
|
+
# @rockerone/xprnkit
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
bun install
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
# XPRNKit:
|
|
3
|
+
> **⚠️ Warning:** Version 0.4.0 introduces breaking changes. Make sure to save your project before migrate.
|
|
10
4
|
|
|
11
5
|
## Accelerating dApp Development for XPRNetwork
|
|
12
6
|
|
|
13
7
|
XPRNKit is a React-based library designed to streamline decentralized application (dApp) development and prototyping on the XPRNetwork blockchain. It offers a comprehensive set of tools, components, and utilities that enable developers to rapidly build, deploy, and test dApps with minimal setup. By abstracting away much of the underlying complexity of blockchain interactions, XPRNKit empowers developers to focus on core functionality and user experience.
|
|
14
8
|
|
|
15
|
-
Whether you're creating smart contracts, integrating wallets, or handling token transactions, XPRNKit simplifies common tasks and accelerates the development process. It
|
|
9
|
+
Whether you're creating smart contracts, integrating wallets, or handling token transactions, XPRNKit simplifies common tasks and accelerates the development process. It's perfect for both experienced blockchain developers looking to prototype quickly and newcomers who want to get up and running with XPRNetwork faster.
|
|
16
10
|
|
|
17
11
|
## Key Features
|
|
18
12
|
|
|
19
13
|
- **Pre-built Components**: Ready-to-use UI components for common dApp functionality like wallet connections, token balances, and transaction history.
|
|
20
14
|
- **Blockchain Integration**: Simplified access to XPRNetwork's blockchain features, reducing the need for extensive configuration.
|
|
21
|
-
- **Developer-Friendly Hook**: A simple unique hook to access objects and
|
|
22
|
-
- **
|
|
15
|
+
- **Developer-Friendly Hook**: A simple unique hook to access objects and methods, maximizing flexibility.
|
|
16
|
+
- **Identity Proof**: Built-in wallet signature verification for secure user authentication with JWT token support.
|
|
17
|
+
- **Multi-Account Support**: Connect and switch between multiple wallet accounts, powered by Proton Web SDK session storage.
|
|
18
|
+
- **Token Swap Interface**: Complete swap UI with market provider abstraction and customizable layouts.
|
|
23
19
|
|
|
24
20
|
XPRNKit is the ideal toolkit for developers who want to build and deploy secure, scalable, and user-friendly dApps on XPRNetwork with greater efficiency.
|
|
25
21
|
|
|
26
22
|
---
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Version 0.3.1 introduces significant performance optimizations to the `XPRNProvider` multi-session management system. The internal state architecture has been refactored to use refs instead of useState for session storage, dramatically reducing unnecessary re-renders.
|
|
31
|
-
|
|
32
|
-
### Performance Gains
|
|
33
|
-
|
|
34
|
-
| Scenario | Before | After | Improvement |
|
|
35
|
-
|----------|--------|-------|-------------|
|
|
36
|
-
| **Single-session usage** | baseline | optimized | **~1.5x faster** |
|
|
37
|
-
| **Multi-session (2-3 wallets)** | baseline | optimized | **~3-4x faster** |
|
|
38
|
-
| **Heavy multi-session (4+ wallets)** | baseline | optimized | **~5x+ faster** |
|
|
39
|
-
|
|
40
|
-
### Re-render Reduction (3-wallet scenario)
|
|
41
|
-
|
|
42
|
-
| Operation | Before | After | Reduction |
|
|
43
|
-
|-----------|--------|-------|-----------|
|
|
44
|
-
| Connect wallet 1 | 3 re-renders | 2 re-renders | 33% |
|
|
45
|
-
| Connect wallet 2 | 2 re-renders | 0 re-renders | 100% |
|
|
46
|
-
| Connect wallet 3 | 2 re-renders | 0 re-renders | 100% |
|
|
47
|
-
| Profile fetch (active) | 1 re-render | 1 re-render | 0% |
|
|
48
|
-
| Profile fetch (non-active) | 1 re-render | 0 re-renders | 100% |
|
|
49
|
-
| Authenticate (non-active) | 1 re-render | 0 re-renders | 100% |
|
|
50
|
-
| **Total (3-wallet setup)** | **13 re-renders** | **4 re-renders** | **~70%** |
|
|
51
|
-
|
|
52
|
-
### Callback Stability
|
|
53
|
-
|
|
54
|
-
All session management callbacks are now stable references:
|
|
55
|
-
|
|
56
|
-
| Callback | Dependencies | Stable? |
|
|
57
|
-
|----------|--------------|---------|
|
|
58
|
-
| `listSessions` | `[]` | ✅ Never recreated |
|
|
59
|
-
| `getSessionById` | `[]` | ✅ Never recreated |
|
|
60
|
-
| `getSessionByActor` | `[]` | ✅ Never recreated |
|
|
61
|
-
| `getAllProfiles` | `[]` | ✅ Never recreated |
|
|
62
|
-
| `getActiveSession` | `[]` | ✅ Never recreated |
|
|
63
|
-
| `setActiveSession` | `[forceUpdate]` | ✅ Stable |
|
|
64
|
-
| `switchSession` | `[setActiveSession]` | ✅ Stable |
|
|
65
|
-
| `removeSession` | `[config, forceUpdate]` | ✅ Stable |
|
|
66
|
-
| `disconnect` | `[removeSession]` | ✅ Stable |
|
|
67
|
-
| `authenticate` | `[config, forceUpdate]` | ✅ Stable |
|
|
68
|
-
| `connect` | `[config, forceUpdate]` | ✅ Stable |
|
|
69
|
-
|
|
70
|
-
### Key Optimizations
|
|
71
|
-
|
|
72
|
-
- **Ref-based session storage**: Sessions Map is now stored in a ref, eliminating Map recreation on every update
|
|
73
|
-
- **Selective re-renders**: Only triggers re-renders when the **active session** data changes
|
|
74
|
-
- **Zero re-renders for non-active operations**: Adding/updating non-active sessions doesn't cause re-renders
|
|
75
|
-
- **Stable callback references**: Consumer components using these callbacks won't re-render due to callback identity changes
|
|
76
|
-
|
|
77
|
-
### Backward Compatibility
|
|
78
|
-
|
|
79
|
-
These optimizations are fully backward compatible. All existing code using `useXPRN()` continues to work without changes.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
# XPRNProvider and useXPRN Documentation
|
|
24
|
+
# XPRNProvider and useXPRN
|
|
84
25
|
|
|
85
26
|
## XPRNProvider
|
|
86
27
|
|
|
@@ -107,10 +48,9 @@ type XPRProviderConfig = {
|
|
|
107
48
|
dAppName: string;
|
|
108
49
|
requesterAccount: string;
|
|
109
50
|
requesterLogo?: string;
|
|
110
|
-
authenticationUrl?: string;
|
|
111
|
-
enforceAuthentication?: boolean;
|
|
112
51
|
apiMode: "testnet" | "mainnet";
|
|
113
52
|
restoreSession?: boolean;
|
|
53
|
+
identityProof?: XPRNKitIdentityProofConfig;
|
|
114
54
|
};
|
|
115
55
|
```
|
|
116
56
|
|
|
@@ -119,15 +59,14 @@ type XPRProviderConfig = {
|
|
|
119
59
|
- `dAppName`: Your dApp's display name.
|
|
120
60
|
- `requesterAccount`: Your dApp's account name.
|
|
121
61
|
- `requesterLogo`: Optional logo URL for your dApp.
|
|
122
|
-
- `
|
|
123
|
-
- `enforceAuthentication`: If true, automatically authenticates users on connection.
|
|
124
|
-
- `apiMode`: Either "testnet" or "mainnet" for different network environments.
|
|
62
|
+
- `apiMode`: Either `"testnet"` or `"mainnet"` for different network environments.
|
|
125
63
|
- `restoreSession`: If true, restores the last active session on page refresh.
|
|
64
|
+
- `identityProof`: Optional identity proof configuration (see [Identity Proof](#identity-proof) section).
|
|
126
65
|
|
|
127
66
|
### Usage
|
|
128
67
|
|
|
129
68
|
```jsx
|
|
130
|
-
import {XPRNProvider} from
|
|
69
|
+
import { XPRNProvider } from '@rockerone/xprnkit';
|
|
131
70
|
|
|
132
71
|
const config = {
|
|
133
72
|
chainId: "your-chain-id",
|
|
@@ -151,19 +90,18 @@ The `useXPRN` hook provides access to the XPRN context within your React compone
|
|
|
151
90
|
### Usage
|
|
152
91
|
|
|
153
92
|
```jsx
|
|
154
|
-
import {useXPRN} from
|
|
93
|
+
import { useXPRN } from '@rockerone/xprnkit';
|
|
155
94
|
|
|
156
95
|
function YourComponent() {
|
|
157
96
|
const {
|
|
158
97
|
session,
|
|
159
98
|
profile,
|
|
99
|
+
identityProof,
|
|
100
|
+
identityProofStatus,
|
|
160
101
|
connect,
|
|
161
102
|
disconnect,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
listSessions,
|
|
165
|
-
setActiveSession,
|
|
166
|
-
getActiveSession,
|
|
103
|
+
pushTransaction,
|
|
104
|
+
switchToSession,
|
|
167
105
|
} = useXPRN();
|
|
168
106
|
|
|
169
107
|
// Use the context values and functions
|
|
@@ -174,688 +112,563 @@ function YourComponent() {
|
|
|
174
112
|
|
|
175
113
|
The `useXPRN` hook returns an object with the following properties:
|
|
176
114
|
|
|
177
|
-
####
|
|
115
|
+
#### State
|
|
178
116
|
|
|
179
|
-
- `
|
|
180
|
-
- `
|
|
181
|
-
- `
|
|
182
|
-
- `
|
|
183
|
-
- `
|
|
184
|
-
- `
|
|
185
|
-
- `disconnect`: Function to disconnect a session (active or specific by actor).
|
|
186
|
-
- `authenticate`: Function to authenticate the user using the authentication URL (active session or specific by actor).
|
|
187
|
-
- `addTransactionError`: Function to add a transaction error to the stack.
|
|
188
|
-
|
|
189
|
-
#### Multi-Session Management Methods
|
|
190
|
-
|
|
191
|
-
- `getActiveSession`: Returns the current active session object or null.
|
|
192
|
-
- `listSessions`: Returns an array of all connected sessions.
|
|
193
|
-
- `setActiveSession`: Switch the active session by actor name.
|
|
194
|
-
- `switchSession`: Alias for setActiveSession.
|
|
195
|
-
- `removeSession`: Remove a specific session by actor name.
|
|
196
|
-
- `getAllProfiles`: Returns an array of all profiles from all connected sessions.
|
|
197
|
-
- `getSessionById`: Get a specific session by actor name.
|
|
198
|
-
- `getSessionByActor`: Get a specific session by actor name (same as getSessionById).
|
|
199
|
-
|
|
200
|
-
### Key Functions
|
|
201
|
-
|
|
202
|
-
#### connect
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
connect(
|
|
206
|
-
restore?: boolean,
|
|
207
|
-
silent?: boolean,
|
|
208
|
-
onSession?: (session: LinkSession) => void,
|
|
209
|
-
onProfile?: (profile: XPRNProfile) => void
|
|
210
|
-
) => void
|
|
211
|
-
```
|
|
117
|
+
- `config`: `XPRProviderConfig | null` - Current provider configuration.
|
|
118
|
+
- `session`: `LinkSession | null` - Current active session object.
|
|
119
|
+
- `link`: `ProtonWebLink | Link | null` - Proton link object for the active session.
|
|
120
|
+
- `profile`: `XPRNKitProfile | null` - Profile data for the active session.
|
|
121
|
+
- `identityProof`: `XPRNKitIdentityProof | null` - Identity proof for the active session (when identity proof is configured).
|
|
122
|
+
- `identityProofStatus`: `XPRNKitIdentityProofStatus` - Current status of the identity proof process (`"idle"` | `"signing"` | `"verifying"` | `"validating"` | `"success"` | `"expired"` | `"error"`).
|
|
212
123
|
|
|
213
|
-
|
|
124
|
+
#### Methods
|
|
214
125
|
|
|
215
|
-
|
|
126
|
+
- `connect(restore?: boolean)`: Initiates a connection to the WebAuth wallet. Pass `true` to restore a previous session silently.
|
|
127
|
+
- `disconnect()`: Disconnects the current active session.
|
|
128
|
+
- `pushTransaction(actions: any[])`: Pushes a transaction with the given actions using the active session.
|
|
129
|
+
- `switchToSession(actor: string, permission: string)`: Switches to a different stored session by restoring it from the Proton Web SDK storage.
|
|
216
130
|
|
|
217
|
-
|
|
218
|
-
disconnect(actor?: string) => void
|
|
219
|
-
```
|
|
131
|
+
### Basic Example
|
|
220
132
|
|
|
221
|
-
|
|
133
|
+
```jsx
|
|
134
|
+
import { useXPRN } from '@rockerone/xprnkit';
|
|
222
135
|
|
|
223
|
-
|
|
136
|
+
function MyComponent() {
|
|
137
|
+
const { session, profile, connect, disconnect } = useXPRN();
|
|
224
138
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
) =>
|
|
139
|
+
return (
|
|
140
|
+
<div>
|
|
141
|
+
{session ? (
|
|
142
|
+
<div>
|
|
143
|
+
<p>Logged in as: {profile?.displayName}</p>
|
|
144
|
+
<button onClick={() => disconnect()}>Logout</button>
|
|
145
|
+
</div>
|
|
146
|
+
) : (
|
|
147
|
+
<button onClick={() => connect()}>Connect</button>
|
|
148
|
+
)}
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
231
152
|
```
|
|
232
153
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
### Multi-Session Management Methods
|
|
154
|
+
### Transaction Example
|
|
236
155
|
|
|
237
|
-
|
|
156
|
+
```jsx
|
|
157
|
+
import { useXPRN } from '@rockerone/xprnkit';
|
|
158
|
+
|
|
159
|
+
function TransferButton() {
|
|
160
|
+
const { session, pushTransaction } = useXPRN();
|
|
161
|
+
|
|
162
|
+
const handleTransfer = async () => {
|
|
163
|
+
if (!session) return;
|
|
164
|
+
|
|
165
|
+
await pushTransaction([
|
|
166
|
+
{
|
|
167
|
+
account: "eosio.token",
|
|
168
|
+
name: "transfer",
|
|
169
|
+
authorization: [session.auth],
|
|
170
|
+
data: {
|
|
171
|
+
from: session.auth.actor.toString(),
|
|
172
|
+
to: "recipient",
|
|
173
|
+
quantity: "1.0000 XPR",
|
|
174
|
+
memo: "Hello!",
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
]);
|
|
178
|
+
};
|
|
238
179
|
|
|
239
|
-
|
|
240
|
-
|
|
180
|
+
return <button onClick={handleTransfer}>Send 1 XPR</button>;
|
|
181
|
+
}
|
|
241
182
|
```
|
|
242
183
|
|
|
243
|
-
|
|
184
|
+
---
|
|
244
185
|
|
|
245
|
-
|
|
186
|
+
# Identity Proof
|
|
246
187
|
|
|
247
|
-
|
|
248
|
-
listSessions(): XPRNSession[]
|
|
249
|
-
```
|
|
188
|
+
Identity Proof allows you to verify that a user owns a specific wallet by having them sign a message. This is useful for authentication flows where you need to confirm a user's identity on your backend.
|
|
250
189
|
|
|
251
|
-
|
|
190
|
+
## Configuration
|
|
252
191
|
|
|
253
|
-
|
|
192
|
+
Add the `identityProof` configuration to your `XPRProvider`:
|
|
254
193
|
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
|
|
194
|
+
```tsx
|
|
195
|
+
const config = {
|
|
196
|
+
chainId: "your-chain-id",
|
|
197
|
+
endpoints: ["https://your-endpoint.com"],
|
|
198
|
+
dAppName: "MyDApp",
|
|
199
|
+
requesterAccount: "your-requester-account",
|
|
200
|
+
apiMode: "mainnet",
|
|
201
|
+
identityProof: {
|
|
202
|
+
required: true, // When true, identity proof is automatically triggered on connect
|
|
203
|
+
createUrl: "/api/auth/authorize", // Backend endpoint to verify signatures and return a JWT
|
|
204
|
+
validationUrl: "/api/auth/validate", // Backend endpoint to validate existing tokens (optional)
|
|
205
|
+
validationBuffer: 300, // Seconds before expiry to trigger revalidation (optional)
|
|
206
|
+
headers: {}, // Custom headers to send with identity proof requests (optional)
|
|
207
|
+
timeout: 10000, // Request timeout in milliseconds (optional)
|
|
208
|
+
},
|
|
209
|
+
};
|
|
258
210
|
```
|
|
259
211
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
#### removeSession
|
|
212
|
+
### XPRNKitIdentityProofConfig
|
|
263
213
|
|
|
264
214
|
```typescript
|
|
265
|
-
|
|
215
|
+
type XPRNKitIdentityProofConfig = {
|
|
216
|
+
required: boolean;
|
|
217
|
+
createUrl: string;
|
|
218
|
+
validationUrl?: string;
|
|
219
|
+
validationBuffer?: number;
|
|
220
|
+
headers?: Record<string, string>;
|
|
221
|
+
timeout?: number;
|
|
222
|
+
};
|
|
266
223
|
```
|
|
267
224
|
|
|
268
|
-
|
|
225
|
+
## How It Works
|
|
269
226
|
|
|
270
|
-
|
|
227
|
+
1. When `identityProof.required` is `true`, the provider automatically triggers the identity proof flow on wallet connect.
|
|
228
|
+
2. The provider first checks localStorage for an existing identity proof and validates it via the `validationUrl` (if configured).
|
|
229
|
+
3. If no valid proof exists, the user is prompted to sign a message in their wallet.
|
|
230
|
+
4. The signed message is sent to the `createUrl` backend endpoint for verification.
|
|
231
|
+
5. The backend returns a JWT token which is stored in localStorage and made available via `useXPRN().identityProof`.
|
|
271
232
|
|
|
272
|
-
|
|
273
|
-
getAllProfiles(): XPRNProfile[]
|
|
274
|
-
```
|
|
233
|
+
## Backend Endpoints
|
|
275
234
|
|
|
276
|
-
|
|
235
|
+
### 1. Authorization Endpoint (`createUrl`)
|
|
277
236
|
|
|
278
|
-
|
|
237
|
+
Verifies the wallet signature and returns a JWT token:
|
|
279
238
|
|
|
280
239
|
```typescript
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
240
|
+
// Expected request body
|
|
241
|
+
{
|
|
242
|
+
signer: {
|
|
243
|
+
actor: string;
|
|
244
|
+
permission: string;
|
|
245
|
+
};
|
|
246
|
+
transaction: any;
|
|
247
|
+
signatures: string[];
|
|
248
|
+
chainId: string;
|
|
249
|
+
}
|
|
290
250
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
251
|
+
// Response on success
|
|
252
|
+
{
|
|
253
|
+
success: true,
|
|
254
|
+
validated: true,
|
|
255
|
+
actor: string,
|
|
256
|
+
permission: string,
|
|
257
|
+
token: string, // JWT token
|
|
258
|
+
timestamp: string,
|
|
259
|
+
}
|
|
297
260
|
```
|
|
298
261
|
|
|
299
|
-
###
|
|
300
|
-
|
|
301
|
-
```typescript
|
|
302
|
-
type XPRNProfile = {
|
|
303
|
-
displayName: string;
|
|
304
|
-
avatar?: string;
|
|
305
|
-
authentication?: XPRNAuthentication;
|
|
306
|
-
isKyc: boolean;
|
|
307
|
-
};
|
|
308
|
-
```
|
|
262
|
+
### 2. Validation Endpoint (`validationUrl`)
|
|
309
263
|
|
|
310
|
-
|
|
264
|
+
Validates an existing JWT token:
|
|
311
265
|
|
|
312
266
|
```typescript
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
267
|
+
// Request: Authorization header with "Bearer <token>" or body { token: string }
|
|
268
|
+
|
|
269
|
+
// Response
|
|
270
|
+
{
|
|
271
|
+
valid: boolean,
|
|
272
|
+
actor?: string,
|
|
273
|
+
expiresAt?: string,
|
|
274
|
+
error?: string,
|
|
275
|
+
}
|
|
320
276
|
```
|
|
321
277
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
## Multi-Session Support
|
|
325
|
-
|
|
326
|
-
XPRNKit now supports managing multiple wallet sessions simultaneously. You can connect multiple wallets, switch between them, and manage each session independently.
|
|
278
|
+
## Identity Proof Gate Component
|
|
327
279
|
|
|
328
|
-
|
|
280
|
+
Use `XPRNIdentityProofGate` to conditionally render content based on identity proof status:
|
|
329
281
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
- **Auto-Switch**: When a new wallet is connected, it automatically becomes the active session.
|
|
333
|
-
- **Persistence**: Only the active session is persisted and restored on page refresh (when `restoreSession: true` in config).
|
|
334
|
-
|
|
335
|
-
### Multi-Session Usage Examples
|
|
336
|
-
|
|
337
|
-
#### Connecting Multiple Wallets
|
|
338
|
-
|
|
339
|
-
```jsx
|
|
340
|
-
import {useXPRN} from "xprnkit";
|
|
341
|
-
|
|
342
|
-
function MultiWalletComponent() {
|
|
343
|
-
const {connect, listSessions, session} = useXPRN();
|
|
344
|
-
|
|
345
|
-
const handleConnectWallet = async () => {
|
|
346
|
-
await connect();
|
|
347
|
-
// Newly connected wallet is now the active session
|
|
348
|
-
};
|
|
282
|
+
```tsx
|
|
283
|
+
import { XPRNIdentityProofGate } from '@rockerone/xprnkit';
|
|
349
284
|
|
|
285
|
+
function ProtectedContent() {
|
|
350
286
|
return (
|
|
351
|
-
<
|
|
352
|
-
|
|
353
|
-
<p>
|
|
354
|
-
<p>
|
|
355
|
-
|
|
287
|
+
<XPRNIdentityProofGate
|
|
288
|
+
fallback={<p>Please verify your identity to access this content.</p>}
|
|
289
|
+
loading={<p>Verifying identity...</p>}
|
|
290
|
+
error={<p>Verification failed. Please try again.</p>}
|
|
291
|
+
notConnected={<p>Please connect your wallet first.</p>}
|
|
292
|
+
>
|
|
293
|
+
<p>This content is only visible after identity verification.</p>
|
|
294
|
+
</XPRNIdentityProofGate>
|
|
356
295
|
);
|
|
357
296
|
}
|
|
358
297
|
```
|
|
359
298
|
|
|
360
|
-
|
|
299
|
+
### Props
|
|
300
|
+
|
|
301
|
+
| Prop | Type | Description |
|
|
302
|
+
| -------------- | ----------------- | ------------------------------------------------------------------------ |
|
|
303
|
+
| `children` | `React.ReactNode` | Content to render when identity proof is obtained. |
|
|
304
|
+
| `fallback` | `React.ReactNode` | Content to render when identity proof is not obtained (optional). |
|
|
305
|
+
| `loading` | `React.ReactNode` | Content to render while identity proof is in progress (optional). |
|
|
306
|
+
| `error` | `React.ReactNode` | Content to render when identity proof failed (optional, falls back to `fallback`). |
|
|
307
|
+
| `notConnected` | `React.ReactNode` | Content to render when no session is connected (optional, falls back to `fallback`). |
|
|
361
308
|
|
|
362
|
-
|
|
363
|
-
import {useXPRN} from "xprnkit";
|
|
309
|
+
## useIdentityProofGate Hook
|
|
364
310
|
|
|
365
|
-
|
|
366
|
-
const {listSessions, getActiveSession, setActiveSession} = useXPRN();
|
|
311
|
+
Hook version of the gate component for programmatic access:
|
|
367
312
|
|
|
368
|
-
|
|
369
|
-
|
|
313
|
+
```tsx
|
|
314
|
+
import { useIdentityProofGate } from '@rockerone/xprnkit';
|
|
370
315
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
316
|
+
function MyComponent() {
|
|
317
|
+
const {
|
|
318
|
+
isGateActive,
|
|
319
|
+
isConnected,
|
|
320
|
+
isInProgress,
|
|
321
|
+
hasError,
|
|
322
|
+
isVerified,
|
|
323
|
+
shouldRenderChildren,
|
|
324
|
+
needsIdentityProof,
|
|
325
|
+
identityProofStatus,
|
|
326
|
+
} = useIdentityProofGate();
|
|
327
|
+
|
|
328
|
+
if (!shouldRenderChildren) {
|
|
329
|
+
return <p>Verification required</p>;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return <p>Verified content</p>;
|
|
387
333
|
}
|
|
388
334
|
```
|
|
389
335
|
|
|
390
|
-
|
|
336
|
+
## Session Storage
|
|
391
337
|
|
|
392
|
-
|
|
393
|
-
import {useXPRN} from "xprnkit";
|
|
338
|
+
Identity proof tokens are automatically stored in localStorage and restored on session recovery. The token is validated silently when a session is restored, and if invalid, the full authentication flow is triggered again (when `required` is enabled).
|
|
394
339
|
|
|
395
|
-
|
|
396
|
-
const {listSessions, getActiveSession, removeSession, getAllProfiles} =
|
|
397
|
-
useXPRN();
|
|
340
|
+
---
|
|
398
341
|
|
|
399
|
-
|
|
400
|
-
await removeSession(actor);
|
|
401
|
-
};
|
|
342
|
+
# Multi-Account Support
|
|
402
343
|
|
|
403
|
-
|
|
404
|
-
<div>
|
|
405
|
-
<h3>Session Manager</h3>
|
|
406
|
-
{listSessions().map(session => (
|
|
407
|
-
<div key={session.actor}>
|
|
408
|
-
<img
|
|
409
|
-
src={session.profile?.avatar}
|
|
410
|
-
alt={session.profile?.displayName}
|
|
411
|
-
/>
|
|
412
|
-
<span>{session.profile?.displayName}</span>
|
|
413
|
-
<span>{session.actor}</span>
|
|
414
|
-
<button onClick={() => handleRemoveSession(session.actor)}>
|
|
415
|
-
Remove
|
|
416
|
-
</button>
|
|
417
|
-
</div>
|
|
418
|
-
))}
|
|
419
|
-
</div>
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
```
|
|
344
|
+
XPRNKit supports connecting multiple wallet accounts. Session persistence and restoration is handled by the Proton Web SDK storage layer, while profile data is persisted in localStorage by XPRNKit.
|
|
423
345
|
|
|
424
|
-
|
|
346
|
+
### How It Works
|
|
425
347
|
|
|
426
|
-
|
|
427
|
-
|
|
348
|
+
- When a user connects a wallet, the session is stored by the Proton Web SDK and the profile is saved in localStorage.
|
|
349
|
+
- The provider maintains one **active session** at a time. The `session`, `link`, `profile`, and `identityProof` properties from `useXPRN()` always return data from the active session.
|
|
350
|
+
- Use `switchToSession(actor, permission)` to switch to a different stored account. This restores the session from the SDK storage.
|
|
351
|
+
- Use the `XPRNAccountList` component to provide a UI for users to switch, add, or remove accounts.
|
|
428
352
|
|
|
429
|
-
|
|
430
|
-
const {authenticate, listSessions} = useXPRN();
|
|
353
|
+
### Switching Accounts Programmatically
|
|
431
354
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
actor // Authenticate specific session
|
|
441
|
-
);
|
|
355
|
+
```tsx
|
|
356
|
+
import { useXPRN } from '@rockerone/xprnkit';
|
|
357
|
+
|
|
358
|
+
function AccountSwitcher() {
|
|
359
|
+
const { session, switchToSession } = useXPRN();
|
|
360
|
+
|
|
361
|
+
const handleSwitch = async () => {
|
|
362
|
+
await switchToSession("otheraccount", "active");
|
|
442
363
|
};
|
|
443
364
|
|
|
444
365
|
return (
|
|
445
366
|
<div>
|
|
446
|
-
{
|
|
447
|
-
|
|
448
|
-
<span>{session.actor}</span>
|
|
449
|
-
<span>
|
|
450
|
-
{session.authentication ? "✓ Authenticated" : "✗ Not Authenticated"}
|
|
451
|
-
</span>
|
|
452
|
-
{!session.authentication && (
|
|
453
|
-
<button onClick={() => handleAuthenticateSession(session.actor)}>
|
|
454
|
-
Authenticate
|
|
455
|
-
</button>
|
|
456
|
-
)}
|
|
457
|
-
</div>
|
|
458
|
-
))}
|
|
367
|
+
<p>Current: {session?.auth.actor.toString()}</p>
|
|
368
|
+
<button onClick={handleSwitch}>Switch to otheraccount</button>
|
|
459
369
|
</div>
|
|
460
370
|
);
|
|
461
371
|
}
|
|
462
372
|
```
|
|
463
373
|
|
|
464
|
-
|
|
374
|
+
---
|
|
465
375
|
|
|
466
|
-
|
|
467
|
-
import {useXPRN} from "xprnkit";
|
|
376
|
+
# Components
|
|
468
377
|
|
|
469
|
-
|
|
470
|
-
const {disconnect, listSessions, getActiveSession} = useXPRN();
|
|
378
|
+
## XPRNConnectButton
|
|
471
379
|
|
|
472
|
-
|
|
473
|
-
// If actor is provided, disconnect that session
|
|
474
|
-
// Otherwise, disconnect active session
|
|
475
|
-
await disconnect(actor);
|
|
476
|
-
};
|
|
380
|
+
A customizable button for connecting to and disconnecting from a wallet session.
|
|
477
381
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
</button>
|
|
483
|
-
|
|
484
|
-
{listSessions().map(session => (
|
|
485
|
-
<div key={session.actor}>
|
|
486
|
-
<span>{session.actor}</span>
|
|
487
|
-
<button onClick={() => handleDisconnect(session.actor)}>
|
|
488
|
-
Disconnect
|
|
489
|
-
</button>
|
|
490
|
-
</div>
|
|
491
|
-
))}
|
|
492
|
-
</div>
|
|
493
|
-
);
|
|
494
|
-
}
|
|
382
|
+
### Import
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
import { XPRNConnectButton } from '@rockerone/xprnkit';
|
|
495
386
|
```
|
|
496
387
|
|
|
497
|
-
###
|
|
388
|
+
### Props
|
|
389
|
+
|
|
390
|
+
| Prop | Type | Description |
|
|
391
|
+
| ----------------- | ----------------------------------------------------- | -------------------------------------------------------- |
|
|
392
|
+
| `className` | `string` | Additional CSS classes to apply to the button. |
|
|
393
|
+
| `variant` | `string` | Button variant (style). |
|
|
394
|
+
| `size` | `string` | Button size. |
|
|
395
|
+
| `asChild` | `boolean` | If true, renders the component as a child component. |
|
|
396
|
+
| `children` | `React.ReactNode` | Custom content for the button when not connected. |
|
|
397
|
+
| `onSession` | `(session: LinkSession, link: ProtonWebLink \| Link) => void` | Called when session is established. |
|
|
398
|
+
| `onProfile` | `(profile: XPRNKitProfile) => void` | Called when profile is fetched. |
|
|
399
|
+
| `onIdentityProof` | `(proof: XPRNKitIdentityProof) => void` | Called when identity proof is obtained. |
|
|
400
|
+
| `...props` | `React.ButtonHTMLAttributes<HTMLButtonElement>` | Any other props accepted by HTML button element. |
|
|
498
401
|
|
|
499
|
-
|
|
402
|
+
### Usage
|
|
500
403
|
|
|
501
404
|
```jsx
|
|
502
|
-
|
|
503
|
-
function ExistingComponent() {
|
|
504
|
-
const {session, profile, connect, disconnect} = useXPRN();
|
|
405
|
+
import { XPRNConnectButton } from '@rockerone/xprnkit';
|
|
505
406
|
|
|
506
|
-
|
|
407
|
+
function MyComponent() {
|
|
507
408
|
return (
|
|
508
|
-
<
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
<button onClick={() => connect()}>Connect</button>
|
|
516
|
-
)}
|
|
517
|
-
</div>
|
|
409
|
+
<XPRNConnectButton
|
|
410
|
+
className="custom-class"
|
|
411
|
+
onSession={(session, link) => console.log("Connected:", session.auth.actor.toString())}
|
|
412
|
+
onIdentityProof={(proof) => console.log("Identity verified:", proof.auth.actor)}
|
|
413
|
+
>
|
|
414
|
+
Connect Wallet
|
|
415
|
+
</XPRNConnectButton>
|
|
518
416
|
);
|
|
519
417
|
}
|
|
520
418
|
```
|
|
521
419
|
|
|
522
|
-
|
|
420
|
+
### Behavior
|
|
523
421
|
|
|
524
|
-
|
|
422
|
+
- When there's no active session, the button displays the provided `children` content and triggers the `connect()` function when clicked.
|
|
423
|
+
- When there's an active session, the button displays "Log out (actor)" and triggers the `disconnect()` function when clicked.
|
|
525
424
|
|
|
526
|
-
|
|
425
|
+
---
|
|
527
426
|
|
|
528
|
-
|
|
529
|
-
- ✅ **Wallet Connection** = Handled by XPRNKit (via Proton Web SDK)
|
|
530
|
-
- ❌ **Authentication State** = Your responsibility (localStorage, cookies, server sessions, etc.)
|
|
427
|
+
## XPRNIdentity
|
|
531
428
|
|
|
532
|
-
|
|
429
|
+
Displays user identity information with a dropdown menu and provides session management functionality.
|
|
533
430
|
|
|
534
|
-
|
|
431
|
+
### Import
|
|
535
432
|
|
|
536
433
|
```typescript
|
|
537
|
-
import {
|
|
538
|
-
|
|
539
|
-
// Save authentication data
|
|
540
|
-
authStorage.save('user@proton', {
|
|
541
|
-
actor: 'user@proton',
|
|
542
|
-
publicKey: 'PUB_K1_...',
|
|
543
|
-
data: { token: 'jwt-token' },
|
|
544
|
-
expiresAt: Date.now() + 86400000,
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
// Load/clear/list
|
|
548
|
-
const auth = authStorage.load('user@proton');
|
|
549
|
-
authStorage.clear('user@proton');
|
|
550
|
-
authStorage.clearAll();
|
|
551
|
-
const actors = authStorage.listActors();
|
|
434
|
+
import { XPRNIdentity } from '@rockerone/xprnkit';
|
|
552
435
|
```
|
|
553
436
|
|
|
554
|
-
###
|
|
437
|
+
### Props
|
|
555
438
|
|
|
556
|
-
|
|
439
|
+
| Prop | Type | Default | Description |
|
|
440
|
+
| ------------------------ | ----------------------------------------------------- | ------- | -------------------------------------------------------- |
|
|
441
|
+
| `children` | `React.ReactNode` | - | Content to render inside the dropdown menu. |
|
|
442
|
+
| `className` | `string` | - | Additional CSS classes for the root element. |
|
|
443
|
+
| `showLogout` | `boolean` | - | Whether to show a logout link. |
|
|
444
|
+
| `activeSessionClassName` | `string` | - | CSS classes for the active session container. |
|
|
445
|
+
| `dropdownClassName` | `string` | - | CSS classes for the dropdown menu. |
|
|
446
|
+
| `avatarClassName` | `string` | - | CSS classes for the avatar component. |
|
|
447
|
+
| `matchDropdownWidth` | `boolean` | `true` | Match dropdown width to trigger width. |
|
|
448
|
+
| `closeOnSelect` | `boolean` | `true` | Close dropdown when children are clicked. |
|
|
449
|
+
| `onSession` | `(session: LinkSession, link: ProtonWebLink \| Link) => void` | - | Called when session is established. |
|
|
450
|
+
| `onProfile` | `(profile: XPRNKitProfile) => void` | - | Called when profile is fetched. |
|
|
451
|
+
| `onIdentityProof` | `(proof: XPRNKitIdentityProof) => void` | - | Called when identity proof is obtained. |
|
|
557
452
|
|
|
558
|
-
|
|
453
|
+
### Usage
|
|
559
454
|
|
|
560
|
-
```
|
|
561
|
-
import {
|
|
562
|
-
|
|
563
|
-
function
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
authStorage.save(session.auth.actor.toString(), {
|
|
570
|
-
actor: session.auth.actor.toString(),
|
|
571
|
-
publicKey: session.publicKey.toString(),
|
|
572
|
-
data: authData,
|
|
573
|
-
expiresAt: Date.now() + 86400000,
|
|
574
|
-
});
|
|
575
|
-
},
|
|
576
|
-
(error) => console.error(error)
|
|
577
|
-
);
|
|
578
|
-
};
|
|
455
|
+
```jsx
|
|
456
|
+
import { XPRNIdentity } from '@rockerone/xprnkit';
|
|
457
|
+
|
|
458
|
+
function MyComponent() {
|
|
459
|
+
return (
|
|
460
|
+
<XPRNIdentity showLogout={true} avatarClassName="custom-avatar">
|
|
461
|
+
<div>Additional dropdown content</div>
|
|
462
|
+
</XPRNIdentity>
|
|
463
|
+
);
|
|
579
464
|
}
|
|
580
465
|
```
|
|
581
466
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
**Use Case:** Next.js apps, production
|
|
467
|
+
### Functionality
|
|
585
468
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
'
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
function MyApp() {
|
|
592
|
-
const { session, authenticate } = useXPRN();
|
|
593
|
-
|
|
594
|
-
const handleAuth = () => {
|
|
595
|
-
authenticate(
|
|
596
|
-
async (authData) => {
|
|
597
|
-
await fetch('/api/auth/session', {
|
|
598
|
-
method: 'POST',
|
|
599
|
-
body: JSON.stringify({ actor: session.auth.actor, authData }),
|
|
600
|
-
});
|
|
601
|
-
},
|
|
602
|
-
(error) => console.error(error)
|
|
603
|
-
);
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
```
|
|
469
|
+
1. If a user session exists:
|
|
470
|
+
- Displays a dropdown menu with the user's avatar and session information
|
|
471
|
+
- Shows the user's name and actor information
|
|
472
|
+
- Optionally displays a logout link
|
|
473
|
+
- Renders any child components in the dropdown content
|
|
607
474
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
// app/api/auth/session/route.ts
|
|
611
|
-
import { NextResponse } from 'next/server';
|
|
612
|
-
|
|
613
|
-
export async function POST(request: Request) {
|
|
614
|
-
const body = await request.json();
|
|
615
|
-
const response = NextResponse.json({ success: true });
|
|
616
|
-
|
|
617
|
-
response.cookies.set('xprn_session', createToken(body), {
|
|
618
|
-
httpOnly: true,
|
|
619
|
-
secure: process.env.NODE_ENV === 'production',
|
|
620
|
-
maxAge: 86400,
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
return response;
|
|
624
|
-
}
|
|
625
|
-
```
|
|
475
|
+
2. If no user session exists:
|
|
476
|
+
- Displays a "Connect" button using the `XPRNConnectButton` component
|
|
626
477
|
|
|
627
|
-
|
|
478
|
+
### Identity Sub-Components
|
|
628
479
|
|
|
629
|
-
|
|
480
|
+
The following components are also exported and can be used independently:
|
|
630
481
|
|
|
631
482
|
```typescript
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const body = await request.json();
|
|
638
|
-
const sessionId = randomUUID();
|
|
639
|
-
|
|
640
|
-
await redis.setex(\`session:\${sessionId}\`, 86400, JSON.stringify(body));
|
|
641
|
-
|
|
642
|
-
const response = NextResponse.json({ success: true });
|
|
643
|
-
response.cookies.set('session_id', sessionId, { httpOnly: true });
|
|
644
|
-
return response;
|
|
645
|
-
}
|
|
483
|
+
import {
|
|
484
|
+
XPRNAvatar,
|
|
485
|
+
XPRNSessionActor,
|
|
486
|
+
XPRNSessionName,
|
|
487
|
+
} from '@rockerone/xprnkit';
|
|
646
488
|
```
|
|
647
489
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|----------|----------|-----|----------|
|
|
652
|
-
| **localStorage** | Medium | ❌ | Client apps |
|
|
653
|
-
| **Cookies** | High | ✅ | SSR apps |
|
|
654
|
-
| **Server Sessions** | Very High | ✅ | Production |
|
|
655
|
-
|
|
656
|
-
### Full Examples
|
|
490
|
+
- **XPRNAvatar**: Renders the user's profile avatar.
|
|
491
|
+
- **XPRNSessionActor**: Displays the current session's actor (e.g., `user1@active`).
|
|
492
|
+
- **XPRNSessionName**: Displays the current session user's display name.
|
|
657
493
|
|
|
658
|
-
|
|
659
|
-
- `auth-localstorage.example.tsx` - Client-side with localStorage
|
|
660
|
-
- `auth-cookies-ssr.example.tsx` - SSR with httpOnly cookies
|
|
661
|
-
- `auth-server-session.example.tsx` - Server sessions with Redis/PostgreSQL
|
|
662
|
-
|
|
663
|
-
# Components Documentation
|
|
494
|
+
---
|
|
664
495
|
|
|
665
|
-
|
|
496
|
+
## XPRNAccountList
|
|
666
497
|
|
|
667
|
-
|
|
498
|
+
Lists all stored accounts and allows switching between them, adding new accounts, and removing existing ones.
|
|
668
499
|
|
|
669
|
-
|
|
500
|
+
### Import
|
|
670
501
|
|
|
671
502
|
```typescript
|
|
672
|
-
import {
|
|
503
|
+
import { XPRNAccountList } from '@rockerone/xprnkit';
|
|
673
504
|
```
|
|
674
505
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
The `XRPNContainer` component accepts the following props:
|
|
506
|
+
### Props
|
|
678
507
|
|
|
679
|
-
| Prop
|
|
680
|
-
|
|
|
681
|
-
| `
|
|
682
|
-
| `
|
|
683
|
-
| `
|
|
508
|
+
| Prop | Type | Default | Description |
|
|
509
|
+
| --------------------- | --------------------------------------------------------- | -------------- | -------------------------------------------------- |
|
|
510
|
+
| `showRemove` | `boolean` | `false` | Show remove button for each account. |
|
|
511
|
+
| `showAddAccount` | `boolean` | `false` | Show an "Add Account" button. |
|
|
512
|
+
| `addAccountLabel` | `string` | `"Add Account"` | Custom label for the add account button. |
|
|
513
|
+
| `addAccountClassName` | `string` | - | CSS class for the add account button. |
|
|
514
|
+
| `renderItem` | `(props: AccountItemRenderProps) => React.ReactNode` | - | Custom render function for each account item. |
|
|
515
|
+
| `onSelect` | `(entry: XPRNKitProfileStorageEntry) => void` | - | Called when an account is selected. |
|
|
516
|
+
| `onRemove` | `(entry: XPRNKitProfileStorageEntry) => void` | - | Called when an account is removed. |
|
|
517
|
+
| `onAddAccount` | `() => void` | - | Called when the add account button is clicked. |
|
|
518
|
+
| `itemClassName` | `string` | - | CSS class for account items. |
|
|
519
|
+
| `activeClassName` | `string` | - | CSS class for the active account item. |
|
|
520
|
+
| `className` | `string` | - | Additional CSS classes for the root element. |
|
|
521
|
+
|
|
522
|
+
### AccountItemRenderProps
|
|
684
523
|
|
|
685
|
-
|
|
524
|
+
```typescript
|
|
525
|
+
type AccountItemRenderProps = {
|
|
526
|
+
entry: XPRNKitProfileStorageEntry;
|
|
527
|
+
isActive: boolean;
|
|
528
|
+
onSelect: () => void;
|
|
529
|
+
onRemove?: () => void;
|
|
530
|
+
};
|
|
531
|
+
```
|
|
686
532
|
|
|
687
|
-
|
|
533
|
+
### Usage
|
|
688
534
|
|
|
689
535
|
```jsx
|
|
690
|
-
import {
|
|
536
|
+
import { XPRNIdentity, XPRNAccountList } from '@rockerone/xprnkit';
|
|
691
537
|
|
|
692
|
-
function
|
|
538
|
+
function Navbar() {
|
|
693
539
|
return (
|
|
694
|
-
<
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
</
|
|
540
|
+
<XPRNIdentity showLogout>
|
|
541
|
+
<XPRNAccountList
|
|
542
|
+
showAddAccount
|
|
543
|
+
showRemove
|
|
544
|
+
onSelect={(entry) => console.log("Switched to:", entry.auth.actor)}
|
|
545
|
+
/>
|
|
546
|
+
</XPRNIdentity>
|
|
701
547
|
);
|
|
702
548
|
}
|
|
703
549
|
```
|
|
704
550
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
- If a session is present (determined by the `useXPRN` hook), the component renders its `children`.
|
|
708
|
-
- If no session is present, the component renders the `noSessionState` content if provided, otherwise it renders nothing.
|
|
709
|
-
|
|
710
|
-
## Dependencies
|
|
551
|
+
### Behavior
|
|
711
552
|
|
|
712
|
-
-
|
|
713
|
-
-
|
|
553
|
+
- Reads stored profiles from localStorage and displays them as a list.
|
|
554
|
+
- The active account is highlighted with a checkmark.
|
|
555
|
+
- Clicking an account calls `switchToSession` to restore that session.
|
|
556
|
+
- The "Add Account" button triggers a new wallet connection via `connect()`.
|
|
557
|
+
- Each account item shows the avatar, display name, actor, KYC badge, and identity proof badge.
|
|
714
558
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
- This component uses the "use client" directive, indicating it's designed for client-side rendering in Next.js applications.
|
|
718
|
-
- The component leverages the `useXPRN` hook to determine the session state.
|
|
559
|
+
---
|
|
719
560
|
|
|
720
|
-
|
|
561
|
+
## XRPNContainer / XPRNLogged / XPRNUnlogged
|
|
721
562
|
|
|
722
|
-
|
|
563
|
+
Conditional rendering components based on the presence of a session.
|
|
723
564
|
|
|
724
|
-
|
|
565
|
+
### Import
|
|
725
566
|
|
|
726
567
|
```typescript
|
|
727
|
-
import {
|
|
568
|
+
import { XRPNContainer, XPRNLogged, XPRNUnlogged } from '@rockerone/xprnkit';
|
|
728
569
|
```
|
|
729
570
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
The `XPRNConnectButton` accepts the following props:
|
|
571
|
+
### XRPNContainer
|
|
733
572
|
|
|
734
|
-
|
|
735
|
-
| ----------- | ----------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
736
|
-
| `className` | `string` | Additional CSS classes to apply to the button |
|
|
737
|
-
| `variant` | `string` | Button variant (style) |
|
|
738
|
-
| `size` | `string` | Button size |
|
|
739
|
-
| `asChild` | `boolean` | If true, renders the component as a child component |
|
|
740
|
-
| `onClick` | `function` | Custom click handler (Note: internal connect/disconnect logic will still apply) |
|
|
741
|
-
| `children` | `React.ReactNode` | Custom content for the button when not connected |
|
|
742
|
-
| `...props` | `React.ButtonHTMLAttributes<HTMLButtonElement>` | Any other props accepted by HTML button element |
|
|
573
|
+
Renders `children` when a session is present, or `noSessionState` content otherwise.
|
|
743
574
|
|
|
744
|
-
|
|
575
|
+
| Prop | Type | Description |
|
|
576
|
+
| ---------------- | -------------------------- | ----------------------------------------------------------- |
|
|
577
|
+
| `children` | `ReactNode \| ReactNode[]` | Content to render when a session is present. |
|
|
578
|
+
| `className` | `string` | Optional CSS class name(s). |
|
|
579
|
+
| `noSessionState` | `ReactNode \| ReactNode[]` | Content to render when no session is present. |
|
|
745
580
|
|
|
746
581
|
```jsx
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
return (
|
|
751
|
-
<XPRNConnectButton variant="primary" size="medium" className="custom-class">
|
|
752
|
-
Connect to XPRN
|
|
753
|
-
</XPRNConnectButton>
|
|
754
|
-
);
|
|
755
|
-
}
|
|
582
|
+
<XRPNContainer noSessionState={<p>Please log in.</p>}>
|
|
583
|
+
<p>Welcome! You are connected.</p>
|
|
584
|
+
</XRPNContainer>
|
|
756
585
|
```
|
|
757
586
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
- When there's no active session, the button displays the provided `children` content and triggers the `connect()` function when clicked.
|
|
761
|
-
- When there's an active session, the button displays "Log out (actor)" and triggers the `disconnect()` function when clicked.
|
|
587
|
+
### XPRNLogged
|
|
762
588
|
|
|
763
|
-
|
|
589
|
+
Renders its children **only** when a session is present.
|
|
764
590
|
|
|
765
|
-
|
|
591
|
+
```jsx
|
|
592
|
+
<XPRNLogged>
|
|
593
|
+
<p>This is only visible when connected.</p>
|
|
594
|
+
</XPRNLogged>
|
|
595
|
+
```
|
|
766
596
|
|
|
767
|
-
|
|
597
|
+
### XPRNUnlogged
|
|
768
598
|
|
|
769
|
-
|
|
599
|
+
Renders its children **only** when no session is present.
|
|
770
600
|
|
|
771
|
-
|
|
601
|
+
```jsx
|
|
602
|
+
<XPRNUnlogged>
|
|
603
|
+
<p>Please connect your wallet to continue.</p>
|
|
604
|
+
</XPRNUnlogged>
|
|
605
|
+
```
|
|
772
606
|
|
|
773
|
-
|
|
607
|
+
---
|
|
774
608
|
|
|
775
|
-
|
|
609
|
+
## XPRNTransaction
|
|
776
610
|
|
|
777
|
-
|
|
778
|
-
- `className`: Additional CSS classes for the root element (optional)
|
|
779
|
-
- `showLogout`: Boolean to determine if the logout link should be displayed (optional)
|
|
780
|
-
- `activeSessionClassName`: Additional CSS classes for the active session container (optional)
|
|
781
|
-
- `dropdownClassName`: Additional CSS classes for the dropdown menu (optional)
|
|
782
|
-
- `avatarClassName`: Additional CSS classes for the avatar component (optional)
|
|
611
|
+
A button component that pushes a blockchain transaction using the active session.
|
|
783
612
|
|
|
784
|
-
|
|
613
|
+
### Import
|
|
785
614
|
|
|
786
|
-
|
|
615
|
+
```typescript
|
|
616
|
+
import { XPRNTransaction } from '@rockerone/xprnkit';
|
|
617
|
+
```
|
|
787
618
|
|
|
788
|
-
|
|
789
|
-
- Shows the user's name and actor information
|
|
790
|
-
- Optionally displays a logout link
|
|
791
|
-
- Renders any child components in the dropdown content
|
|
619
|
+
### Props
|
|
792
620
|
|
|
793
|
-
|
|
794
|
-
|
|
621
|
+
| Prop | Type | Description |
|
|
622
|
+
| ---------------------- | --------------------------------- | -------------------------------------------------------- |
|
|
623
|
+
| `actions` | `any[]` | Array of transaction actions to push. |
|
|
624
|
+
| `onTransactionStart` | `() => void` | Called when the transaction starts (optional). |
|
|
625
|
+
| `onTransactionSuccess` | `(res: TransactResult) => void` | Called when the transaction succeeds (optional). |
|
|
626
|
+
| `onTransactionFail` | `(e: any) => void` | Called when the transaction fails (optional). |
|
|
627
|
+
| `className` | `string` | Additional CSS classes. |
|
|
628
|
+
| `variant` | `string` | Button variant (style). |
|
|
629
|
+
| `size` | `string` | Button size. |
|
|
630
|
+
| `asChild` | `boolean` | If true, renders as a child component. |
|
|
631
|
+
| `children` | `React.ReactNode` | Button label content. |
|
|
795
632
|
|
|
796
|
-
|
|
633
|
+
### Usage
|
|
797
634
|
|
|
798
635
|
```jsx
|
|
799
|
-
import {
|
|
636
|
+
import { XPRNTransaction } from '@rockerone/xprnkit';
|
|
800
637
|
|
|
801
|
-
function
|
|
638
|
+
function SwapButton({ actions }) {
|
|
802
639
|
return (
|
|
803
|
-
<
|
|
804
|
-
|
|
805
|
-
|
|
640
|
+
<XPRNTransaction
|
|
641
|
+
actions={actions}
|
|
642
|
+
onTransactionSuccess={(res) => console.log("Success:", res)}
|
|
643
|
+
onTransactionFail={(err) => console.error("Failed:", err)}
|
|
644
|
+
>
|
|
645
|
+
Swap
|
|
646
|
+
</XPRNTransaction>
|
|
806
647
|
);
|
|
807
648
|
}
|
|
808
649
|
```
|
|
809
650
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
- The component is wrapped in a "use client" directive, indicating it's designed for client-side rendering.
|
|
813
|
-
- It uses the `useXPRN` hook to access session information and the `disconnect` function.
|
|
814
|
-
- The logout functionality is implemented using the `disconnect` function from the XPRN context.
|
|
651
|
+
### Behavior
|
|
815
652
|
|
|
816
|
-
|
|
653
|
+
- When no session is present, displays a "Connect" button that triggers wallet connection.
|
|
654
|
+
- When a session is present, clicking the button pushes the transaction.
|
|
655
|
+
- Automatically shows loading spinner during transaction and success/fail states after completion.
|
|
817
656
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
1. **XPRNAvatar**
|
|
821
|
-
|
|
822
|
-
- Exported from: `'./xprn-avatar'`
|
|
823
|
-
- Description: A component for rendering user avatars or profile pictures.
|
|
824
|
-
|
|
825
|
-
2. **XPRNSessionActor**
|
|
826
|
-
|
|
827
|
-
- Exported from: `'./xprn-session-actor'`
|
|
828
|
-
- Description: Related to the current session's active user or actor.
|
|
829
|
-
|
|
830
|
-
3. **XPRNSessionName**
|
|
831
|
-
- Exported from: `'./xprn-session-name'`
|
|
832
|
-
- Description: For displaying the current session user's name.
|
|
833
|
-
|
|
834
|
-
## Usage
|
|
835
|
-
|
|
836
|
-
To use these components in your project, you can import them from this file:
|
|
657
|
+
---
|
|
837
658
|
|
|
838
|
-
|
|
839
|
-
import {
|
|
840
|
-
XPRNAvatar,
|
|
841
|
-
XPRNSessionActor,
|
|
842
|
-
XPRNSessionName,
|
|
843
|
-
} from "xprnkit/src/components/identity";
|
|
844
|
-
```
|
|
659
|
+
# Swap Components
|
|
845
660
|
|
|
846
|
-
|
|
661
|
+
## XPRNSwap
|
|
847
662
|
|
|
848
|
-
The `XPRNSwap` component
|
|
663
|
+
The `XPRNSwap` component provides a complete token swap interface out of the box.
|
|
849
664
|
|
|
850
|
-
|
|
665
|
+
### Import
|
|
851
666
|
|
|
852
667
|
```typescript
|
|
853
|
-
import {XPRNSwap} from
|
|
668
|
+
import { XPRNSwap } from '@rockerone/xprnkit';
|
|
854
669
|
```
|
|
855
670
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
The `XPRNSwap` component accepts the following props:
|
|
671
|
+
### Props
|
|
859
672
|
|
|
860
673
|
| Prop | Type | Description |
|
|
861
674
|
| ----------- | ------------------------------- | ----------------------------------------------------------- |
|
|
@@ -865,38 +678,44 @@ The `XPRNSwap` component accepts the following props:
|
|
|
865
678
|
| `className` | `string` | Optional. Additional CSS classes to apply to the component. |
|
|
866
679
|
| `children` | `React.ReactNode` | Optional. Child elements to render within the component. |
|
|
867
680
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
## Usage
|
|
681
|
+
### Usage
|
|
871
682
|
|
|
872
|
-
|
|
683
|
+
#### Basic
|
|
873
684
|
|
|
874
685
|
```jsx
|
|
875
686
|
<XPRNSwap />
|
|
876
687
|
```
|
|
877
688
|
|
|
878
|
-
|
|
689
|
+
#### With config
|
|
879
690
|
|
|
880
691
|
```jsx
|
|
881
692
|
<XPRNSwap
|
|
882
|
-
filters={
|
|
883
|
-
sides={['buy', 'sell']}
|
|
884
|
-
|
|
885
|
-
className="custom-class"
|
|
693
|
+
filters={{ quoteSymbol: "XUSDC" }}
|
|
694
|
+
sides={['buy', 'sell']}
|
|
695
|
+
className="custom-class"
|
|
886
696
|
/>
|
|
887
697
|
```
|
|
888
698
|
|
|
889
|
-
|
|
699
|
+
#### Custom layout using `XPRNSwapProvider`
|
|
890
700
|
|
|
891
701
|
```jsx
|
|
702
|
+
import {
|
|
703
|
+
XPRNSwapProvider,
|
|
704
|
+
XPRNPairsSelector,
|
|
705
|
+
XPRNSwapFieldsGroup,
|
|
706
|
+
XPRNSwapField,
|
|
707
|
+
XPRNSwapSideButton,
|
|
708
|
+
XPRNTransaction,
|
|
709
|
+
} from '@rockerone/xprnkit';
|
|
710
|
+
|
|
892
711
|
<XPRNSwapProvider
|
|
893
|
-
config={{filters: {quoteSymbol: "SNIPS", baseSymbol: "XUSDC"}}}
|
|
712
|
+
config={{ filters: { quoteSymbol: "SNIPS", baseSymbol: "XUSDC" } }}
|
|
894
713
|
>
|
|
895
|
-
<div className="
|
|
714
|
+
<div className="grid grid-cols-[1fr,min-content] gap-6 p-4 w-full">
|
|
896
715
|
<XPRNPairsSelector />
|
|
897
716
|
<XPRNSwapFieldsGroup horizontal className="w-full">
|
|
898
717
|
<XPRNSwapField />
|
|
899
|
-
<XPRNSwapSideButton horizontal>
|
|
718
|
+
<XPRNSwapSideButton horizontal>Swap</XPRNSwapSideButton>
|
|
900
719
|
<XPRNSwapField />
|
|
901
720
|
</XPRNSwapFieldsGroup>
|
|
902
721
|
<XPRNTransaction>Swap</XPRNTransaction>
|
|
@@ -904,41 +723,34 @@ className="custom-class"
|
|
|
904
723
|
</XPRNSwapProvider>
|
|
905
724
|
```
|
|
906
725
|
|
|
907
|
-
|
|
726
|
+
### Behavior
|
|
908
727
|
|
|
909
728
|
1. The component wraps its content in an `XPRNSwapProvider` to provide context for swap-related data and functionality.
|
|
910
729
|
2. It renders an `XPRNSwapLayout` component within the provider.
|
|
911
730
|
3. The component applies a default grid layout with padding and border styling.
|
|
912
|
-
4.
|
|
913
|
-
|
|
914
|
-
## Dependencies
|
|
915
|
-
|
|
916
|
-
- XPRNSwapProvider
|
|
917
|
-
- XPRNSwapLayout
|
|
918
|
-
|
|
919
|
-
## Notes
|
|
731
|
+
4. Alternatively, you can rebuild the entire swap layout using the sub-components wrapped in a `XPRNSwapProvider`.
|
|
920
732
|
|
|
921
|
-
|
|
733
|
+
---
|
|
922
734
|
|
|
923
|
-
|
|
735
|
+
## XPRNSwapProvider
|
|
924
736
|
|
|
925
|
-
The `XPRNSwapProvider` is a React component that provides context for managing
|
|
737
|
+
The `XPRNSwapProvider` is a React component that provides context for managing swap operations.
|
|
926
738
|
|
|
927
|
-
|
|
739
|
+
### Usage
|
|
928
740
|
|
|
929
741
|
```jsx
|
|
930
|
-
import { XPRNSwapProvider } from '
|
|
742
|
+
import { XPRNSwapProvider } from '@rockerone/xprnkit';
|
|
931
743
|
|
|
932
744
|
function App() {
|
|
933
745
|
return (
|
|
934
746
|
<XPRNSwapProvider config={/* optional config */}>
|
|
935
|
-
{/* Your
|
|
747
|
+
{/* Your swap sub-components */}
|
|
936
748
|
</XPRNSwapProvider>
|
|
937
749
|
);
|
|
938
750
|
}
|
|
939
751
|
```
|
|
940
752
|
|
|
941
|
-
|
|
753
|
+
### Props
|
|
942
754
|
|
|
943
755
|
| Prop | Type | Description |
|
|
944
756
|
| ---------- | -------------------------------------- | ---------------------------------------------- |
|
|
@@ -953,9 +765,18 @@ function App() {
|
|
|
953
765
|
| `marketFilters` | `string[]` (optional) | Filters for specific markets |
|
|
954
766
|
| `sides` | `XPRNSwapSide[]` (optional) | Available swap sides (e.g., "buy", "sell") |
|
|
955
767
|
|
|
956
|
-
|
|
768
|
+
### Context (useXPRNSwap)
|
|
769
|
+
|
|
770
|
+
The `useXPRNSwap` hook provides access to the swap context:
|
|
771
|
+
|
|
772
|
+
```jsx
|
|
773
|
+
import { useXPRNSwap } from '@rockerone/xprnkit';
|
|
957
774
|
|
|
958
|
-
|
|
775
|
+
function SwapComponent() {
|
|
776
|
+
const { currentSwapPair, swapSide, setSwapSide } = useXPRNSwap();
|
|
777
|
+
// ...
|
|
778
|
+
}
|
|
779
|
+
```
|
|
959
780
|
|
|
960
781
|
| Property/Method | Type | Description |
|
|
961
782
|
| -------------------------- | ----------------------------------------------------------------------- | ------------------------------------------- |
|
|
@@ -968,7 +789,7 @@ The `XPRNSwapProvider` creates a context with the following properties and metho
|
|
|
968
789
|
| `setCurrentSwapPair` | `(pair: XPRNMarketProviderResult) => void` | Function to set the current swap pair |
|
|
969
790
|
| `currentSwapPair` | `XPRNMarketProviderResult \| null` | Currently selected swap pair |
|
|
970
791
|
| `swapTransaction` | `any[]` | Current swap transaction details |
|
|
971
|
-
| `swapSide` | `XPRNSwapSide` | Current swap side (
|
|
792
|
+
| `swapSide` | `XPRNSwapSide` | Current swap side ("buy" or "sell") |
|
|
972
793
|
| `setSwapSide` | `(value: XPRNSwapSide) => void` | Function to set the swap side |
|
|
973
794
|
| `swapVolume` | `number` | Current swap volume |
|
|
974
795
|
| `setSwapVolume` | `(value: number) => void` | Function to set the swap volume |
|
|
@@ -976,47 +797,25 @@ The `XPRNSwapProvider` creates a context with the following properties and metho
|
|
|
976
797
|
| `swapValues` | `XPRNSwapValues` | Current swap values |
|
|
977
798
|
| `updateSwapValues` | `(base: number, quote: number, lastMutated: "base" \| "quote") => void` | Function to update swap values |
|
|
978
799
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
The `useXPRNSwap` hook can be used to access the `XPRNSwapProvider` context in child components.
|
|
800
|
+
### Notes
|
|
982
801
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
```jsx
|
|
986
|
-
import { useXPRNSwap } from 'path/to/xprn-swap-provider';
|
|
987
|
-
|
|
988
|
-
function SwapComponent() {
|
|
989
|
-
const { currentSwapPair, swapSide, setSwapSide } = useXPRNSwap();
|
|
990
|
-
|
|
991
|
-
// Use the context values and methods
|
|
992
|
-
// ...
|
|
993
|
-
|
|
994
|
-
return (
|
|
995
|
-
// Your component JSX
|
|
996
|
-
);
|
|
997
|
-
}
|
|
998
|
-
```
|
|
999
|
-
|
|
1000
|
-
## Notes
|
|
1001
|
-
|
|
1002
|
-
- The provider fetches market pairs from the selected market provider's endpoint (currently Alcor is the only supported exchange). You can edit or add new provider using the `XPRNMarketProvider` interface.
|
|
802
|
+
- The provider fetches market pairs from the selected market provider's endpoint (currently Alcor is the only supported exchange). You can add new providers using the `XPRNMarketProvider` interface.
|
|
1003
803
|
- It manages the state of the current swap, including the selected pair, swap side, and volume.
|
|
1004
804
|
- The provider automatically updates swap transactions when relevant values change.
|
|
1005
|
-
- Error handling is implemented for network requests and configuration issues.
|
|
1006
805
|
|
|
1007
|
-
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
## XPRNSwapFieldsGroup
|
|
1008
809
|
|
|
1009
|
-
|
|
810
|
+
A flexible container for grouping swap fields that flips field positions according to the swap side (buy or sell).
|
|
1010
811
|
|
|
1011
|
-
|
|
812
|
+
### Import
|
|
1012
813
|
|
|
1013
814
|
```typescript
|
|
1014
|
-
import {XPRNSwapFieldsGroup} from
|
|
815
|
+
import { XPRNSwapFieldsGroup } from '@rockerone/xprnkit';
|
|
1015
816
|
```
|
|
1016
817
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
The component accepts the following props:
|
|
818
|
+
### Props
|
|
1020
819
|
|
|
1021
820
|
| Prop | Type | Default | Description |
|
|
1022
821
|
| ------------ | ----------------- | ----------- | --------------------------------------------------------- |
|
|
@@ -1024,229 +823,181 @@ The component accepts the following props:
|
|
|
1024
823
|
| `className` | `string` | `undefined` | Additional CSS classes to be applied to the root element. |
|
|
1025
824
|
| `horizontal` | `boolean` | `false` | Determines if the fields should be arranged horizontally. |
|
|
1026
825
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
## Usage
|
|
1030
|
-
|
|
1031
|
-
```jsx
|
|
1032
|
-
import {XPRNSwapFieldsGroup} from "packages/xprnkit/src/components/swap/xprn-swap-fields-group";
|
|
1033
|
-
|
|
1034
|
-
function SwapInterface() {
|
|
1035
|
-
return (
|
|
1036
|
-
<XPRNSwapFieldsGroup horizontal={true} className="custom-class">
|
|
1037
|
-
{/* Swap field components go here */}
|
|
1038
|
-
</XPRNSwapFieldsGroup>
|
|
1039
|
-
);
|
|
1040
|
-
}
|
|
1041
|
-
```
|
|
1042
|
-
|
|
1043
|
-
## Behavior
|
|
826
|
+
### Behavior
|
|
1044
827
|
|
|
1045
|
-
- The component uses the `useXPRNSwap` hook to access the current swap configuration.
|
|
1046
|
-
- It dynamically applies CSS classes based on the `horizontal` prop and the current `swapSide`.
|
|
1047
828
|
- The layout of child components is reversed when `swapSide` is "sell".
|
|
1048
|
-
-
|
|
829
|
+
- Supports both vertical (default) and horizontal layouts.
|
|
830
|
+
|
|
831
|
+
---
|
|
1049
832
|
|
|
1050
|
-
|
|
833
|
+
## XPRNSwapField
|
|
1051
834
|
|
|
1052
|
-
|
|
835
|
+
An input field for entering the amount of tokens to swap, for either the base or quote currency.
|
|
1053
836
|
|
|
1054
|
-
|
|
837
|
+
### Import
|
|
1055
838
|
|
|
1056
839
|
```typescript
|
|
1057
|
-
import {
|
|
840
|
+
import { XPRNSwapField } from '@rockerone/xprnkit';
|
|
1058
841
|
```
|
|
1059
842
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
The component accepts the following props:
|
|
1063
|
-
|
|
1064
|
-
| Prop | Type | Default | Description |
|
|
1065
|
-
| ------------ | ----------------- | ----------- | --------------------------------------------------------------------------------------------- |
|
|
1066
|
-
| `horizontal` | `boolean` | `false` | Determines the orientation of the swap icon. If `true`, a horizontal arrow icon is displayed. |
|
|
1067
|
-
| `children` | `React.ReactNode` | `undefined` | Custom content to be rendered inside the button. If not provided, a default icon is used. |
|
|
1068
|
-
| `className` | `string` | `undefined` | Additional CSS classes to be applied to the button. |
|
|
843
|
+
### Props
|
|
1069
844
|
|
|
1070
|
-
|
|
845
|
+
- `type`: `"quote" | "base"` - Indicates whether this field is for the quote or base currency.
|
|
846
|
+
- `className`: Optional string for additional CSS classes.
|
|
1071
847
|
|
|
1072
|
-
|
|
848
|
+
Must be wrapped in a `XPRNSwapProvider`.
|
|
1073
849
|
|
|
1074
|
-
|
|
1075
|
-
import {XPRNSwapSideButton} from "path/to/xprn-swap-side-button";
|
|
850
|
+
### Usage
|
|
1076
851
|
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
<div>
|
|
1080
|
-
{/* Other swap interface components */}
|
|
1081
|
-
<XPRNSwapSideButton horizontal={true} className="custom-class" />
|
|
1082
|
-
</div>
|
|
1083
|
-
);
|
|
1084
|
-
}
|
|
852
|
+
```tsx
|
|
853
|
+
<XPRNSwapField type="base" className="custom-class" />
|
|
1085
854
|
```
|
|
1086
855
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
- The button toggles between "buy" and "sell" sides when clicked.
|
|
1090
|
-
- It uses the `useXPRNSwap` hook to access and modify the swap state.
|
|
1091
|
-
- The button is not rendered if the swap configuration only has one side.
|
|
1092
|
-
- The button has a hover effect that rotates it 180 degrees.
|
|
1093
|
-
|
|
1094
|
-
## Customization
|
|
1095
|
-
|
|
1096
|
-
- You can provide custom content by passing children to the component.
|
|
1097
|
-
- The default icon can be overridden by passing custom JSX as children.
|
|
1098
|
-
- Additional styling can be applied using the `className` prop.
|
|
1099
|
-
|
|
1100
|
-
## Notes
|
|
1101
|
-
|
|
1102
|
-
- The component is wrapped with `"use client"` directive, indicating it's a Client Component in Next.js.
|
|
1103
|
-
- It uses React hooks (`useCallback`, `useMemo`) for performance optimization.
|
|
1104
|
-
|
|
1105
|
-
# XPRNSwapField Component
|
|
1106
|
-
|
|
1107
|
-
## Overview
|
|
1108
|
-
|
|
1109
|
-
The `XPRNSwapField` is a React component used in a the `XPRNSwap` interface. It provides an input field for users to enter the amount of tokens they want to swap, either for the base or quote currency of a trading pair. This component should be wrapped in a `XPRNSwapProvider`
|
|
1110
|
-
|
|
1111
|
-
## Props
|
|
1112
|
-
|
|
1113
|
-
The component accepts the following props:
|
|
1114
|
-
|
|
1115
|
-
- `type`: A string, either "quote" or "base", indicating whether this field is for the quote or base currency.
|
|
1116
|
-
- `className`: An optional string for additional CSS classes.
|
|
1117
|
-
- `children`: Optional child elements (not used in the current implementation).
|
|
856
|
+
---
|
|
1118
857
|
|
|
1119
|
-
|
|
858
|
+
## XPRNSwapSideButton
|
|
1120
859
|
|
|
1121
|
-
|
|
860
|
+
A button for switching between "buy" and "sell" sides in the swap interface.
|
|
1122
861
|
|
|
1123
|
-
|
|
1124
|
-
import {XPRNSwapField} from "./path/to/xprn-swap-field";
|
|
862
|
+
### Import
|
|
1125
863
|
|
|
1126
|
-
|
|
864
|
+
```typescript
|
|
865
|
+
import { XPRNSwapSideButton } from '@rockerone/xprnkit';
|
|
1127
866
|
```
|
|
1128
867
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
The component uses CSS classes for styling, including conditional classes based on the `className` prop and predefined classes for the input field.
|
|
1132
|
-
|
|
1133
|
-
# XPRNSwapMarketsSelector
|
|
1134
|
-
|
|
1135
|
-
## Overview
|
|
868
|
+
### Props
|
|
1136
869
|
|
|
1137
|
-
|
|
870
|
+
| Prop | Type | Default | Description |
|
|
871
|
+
| ------------ | ----------------- | ----------- | ---------------------------------------------------------------------------------- |
|
|
872
|
+
| `horizontal` | `boolean` | `false` | If `true`, displays a horizontal arrow icon. |
|
|
873
|
+
| `children` | `React.ReactNode` | `undefined` | Custom content inside the button. If not provided, a default arrow icon is used. |
|
|
874
|
+
| `className` | `string` | `undefined` | Additional CSS classes. |
|
|
1138
875
|
|
|
1139
|
-
|
|
876
|
+
### Behavior
|
|
1140
877
|
|
|
1141
|
-
|
|
878
|
+
- Toggles between "buy" and "sell" sides when clicked.
|
|
879
|
+
- Not rendered if the swap configuration only has one side.
|
|
880
|
+
- Has a hover effect that rotates the icon 180 degrees.
|
|
1142
881
|
|
|
1143
|
-
|
|
1144
|
-
- `className`: string (optional)
|
|
882
|
+
---
|
|
1145
883
|
|
|
1146
|
-
|
|
884
|
+
## XPRNSwapMarketsSelector
|
|
1147
885
|
|
|
1148
|
-
|
|
886
|
+
A dropdown selector for swap market providers. Must be wrapped in a `XPRNSwapProvider`.
|
|
1149
887
|
|
|
1150
|
-
|
|
1151
|
-
import {XPRNSwapMarketsSelector} from "path/to/xprn-swap-markets-selector";
|
|
888
|
+
### Import
|
|
1152
889
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
}
|
|
890
|
+
```typescript
|
|
891
|
+
import { XPRNSwapMarketsSelector } from '@rockerone/xprnkit';
|
|
1156
892
|
```
|
|
1157
893
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
1. The component uses the `useXPRNSwap` hook to get `marketProviders`.
|
|
1161
|
-
2. It initializes `services` state with `useState`.
|
|
1162
|
-
3. `defaultServices` are memoized using `useMemo` and set to `DEFAULT_SWAP_SERVICES`.
|
|
1163
|
-
4. `defaultService` is memoized to find the first service marked as default or the first service in the list.
|
|
1164
|
-
5. The component renders a `Select` component
|
|
1165
|
-
|
|
1166
|
-
## Conditional Rendering
|
|
894
|
+
### Props
|
|
1167
895
|
|
|
1168
|
-
|
|
896
|
+
- `className`: Optional string for additional CSS classes.
|
|
1169
897
|
|
|
1170
|
-
|
|
898
|
+
Only renders if there is more than one market provider available.
|
|
1171
899
|
|
|
1172
|
-
|
|
900
|
+
---
|
|
1173
901
|
|
|
1174
|
-
|
|
902
|
+
## XPRNPairsSelector
|
|
1175
903
|
|
|
1176
|
-
|
|
904
|
+
A dropdown selector for available trading pairs from the selected market provider. Must be wrapped in a `XPRNSwapProvider`.
|
|
1177
905
|
|
|
1178
|
-
|
|
906
|
+
### Import
|
|
1179
907
|
|
|
1180
908
|
```typescript
|
|
1181
|
-
import
|
|
1182
|
-
import classNames from "classnames";
|
|
1183
|
-
import {useXPRNSwap} from "./xprn-swap-provider";
|
|
1184
|
-
import {
|
|
1185
|
-
Select,
|
|
1186
|
-
SelectItem,
|
|
1187
|
-
SelectContent,
|
|
1188
|
-
SelectTrigger,
|
|
1189
|
-
SelectValue,
|
|
1190
|
-
} from "../ui/select";
|
|
909
|
+
import { XPRNPairsSelector } from '@rockerone/xprnkit';
|
|
1191
910
|
```
|
|
1192
911
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
The component accepts the following props:
|
|
1196
|
-
|
|
1197
|
-
- `className?: string`: Additional CSS classes for the root element.
|
|
1198
|
-
- `contentClassName?: string`: Additional CSS classes for the dropdown content.
|
|
1199
|
-
- `itemsClassName?: string`: Additional CSS classes for the dropdown items.
|
|
912
|
+
### Props
|
|
1200
913
|
|
|
1201
|
-
|
|
914
|
+
- `className`: Optional CSS classes for the root element.
|
|
915
|
+
- `contentClassName`: Optional CSS classes for the dropdown content.
|
|
916
|
+
- `itemsClassName`: Optional CSS classes for the dropdown items.
|
|
1202
917
|
|
|
1203
|
-
|
|
918
|
+
### Behavior
|
|
1204
919
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
4. The component shows loading and error states based on the `XPRNSwapProvider` loading status of the pair list.
|
|
920
|
+
- Displays available trading pairs from the current market provider.
|
|
921
|
+
- Shows loading and error states based on the pair list fetch status.
|
|
922
|
+
- Does not render if there is only one or zero pairs available.
|
|
1209
923
|
|
|
1210
|
-
|
|
924
|
+
---
|
|
1211
925
|
|
|
1212
|
-
|
|
1213
|
-
<XPRNPairsSelector
|
|
1214
|
-
className="custom-class"
|
|
1215
|
-
contentClassName="content-class"
|
|
1216
|
-
itemsClassName="item-class"
|
|
1217
|
-
/>
|
|
1218
|
-
```
|
|
926
|
+
# Types Reference
|
|
1219
927
|
|
|
1220
|
-
|
|
928
|
+
```typescript
|
|
929
|
+
type XPRProviderConfig = {
|
|
930
|
+
chainId: string;
|
|
931
|
+
endpoints: string[];
|
|
932
|
+
dAppName: string;
|
|
933
|
+
requesterAccount: string;
|
|
934
|
+
requesterLogo?: string;
|
|
935
|
+
apiMode: "testnet" | "mainnet";
|
|
936
|
+
restoreSession?: boolean;
|
|
937
|
+
identityProof?: XPRNKitIdentityProofConfig;
|
|
938
|
+
};
|
|
1221
939
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
- Displays "Pairs shit" (consider changing this to a more appropriate error message).
|
|
940
|
+
type XPRNKitProfile = {
|
|
941
|
+
displayName: string;
|
|
942
|
+
avatar?: string;
|
|
943
|
+
isKyc: boolean;
|
|
944
|
+
};
|
|
1228
945
|
|
|
1229
|
-
|
|
946
|
+
type XPRNKitIdentityProofConfig = {
|
|
947
|
+
required: boolean;
|
|
948
|
+
createUrl: string;
|
|
949
|
+
validationUrl?: string;
|
|
950
|
+
validationBuffer?: number;
|
|
951
|
+
headers?: Record<string, string>;
|
|
952
|
+
timeout?: number;
|
|
953
|
+
};
|
|
1230
954
|
|
|
1231
|
-
|
|
955
|
+
type XPRNKitIdentityProof = {
|
|
956
|
+
auth: {
|
|
957
|
+
actor: string;
|
|
958
|
+
permission: string;
|
|
959
|
+
};
|
|
960
|
+
token: string;
|
|
961
|
+
};
|
|
1232
962
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
963
|
+
type XPRNKitIdentityProofPayload = {
|
|
964
|
+
signer: {
|
|
965
|
+
actor: string;
|
|
966
|
+
permission: string;
|
|
967
|
+
};
|
|
968
|
+
transaction: any;
|
|
969
|
+
signatures: string[];
|
|
970
|
+
chainId: string;
|
|
971
|
+
};
|
|
1236
972
|
|
|
1237
|
-
|
|
973
|
+
type XPRNKitIdentityProofStatus =
|
|
974
|
+
| "idle"
|
|
975
|
+
| "signing"
|
|
976
|
+
| "verifying"
|
|
977
|
+
| "validating"
|
|
978
|
+
| "success"
|
|
979
|
+
| "expired"
|
|
980
|
+
| "error";
|
|
981
|
+
|
|
982
|
+
type XPRNKitProfileStorageEntry = {
|
|
983
|
+
auth: {
|
|
984
|
+
actor: string;
|
|
985
|
+
permission: string;
|
|
986
|
+
};
|
|
987
|
+
chainId: string;
|
|
988
|
+
profile: XPRNKitProfile;
|
|
989
|
+
};
|
|
990
|
+
```
|
|
1238
991
|
|
|
1239
|
-
|
|
1240
|
-
- The default selected value is set based on the `currentSwapPair`.
|
|
1241
|
-
- Consider improving the error message for the "fail" state to be more user-friendly and informative.
|
|
992
|
+
---
|
|
1242
993
|
|
|
1243
|
-
#
|
|
994
|
+
# Utilities
|
|
1244
995
|
|
|
1245
|
-
##
|
|
996
|
+
## toPrecision
|
|
1246
997
|
|
|
1247
|
-
The `toPrecision` function adjusts a numeric value to a specified precision, with options for rounding behavior and decimal representation. It's used to format
|
|
998
|
+
The `toPrecision` function adjusts a numeric value to a specified precision, with options for rounding behavior and decimal representation. It's used to format an arbitrary price according to the token precision.
|
|
1248
999
|
|
|
1249
|
-
|
|
1000
|
+
### Function Signature
|
|
1250
1001
|
|
|
1251
1002
|
```typescript
|
|
1252
1003
|
function toPrecision(
|
|
@@ -1257,7 +1008,7 @@ function toPrecision(
|
|
|
1257
1008
|
): string;
|
|
1258
1009
|
```
|
|
1259
1010
|
|
|
1260
|
-
|
|
1011
|
+
### Parameters
|
|
1261
1012
|
|
|
1262
1013
|
- `value` (number): The input number to be adjusted.
|
|
1263
1014
|
- `precision` (number): The number of decimal places to round to.
|
|
@@ -1268,19 +1019,11 @@ function toPrecision(
|
|
|
1268
1019
|
- 'none': Uses 'ceil' behavior (same as 'ceil').
|
|
1269
1020
|
- `forceDecimal` (boolean, optional): Whether to force the output to include decimal places. Defaults to true.
|
|
1270
1021
|
|
|
1271
|
-
|
|
1022
|
+
### Returns
|
|
1272
1023
|
|
|
1273
1024
|
- (string): The adjusted value as a string, with or without forced decimal places based on the `forceDecimal` parameter.
|
|
1274
1025
|
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
1. Multiplies the input `value` by 10^`precision` to shift the decimal point.
|
|
1278
|
-
2. Applies the specified rounding `mode` to the shifted value.
|
|
1279
|
-
3. Divides the result by 10^`precision` to shift the decimal point back.
|
|
1280
|
-
4. If `forceDecimal` is true, returns the result with the specified number of decimal places.
|
|
1281
|
-
5. If `forceDecimal` is false, returns the result as a string without forcing decimal places.
|
|
1282
|
-
|
|
1283
|
-
## Example Usage
|
|
1026
|
+
### Example Usage
|
|
1284
1027
|
|
|
1285
1028
|
```typescript
|
|
1286
1029
|
console.log(toPrecision(3.14159, 2)); // "3.15"
|
|
@@ -1290,9 +1033,3 @@ console.log(toPrecision(3.14159, 2, "ceil", false)); // "3.15"
|
|
|
1290
1033
|
console.log(toPrecision(3, 2, "none", true)); // "3.00"
|
|
1291
1034
|
console.log(toPrecision(3, 2, "ceil", false)); // "3"
|
|
1292
1035
|
```
|
|
1293
|
-
|
|
1294
|
-
## Notes
|
|
1295
|
-
|
|
1296
|
-
- The 'none' mode behaves the same as 'ceil' mode.
|
|
1297
|
-
- When `forceDecimal` is true, the output will always have the specified number of decimal places, even if the input is an integer.
|
|
1298
|
-
- When `forceDecimal` is false, the output may have fewer decimal places than specified if they are not needed (e.g., for whole numbers).
|