@orbi-wallet/sdk 0.0.1 → 0.0.3
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 +307 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js +25 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# @orbi-wallet/sdk
|
|
2
|
+
|
|
3
|
+
The official SDK for integrating [Orbi Smart Wallet](https://orbiwallet.xyz) into any Stellar dApp.
|
|
4
|
+
|
|
5
|
+
Orbi is a passkey-based smart wallet on Stellar. Users sign transactions with Face ID or Touch ID — no seed phrase, no browser extension. This SDK lets your dApp connect to Orbi wallets and optionally sponsor gas so your users pay nothing.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @orbi-wallet/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### User pays gas (default)
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { OrbiClient } from '@orbi-wallet/sdk';
|
|
23
|
+
|
|
24
|
+
const orbi = new OrbiClient({
|
|
25
|
+
apiUrl: 'https://api.orbiwallet.xyz',
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### dApp sponsors gas (gasless)
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { OrbiClient } from '@orbi-wallet/sdk';
|
|
33
|
+
|
|
34
|
+
const orbi = new OrbiClient({
|
|
35
|
+
apiUrl: 'https://api.orbiwallet.xyz',
|
|
36
|
+
apiKey: 'YOUR_API_KEY', // get this from developers.orbiwallet.xyz
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That one line is the only difference. Everything else — connecting, signing, submitting — works exactly the same. Users see the fee crossed out and "Sponsored by [your app]".
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## How It Works
|
|
45
|
+
|
|
46
|
+
Orbi uses a **redirect flow** — no popups, no browser extensions. Works on all devices including mobile.
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
1. orbi.connect() → redirect user to Orbi to connect wallet
|
|
50
|
+
2. orbi.handleCallback() → on return, get wallet address + passkey ID
|
|
51
|
+
3. orbi.sign() → redirect user to approve transaction with passkey
|
|
52
|
+
4. orbi.handleSignCallback() + orbi.bundle() → submit signed tx to relay
|
|
53
|
+
5. orbi.waitForConfirmation(opId) → wait for on-chain confirmation (~5s)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Full Example
|
|
59
|
+
|
|
60
|
+
### Step 1 — Connect wallet
|
|
61
|
+
|
|
62
|
+
On your "Connect" button:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
orbi.connect({
|
|
66
|
+
redirectUrl: 'https://yourapp.com/callback',
|
|
67
|
+
});
|
|
68
|
+
// navigates to keys.orbiwallet.xyz, then back to redirectUrl?token=...
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
On your `/callback` page:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const wallet = await orbi.handleCallback();
|
|
75
|
+
if (wallet) {
|
|
76
|
+
// { walletAddress, passkeyId, email }
|
|
77
|
+
localStorage.setItem('walletAddress', wallet.walletAddress);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Step 2 — Sign and submit a transaction
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// Redirect user to approve
|
|
85
|
+
orbi.sign({
|
|
86
|
+
walletAddress: localStorage.getItem('walletAddress')!,
|
|
87
|
+
contractId: 'YOUR_CONTRACT_ID',
|
|
88
|
+
functionName: 'transfer',
|
|
89
|
+
argsXdr: ['...', '...'], // XDR-encoded args
|
|
90
|
+
redirectUrl: 'https://yourapp.com/sign-callback',
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
On your `/sign-callback` page:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const result = orbi.handleSignCallback();
|
|
98
|
+
if (!result) return; // user cancelled or came directly to this page
|
|
99
|
+
|
|
100
|
+
const { opId } = await orbi.bundle({
|
|
101
|
+
walletAddress: result.walletAddress,
|
|
102
|
+
quoteId: result.quoteId,
|
|
103
|
+
signedAuthEntryXdr: result.signedAuthEntryXdr,
|
|
104
|
+
contractId: 'YOUR_CONTRACT_ID',
|
|
105
|
+
functionName: 'transfer',
|
|
106
|
+
argsXdr: result.argsXdr,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Wait for on-chain confirmation via SSE
|
|
110
|
+
const status = await orbi.waitForConfirmation(opId);
|
|
111
|
+
if (status.status === 'confirmed') {
|
|
112
|
+
console.log('tx hash:', status.txHash);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## API Reference
|
|
119
|
+
|
|
120
|
+
### `new OrbiClient(config)`
|
|
121
|
+
|
|
122
|
+
| Parameter | Type | Required | Description |
|
|
123
|
+
|---|---|---|---|
|
|
124
|
+
| `apiUrl` | `string` | Yes | Orbi relay URL — use `https://api.orbiwallet.xyz` |
|
|
125
|
+
| `apiKey` | `string` | No | Your developer API key. Enables gas sponsorship. |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### Wallet Connection
|
|
130
|
+
|
|
131
|
+
#### `connect(params)`
|
|
132
|
+
|
|
133
|
+
Redirects the user to Orbi to connect their wallet.
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
orbi.connect({ redirectUrl: 'https://yourapp.com/callback' });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### `handleCallback()`
|
|
140
|
+
|
|
141
|
+
Call on your callback page after `connect()` redirects back. Returns wallet data or `null` if no token in URL.
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const wallet = await orbi.handleCallback();
|
|
145
|
+
// { walletAddress: string, passkeyId: string, email: string } | null
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### Transaction Signing
|
|
151
|
+
|
|
152
|
+
#### `sign(params)`
|
|
153
|
+
|
|
154
|
+
Redirects the user to Orbi to approve a transaction with their passkey.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
orbi.sign({
|
|
158
|
+
walletAddress: string,
|
|
159
|
+
contractId: string,
|
|
160
|
+
functionName: string,
|
|
161
|
+
argsXdr: string[], // XDR-encoded Soroban args
|
|
162
|
+
redirectUrl: string,
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
If `apiKey` is set, the user sees the fee as sponsored — they pay nothing.
|
|
167
|
+
|
|
168
|
+
#### `handleSignCallback()`
|
|
169
|
+
|
|
170
|
+
Call on your sign-callback page. Returns the signed data needed to call `bundle()`, or `null` if nothing to process.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
const result = orbi.handleSignCallback();
|
|
174
|
+
// { signedAuthEntryXdr, quoteId, argsXdr, nativeSacId, walletAddress } | null
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### Relay
|
|
180
|
+
|
|
181
|
+
#### `bundle(params)`
|
|
182
|
+
|
|
183
|
+
Submit a signed operation to the Orbi relay for on-chain execution.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const { opId } = await orbi.bundle({
|
|
187
|
+
walletAddress: string,
|
|
188
|
+
quoteId: string,
|
|
189
|
+
signedAuthEntryXdr: string,
|
|
190
|
+
contractId: string,
|
|
191
|
+
functionName: string,
|
|
192
|
+
argsXdr: string[],
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### `waitForConfirmation(opId)`
|
|
197
|
+
|
|
198
|
+
Wait for the operation to be confirmed or fail. Uses SSE — resolves in ~5s on Stellar.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
const status = await orbi.waitForConfirmation(opId);
|
|
202
|
+
// { opId, status: 'confirmed' | 'failed', txHash: string | null, error: string | null }
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### `getStatus(opId)`
|
|
206
|
+
|
|
207
|
+
One-shot status check (non-blocking alternative to `waitForConfirmation`).
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
const status = await orbi.getStatus(opId);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### Token Management
|
|
216
|
+
|
|
217
|
+
#### `watchAsset(params)`
|
|
218
|
+
|
|
219
|
+
Redirect the user to add a Soroban token to their Orbi wallet.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
orbi.watchAsset({
|
|
223
|
+
contractId: 'TOKEN_CONTRACT_ID',
|
|
224
|
+
redirectUrl: 'https://yourapp.com/callback',
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### `handleWatchAssetCallback()`
|
|
229
|
+
|
|
230
|
+
Call on your callback page after `watchAsset()` redirects back.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
const result = orbi.handleWatchAssetCallback();
|
|
234
|
+
// { contractId: string, added: boolean } | null
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
### Gas Sponsorship (Developer Setup)
|
|
240
|
+
|
|
241
|
+
These methods are for onboarding your dApp to gas sponsorship. You can also do this through the [developer portal](https://developers.orbiwallet.xyz).
|
|
242
|
+
|
|
243
|
+
#### `register(params)`
|
|
244
|
+
|
|
245
|
+
Register a new developer account. Returns a one-time API key — save it immediately.
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
const { apiKey } = await orbi.register({
|
|
249
|
+
developerName: 'My App',
|
|
250
|
+
email: 'you@example.com',
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
#### `setDeployer(deployerPublicKey)`
|
|
255
|
+
|
|
256
|
+
Set the Stellar G... address that will fund gas for your users. Requires `apiKey` in constructor.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
await orbi.setDeployer('GABC...XYZ');
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### `getDeployerBalance()`
|
|
263
|
+
|
|
264
|
+
Check your gas tank balance. Requires `apiKey` in constructor.
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
const { balanceXlm } = await orbi.getDeployerBalance();
|
|
268
|
+
console.log(`${balanceXlm} XLM remaining`);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Gas Sponsorship Setup
|
|
274
|
+
|
|
275
|
+
To sponsor gas for your users:
|
|
276
|
+
|
|
277
|
+
1. **Create a developer account** at [developers.orbiwallet.xyz](https://developers.orbiwallet.xyz) — get your API key
|
|
278
|
+
2. **Create a Stellar keypair** for your gas tank (a regular G... account)
|
|
279
|
+
3. **Fund it with XLM** — each sponsored transaction deducts the exact network fee
|
|
280
|
+
4. **Set the deployer** in the developer portal (or via `setDeployer()`)
|
|
281
|
+
5. **Add `apiKey`** to your `OrbiClient` constructor
|
|
282
|
+
|
|
283
|
+
That's it. Users with Orbi wallets will see fees as sponsored. Users on other wallets are unaffected.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Notes
|
|
288
|
+
|
|
289
|
+
- Works on all browsers and mobile — redirect flow, no popups or extensions
|
|
290
|
+
- Only works with Orbi smart wallets — other Stellar wallets (Freighter, Lobstr) are unaffected
|
|
291
|
+
- Stellar ledger closes every ~5s, so `waitForConfirmation` typically resolves in under 10s
|
|
292
|
+
- XDR arg encoding: use `@stellar/stellar-sdk` to build and encode Soroban contract args
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Links
|
|
297
|
+
|
|
298
|
+
- [Orbi Wallet](https://orbiwallet.xyz)
|
|
299
|
+
- [Developer Portal](https://developers.orbiwallet.xyz)
|
|
300
|
+
- [npm](https://npmjs.com/package/@orbi-wallet/sdk)
|
|
301
|
+
- [GitHub](https://github.com/Novablitz404/orbi-smart-wallet)
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## License
|
|
306
|
+
|
|
307
|
+
MIT
|
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* @orbi/sdk — Orbi Smart Wallet SDK
|
|
3
|
+
* @orbi-wallet/sdk — Orbi Smart Wallet SDK
|
|
4
4
|
*
|
|
5
5
|
* Lets any Stellar dApp integrate Orbi passkey wallets using a redirect flow.
|
|
6
6
|
* Works on all devices and browsers — no popups, no extensions needed.
|
|
@@ -24,10 +24,34 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.OrbiClient = void 0;
|
|
26
26
|
const KEYS_URL = 'https://keys.orbiwallet.xyz';
|
|
27
|
+
function _patchBuffer() {
|
|
28
|
+
if (typeof window === 'undefined')
|
|
29
|
+
return;
|
|
30
|
+
function dv(b) { return new DataView(b.buffer, b.byteOffset, b.byteLength); }
|
|
31
|
+
function def(p, n, fn) {
|
|
32
|
+
if (typeof p[n] !== 'function')
|
|
33
|
+
Object.defineProperty(p, n, { value: fn, writable: true, configurable: true });
|
|
34
|
+
}
|
|
35
|
+
function patch(p) {
|
|
36
|
+
if (!p)
|
|
37
|
+
return;
|
|
38
|
+
def(p, 'readBigInt64BE', function (o = 0) { return dv(this).getBigInt64(o, false); });
|
|
39
|
+
def(p, 'readBigUInt64BE', function (o = 0) { return dv(this).getBigUint64(o, false); });
|
|
40
|
+
def(p, 'readBigInt64LE', function (o = 0) { return dv(this).getBigInt64(o, true); });
|
|
41
|
+
def(p, 'readBigUInt64LE', function (o = 0) { return dv(this).getBigUint64(o, true); });
|
|
42
|
+
def(p, 'writeBigInt64BE', function (v, o = 0) { dv(this).setBigInt64(o, v, false); return o + 8; });
|
|
43
|
+
def(p, 'writeBigUInt64BE', function (v, o = 0) { dv(this).setBigUint64(o, v, false); return o + 8; });
|
|
44
|
+
def(p, 'writeBigInt64LE', function (v, o = 0) { dv(this).setBigInt64(o, v, true); return o + 8; });
|
|
45
|
+
def(p, 'writeBigUInt64LE', function (v, o = 0) { dv(this).setBigUint64(o, v, true); return o + 8; });
|
|
46
|
+
}
|
|
47
|
+
patch(Uint8Array.prototype);
|
|
48
|
+
patch(globalThis.Buffer?.prototype);
|
|
49
|
+
}
|
|
27
50
|
class OrbiClient {
|
|
28
51
|
constructor(config) {
|
|
29
52
|
this.apiUrl = config.apiUrl.replace(/\/$/, '');
|
|
30
53
|
this.apiKey = config.apiKey;
|
|
54
|
+
_patchBuffer();
|
|
31
55
|
}
|
|
32
56
|
authHeaders() {
|
|
33
57
|
return this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {};
|
package/package.json
CHANGED