@velumx/sdk 2.1.0 → 2.3.0

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 CHANGED
@@ -23,238 +23,125 @@ VelumX SDK enables gasless transactions on Stacks blockchain. Users pay transact
23
23
  npm install @velumx/sdk
24
24
  ```
25
25
 
26
- ## Quick Start
26
+ ## Quick Start (Production Pattern)
27
27
 
28
- ### 1. Initialize Client
28
+ ### 1. Initialize Client via Proxy
29
+ For production dApps, initialize the client pointing to your backend proxy to keep your API key secure.
29
30
 
30
31
  ```typescript
31
- import { getVelumXClient } from '@velumx/sdk';
32
-
33
- const velumx = getVelumXClient();
34
- ```
35
-
36
- ### 2. Estimate Fee
32
+ import { VelumXClient } from '@velumx/sdk';
37
33
 
38
- ```typescript
39
- const estimate = await velumx.estimateFee({
40
- estimatedGas: 100000
34
+ const velumx = new VelumXClient({
35
+ paymasterUrl: '/api/velumx/proxy', // Your secure backend proxy
36
+ network: 'mainnet'
41
37
  });
42
-
43
- console.log(`Fee: ${estimate.maxFeeUSDCx} micro-USDCx`);
44
- // Output: Fee: 540000 micro-USDCx (0.54 USDCx)
45
38
  ```
46
39
 
47
- ### 3. Execute Gasless Transaction
40
+ ### 2. Request Sponsorship
41
+ Use the **`.sponsor()`** method to request gas sponsorship while reporting your custom fee for the VelumX Dashboard.
48
42
 
49
43
  ```typescript
50
- import { openContractCall } from '@stacks/connect';
51
- import { Cl } from '@stacks/transactions';
52
-
53
- // Call paymaster contract with sponsored=true
54
- const result = await openContractCall({
55
- contractAddress: 'STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P',
56
- contractName: 'simple-paymaster-v1',
57
- functionName: 'bridge-gasless',
58
- functionArgs: [
59
- Cl.uint(10000000), // 10 USDCx
60
- Cl.buffer(recipientBytes),
61
- Cl.uint(estimate.maxFeeUSDCx),
62
- Cl.principal('STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P'),
63
- Cl.principal('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx')
64
- ],
65
- sponsored: true, // Enable gasless mode
66
- network: 'testnet',
67
- onFinish: async (data) => {
68
- // Submit to relayer for sponsorship
69
- const tx = await velumx.submitRawTransaction(data.txRaw);
70
- console.log(`Transaction: ${tx.txid}`);
71
- }
44
+ // Report your dApp's specific fee and a unique user ID for tracking
45
+ const result = await velumx.sponsor(txRaw, {
46
+ feeAmount: '250000', // 0.25 USDCx (6 decimals)
47
+ userId: 'user_12345'
72
48
  });
73
- ```
74
-
75
- ## How It Works
76
-
77
- ### Architecture
78
-
79
- ```
80
- ┌──────────┐ ┌──────────┐
81
- │ User │ │ Relayer │
82
- └────┬─────┘ └────┬─────┘
83
- │ │
84
- │ 1. Request fee estimate │
85
- ├──────────────────────────────────────────────► │
86
- │ │
87
- │ 2. Return fee in USDCx │
88
- │ ◄──────────────────────────────────────────────┤
89
- │ │
90
- │ 3. Sign transaction (sponsored=true) │
91
- │ │
92
- │ 4. Submit signed transaction │
93
- ├──────────────────────────────────────────────► │
94
- │ │
95
- │ │ 5. Sponsor with STX
96
- │ │ & broadcast
97
- │ │
98
- │ 6. Return transaction ID │
99
- │ ◄──────────────────────────────────────────────┤
100
- │ │
101
- ▼ ▼
102
-
103
- ┌─────────────────────────────────────────────────────┐
104
- │ Stacks Blockchain │
105
- │ │
106
- │ simple-paymaster-v1::bridge-gasless │
107
- │ • Transfer USDCx fee from user to relayer │
108
- │ • Execute core logic (burn/swap) │
109
- │ • Transaction confirmed ✓ │
110
- └─────────────────────────────────────────────────────┘
111
- ```
112
-
113
- ### Fee Calculation
114
49
 
115
- ```
116
- Fee in any SIP-010 token = (Gas Cost in STX × STX/USD Rate × 1.08) / Token/USD Rate
117
-
118
- Example with USDCx:
119
- - Gas: 100,000 units = 1 STX
120
- - STX/USD: $0.50
121
- - USDC/USD: $1.00
122
- - Markup: 8%
123
- - Fee: 1 × $0.50 × 1.08 / $1.00 = 0.54 USDCx
124
-
125
- Example with sBTC:
126
- - Gas: 100,000 units = 1 STX
127
- - STX/USD: $0.50
128
- - BTC/USD: $45,000
129
- - Markup: 8%
130
- - Fee: 1 × $0.50 × 1.08 / $45,000 = 0.000012 BTC (1,200 sats)
131
-
132
- Example with ALEX:
133
- - Gas: 100,000 units = 1 STX
134
- - STX/USD: $0.50
135
- - ALEX/USD: $0.10
136
- - Markup: 8%
137
- - Fee: 1 × $0.50 × 1.08 / $0.10 = 5.4 ALEX
50
+ console.log(`Transaction Sponsored: ${result.txid}`);
138
51
  ```
139
52
 
140
- ## API Reference
53
+ ## Security Best Practice: The Proxy Pattern
141
54
 
142
- ### VelumXClient
143
-
144
- #### Configuration
55
+ **NEVER** expose your `VELUMX_API_KEY` in the browser. Instead, create a simple backend route that injects the key and forwards the request to the VelumX Relayer.
145
56
 
57
+ ### Example Next.js Proxy Route
146
58
  ```typescript
147
- interface NetworkConfig {
148
- coreApiUrl: string; // Stacks API URL
149
- network: 'mainnet' | 'testnet' | 'devnet';
150
- paymasterUrl?: string; // Relayer URL (optional)
151
- }
152
- ```
59
+ // app/api/velumx/proxy/[...path]/route.ts
60
+ export async function POST(req: Request, { params }) {
61
+ const { path } = params;
62
+ const apiKey = process.env.VELUMX_API_KEY; // Securely stored on server
63
+ const targetUrl = `https://relayer.velumx.com/api/v1/${path.join('/')}`;
64
+
65
+ const body = await req.json();
66
+ const response = await fetch(targetUrl, {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json',
70
+ 'x-api-key': apiKey
71
+ },
72
+ body: JSON.stringify(body),
73
+ });
153
74
 
154
- **Default Configuration**:
155
- ```typescript
156
- {
157
- coreApiUrl: 'https://api.testnet.hiro.so',
158
- network: 'testnet',
159
- paymasterUrl: 'https://sgal-relayer.onrender.com/api/v1'
75
+ return Response.json(await response.json());
160
76
  }
161
77
  ```
162
78
 
163
- #### Methods
79
+ ## API Reference
164
80
 
165
- ##### estimateFee()
81
+ ### VelumXClient
166
82
 
167
- Get fee estimate in USDCx for a transaction.
83
+ #### Methods
168
84
 
169
- ```typescript
170
- estimateFee(params: {
171
- estimatedGas: number
172
- }): Promise<FeeEstimate>
173
- ```
85
+ ##### `.sponsor(txHex, options)`
86
+ The recommended method for Stacks-native sponsorship.
174
87
 
175
- **Parameters**:
176
- - `estimatedGas`: Estimated gas units (e.g., 100000)
88
+ - `txHex`: The raw hex string of the signed transaction.
89
+ - `options`:
90
+ - `feeAmount`: (Optional) The specific fee collected by your contract (e.g., "250000").
91
+ - `userId`: (Optional) A unique identifier for your user to enable multi-tenant wallet tracking.
177
92
 
178
- **Returns**:
179
- ```typescript
180
- interface FeeEstimate {
181
- maxFeeUSDCx: string; // Fee in micro-USDCx
182
- estimatedGas: number; // Gas units
183
- stxToUsd?: number; // Exchange rate
184
- markup?: number; // Fee markup (0.08 = 8%)
185
- }
186
- ```
93
+ ##### `.estimateFee(intent)`
94
+ Get a real-time USDCx fee estimation for a transaction intent.
95
+ - `intent`: The transaction details (target, function, args).
187
96
 
188
- **Example**:
189
- ```typescript
190
- const estimate = await velumx.estimateFee({
191
- estimatedGas: 100000
192
- });
97
+ ##### `.submitIntent(signedIntent)`
98
+ Submit a SIP-018 signed intent for legacy smart-wallet sponsorship.
193
99
 
194
- console.log(`Fee: ${estimate.maxFeeUSDCx} micro-USDCx`);
195
- // Fee: 540000 micro-USDCx (0.54 USDCx)
196
- ```
100
+ ## Use Cases
197
101
 
198
- ##### submitRawTransaction()
102
+ ### 1. Gasless Token Transfer (New in v2.3.0)
199
103
 
200
- Submit a signed transaction for sponsorship.
104
+ Transfer any SIP-010 token (like USDCx) between wallets without needing STX.
201
105
 
202
106
  ```typescript
203
- submitRawTransaction(txRaw: string): Promise<TransactionResult>
204
- ```
205
-
206
- **Parameters**:
207
- - `txRaw`: Hex-encoded signed transaction from wallet
107
+ import { getVelumXClient } from '@velumx/sdk';
208
108
 
209
- **Returns**:
210
- ```typescript
211
- interface TransactionResult {
212
- txid: string; // Transaction ID
213
- status: string; // Status (pending/success/failed)
109
+ async function sendTokens(token: string, amount: string, recipient: string) {
110
+ const velumx = getVelumXClient();
111
+
112
+ // 1. Estimate fee
113
+ const estimate = await velumx.estimateFee({ estimatedGas: 100000 });
114
+
115
+ // 2. Perform gasless transfer
116
+ await velumx.transferGasless({
117
+ token: 'SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx',
118
+ amount: '10000000', // 10 USDCx
119
+ recipient: 'SP123...',
120
+ feeUsdcx: estimate.maxFeeUSDCx,
121
+ onFinish: (data) => console.log(`Transfer TX: ${data.txid}`)
122
+ });
214
123
  }
215
124
  ```
216
125
 
217
- **Example**:
218
- ```typescript
219
- const result = await velumx.submitRawTransaction(data.txRaw);
220
- console.log(`Transaction ID: ${result.txid}`);
221
- ```
222
-
223
- ##### sponsorTransaction()
126
+ ### 2. Universal Gasless Action (New in v2.3.0)
224
127
 
225
- High-level helper to make any transaction gasless.
128
+ Make any contract call gasless by using the Universal Executor trait.
226
129
 
227
130
  ```typescript
228
- sponsorTransaction(params: {
229
- transaction: any;
230
- network: 'mainnet' | 'testnet';
231
- }): Promise<any>
232
- ```
233
-
234
- **Parameters**:
235
- - `transaction`: Unsigned Stacks transaction
236
- - `network`: Target network
237
-
238
- **Returns**: Transaction with `sponsored: true` flag
239
-
240
- **Example**:
241
- ```typescript
242
- import { makeContractCall } from '@stacks/transactions';
243
-
244
- const unsignedTx = await makeContractCall({...});
245
-
246
- const sponsored = await velumx.sponsorTransaction({
247
- transaction: unsignedTx,
248
- network: 'testnet'
249
- });
250
-
251
- // User signs and broadcasts
252
- const result = await openContractCall(sponsored);
131
+ async function callDeFiProtocol() {
132
+ const velumx = getVelumXClient();
133
+
134
+ await velumx.executeGasless({
135
+ target: 'SP...YOUR_PROTOCOL_CONTRACT',
136
+ actionId: '0x...', // Hex hash of the intended action
137
+ param: '100', // Numeric parameter
138
+ feeUsdcx: '250000',
139
+ onFinish: (data) => console.log(`Action TX: ${data.txid}`)
140
+ });
141
+ }
253
142
  ```
254
143
 
255
- ## Use Cases
256
-
257
- ### 1. Gasless Bridge
144
+ ### 3. Gasless Bridge
258
145
 
259
146
  Bridge USDC from Ethereum to Stacks without needing STX.
260
147
 
@@ -277,18 +164,18 @@ async function gaslessBridge(amount: string, recipient: string) {
277
164
 
278
165
  // 3. Execute gasless bridge
279
166
  const result = await openContractCall({
280
- contractAddress: 'STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P',
167
+ contractAddress: 'SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW',
281
168
  contractName: 'simple-paymaster-v1',
282
169
  functionName: 'bridge-gasless',
283
170
  functionArgs: [
284
171
  Cl.uint(parseUnits(amount, 6)),
285
172
  Cl.buffer(recipientBytes),
286
173
  Cl.uint(estimate.maxFeeUSDCx),
287
- Cl.principal('STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P'),
288
- Cl.principal('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx')
174
+ Cl.principal('SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW'),
175
+ Cl.principal('SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx')
289
176
  ],
290
177
  sponsored: true,
291
- network: 'testnet',
178
+ network: 'mainnet',
292
179
  onFinish: async (data) => {
293
180
  const tx = await velumx.submitRawTransaction(data.txRaw);
294
181
  console.log(`Bridge transaction: ${tx.txid}`);
@@ -328,7 +215,7 @@ async function gaslessSwap(
328
215
 
329
216
  // 2. Execute gasless swap
330
217
  const result = await openContractCall({
331
- contractAddress: 'STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P',
218
+ contractAddress: 'SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW',
332
219
  contractName: 'simple-paymaster-v1',
333
220
  functionName: 'swap-gasless',
334
221
  functionArgs: [
@@ -337,11 +224,11 @@ async function gaslessSwap(
337
224
  Cl.uint(parseUnits(amountIn, 6)),
338
225
  Cl.uint(parseUnits(minOut, 6)),
339
226
  Cl.uint(estimate.maxFeeUSDCx),
340
- Cl.principal('STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P'),
341
- Cl.principal('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx')
227
+ Cl.principal('SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW'),
228
+ Cl.principal('SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx')
342
229
  ],
343
230
  sponsored: true,
344
- network: 'testnet',
231
+ network: 'mainnet',
345
232
  onFinish: async (data) => {
346
233
  const tx = await velumx.submitRawTransaction(data.txRaw);
347
234
  console.log(`Swap transaction: ${tx.txid}`);
@@ -374,7 +261,7 @@ async function customGaslessTransaction() {
374
261
  // More args...
375
262
  ],
376
263
  sponsored: true, // Enable gasless
377
- network: 'testnet',
264
+ network: 'mainnet',
378
265
  onFinish: async (data) => {
379
266
  const tx = await velumx.submitRawTransaction(data.txRaw);
380
267
  console.log(`Transaction: ${tx.txid}`);
@@ -401,18 +288,18 @@ async function gaslessWithSBTC(amount: string) {
401
288
 
402
289
  // 3. Execute with sBTC as fee token
403
290
  const result = await openContractCall({
404
- contractAddress: 'STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P',
291
+ contractAddress: 'SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW',
405
292
  contractName: 'simple-paymaster-v1',
406
293
  functionName: 'bridge-gasless',
407
294
  functionArgs: [
408
295
  Cl.uint(parseUnits(amount, 6)),
409
296
  Cl.buffer(recipientBytes),
410
297
  Cl.uint(feeInSBTC), // Fee in sBTC
411
- Cl.principal('STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P'),
298
+ Cl.principal('SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW'),
412
299
  Cl.principal('SM3KNVZS30WM7F89SXKVVFY4SN9RMPZZ9FX929N0V.sbtc') // sBTC token
413
300
  ],
414
301
  sponsored: true,
415
- network: 'testnet',
302
+ network: 'mainnet',
416
303
  onFinish: async (data) => {
417
304
  const tx = await velumx.submitRawTransaction(data.txRaw);
418
305
  console.log(`Transaction: ${tx.txid}`);
@@ -442,18 +329,18 @@ async function gaslessWithALEX(amount: string) {
442
329
  const feeInALEX = convertToALEX(estimate.maxFeeUSDCx);
443
330
 
444
331
  const result = await openContractCall({
445
- contractAddress: 'STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P',
332
+ contractAddress: 'SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW',
446
333
  contractName: 'simple-paymaster-v1',
447
334
  functionName: 'bridge-gasless',
448
335
  functionArgs: [
449
336
  Cl.uint(parseUnits(amount, 6)),
450
337
  Cl.buffer(recipientBytes),
451
338
  Cl.uint(feeInALEX), // Fee in ALEX
452
- Cl.principal('STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P'),
339
+ Cl.principal('SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW'),
453
340
  Cl.principal('ALEX_TOKEN_ADDRESS') // ALEX token
454
341
  ],
455
342
  sponsored: true,
456
- network: 'testnet',
343
+ network: 'mainnet',
457
344
  onFinish: async (data) => {
458
345
  const tx = await velumx.submitRawTransaction(data.txRaw);
459
346
  console.log(`Transaction: ${tx.txid}`);
@@ -495,7 +382,7 @@ VelumX accepts ANY SIP-010 token for gas fees. The paymaster contract uses the `
495
382
 
496
383
  | Token | Contract Address | Decimals | Use Case |
497
384
  |-------|-----------------|----------|----------|
498
- | USDCx | `ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx` | 6 | Stablecoin fees |
385
+ | USDCx | `SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx` | 6 | Stablecoin fees |
499
386
  | sBTC | `SM3KNVZS30WM7F89SXKVVFY4SN9RMPZZ9FX929N0V.sbtc` | 8 | Bitcoin fees |
500
387
  | ALEX | `ALEX_TOKEN_ADDRESS` | 6 | DeFi token fees |
501
388
  | STX | Native | 6 | Native token fees |
@@ -540,13 +427,13 @@ const feeInSBTC = await calculateFeeInToken(estimate.maxFeeUSDCx, 'sBTC');
540
427
 
541
428
  ```bash
542
429
  # Frontend (.env.local)
543
- NEXT_PUBLIC_STACKS_NETWORK=testnet
544
- NEXT_PUBLIC_STACKS_API_URL=https://api.testnet.hiro.so
545
- NEXT_PUBLIC_VELUMX_RELAYER_URL=https://sgal-relayer.onrender.com/api/v1
430
+ NEXT_PUBLIC_STACKS_NETWORK=mainnet
431
+ NEXT_PUBLIC_STACKS_API_URL=https://api.mainnet.hiro.so
432
+ NEXT_PUBLIC_VELUMX_RELAYER_URL=https://your-relayer-proxy.com
546
433
 
547
434
  # Contracts
548
- NEXT_PUBLIC_STACKS_PAYMASTER_ADDRESS=STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P.simple-paymaster-v1
549
- NEXT_PUBLIC_STACKS_USDCX_ADDRESS=ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx
435
+ NEXT_PUBLIC_STACKS_PAYMASTER_ADDRESS=SP...YOUR_PAYMASTER_ADDRESS
436
+ NEXT_PUBLIC_STACKS_USDCX_ADDRESS=SP...YOUR_USDCX_ADDRESS
550
437
  ```
551
438
 
552
439
  ### Network Configuration
@@ -635,14 +522,14 @@ describe('VelumX SDK', () => {
635
522
 
636
523
  **Simple Paymaster**
637
524
  ```
638
- Address: STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P.simple-paymaster-v1
639
- Network: Stacks Testnet
640
- Explorer: https://explorer.hiro.so/txid/0x90c134205b04599405e3cccae6c86ed496ae2d81ef0392970e2c9a7acd3b2138?chain=testnet
525
+ Address: SPKYNF473GQ1V0WWCF24TV7ZR1WYAKTC7AM8QGBW.simple-paymaster-v1
526
+ Network: Stacks Mainnet
527
+ Explorer: https://explorer.hiro.so/txid/[TRANSACTION_ID]?chain=mainnet
641
528
  ```
642
529
 
643
530
  **USDCx Token**
644
531
  ```
645
- Address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx
532
+ Address: SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx
646
533
  Standard: SIP-010
647
534
  Decimals: 6
648
535
  ```
@@ -671,7 +558,7 @@ Status: https://sgal-relayer.onrender.com/api/v1/health
671
558
  **A:** Any Stacks wallet (Xverse, Leather, Hiro) that supports sponsored transactions.
672
559
 
673
560
  ### Q: Can I use this in production?
674
- **A:** Currently on testnet. Mainnet launch pending security audit.
561
+ **A:** Yes! VelumX is fully functional on Stacks Mainnet.
675
562
 
676
563
  ### Q: How do I get an API key?
677
564
  **A:** Visit [https://velum-x-ssum.vercel.app](https://velum-x-ssum.vercel.app) to sign up and generate API keys.
@@ -24,6 +24,22 @@ export interface SwapParams {
24
24
  onFinish?: (data: any) => void;
25
25
  onCancel?: () => void;
26
26
  }
27
+ export interface TransferParams {
28
+ token: string;
29
+ amount: string;
30
+ recipient: string;
31
+ feeUsdcx: string;
32
+ onFinish?: (data: any) => void;
33
+ onCancel?: () => void;
34
+ }
35
+ export interface ExecuteParams {
36
+ target: string;
37
+ actionId: string;
38
+ param: string;
39
+ feeUsdcx: string;
40
+ onFinish?: (data: any) => void;
41
+ onCancel?: () => void;
42
+ }
27
43
  export declare class SimplePaymaster {
28
44
  private config;
29
45
  constructor(config: SimplePaymasterConfig);
@@ -35,6 +51,14 @@ export declare class SimplePaymaster {
35
51
  * Execute gasless swap
36
52
  */
37
53
  swapGasless(params: SwapParams): Promise<void>;
54
+ /**
55
+ * Execute gasless token transfer
56
+ */
57
+ transferGasless(params: TransferParams): Promise<void>;
58
+ /**
59
+ * Execute universal gasless action
60
+ */
61
+ executeGasless(params: ExecuteParams): Promise<void>;
38
62
  /**
39
63
  * Estimate fee for gasless transaction
40
64
  */
@@ -63,6 +63,58 @@ class SimplePaymaster {
63
63
  onCancel: params.onCancel || (() => { }),
64
64
  });
65
65
  }
66
+ /**
67
+ * Execute gasless token transfer
68
+ */
69
+ async transferGasless(params) {
70
+ const [contractAddress, contractName] = this.config.paymasterContract.split('.');
71
+ const [tokenAddress, tokenName] = params.token.split('.');
72
+ const functionArgs = [
73
+ (0, transactions_1.contractPrincipalCV)(tokenAddress, tokenName),
74
+ (0, transactions_1.uintCV)(params.amount),
75
+ (0, transactions_1.principalCV)(params.recipient),
76
+ (0, transactions_1.uintCV)(params.feeUsdcx),
77
+ (0, transactions_1.principalCV)(this.config.relayerAddress),
78
+ (0, transactions_1.contractPrincipalCV)(this.config.usdcxContract.split('.')[0], this.config.usdcxContract.split('.')[1])
79
+ ];
80
+ await (0, connect_1.openContractCall)({
81
+ contractAddress,
82
+ contractName,
83
+ functionName: 'transfer-gasless',
84
+ functionArgs,
85
+ network: this.config.network,
86
+ sponsored: true,
87
+ postConditionMode: transactions_1.PostConditionMode.Allow,
88
+ onFinish: params.onFinish || (() => { }),
89
+ onCancel: params.onCancel || (() => { }),
90
+ });
91
+ }
92
+ /**
93
+ * Execute universal gasless action
94
+ */
95
+ async executeGasless(params) {
96
+ const [contractAddress, contractName] = this.config.paymasterContract.split('.');
97
+ const [targetAddress, targetName] = params.target.split('.');
98
+ const functionArgs = [
99
+ (0, transactions_1.contractPrincipalCV)(targetAddress, targetName),
100
+ (0, transactions_1.bufferCV)(Buffer.from(params.actionId.replace(/^0x/, ''), 'hex')),
101
+ (0, transactions_1.uintCV)(params.param),
102
+ (0, transactions_1.uintCV)(params.feeUsdcx),
103
+ (0, transactions_1.principalCV)(this.config.relayerAddress),
104
+ (0, transactions_1.contractPrincipalCV)(this.config.usdcxContract.split('.')[0], this.config.usdcxContract.split('.')[1])
105
+ ];
106
+ await (0, connect_1.openContractCall)({
107
+ contractAddress,
108
+ contractName,
109
+ functionName: 'execute-gasless',
110
+ functionArgs,
111
+ network: this.config.network,
112
+ sponsored: true,
113
+ postConditionMode: transactions_1.PostConditionMode.Allow,
114
+ onFinish: params.onFinish || (() => { }),
115
+ onCancel: params.onCancel || (() => { }),
116
+ });
117
+ }
66
118
  /**
67
119
  * Estimate fee for gasless transaction
68
120
  */
@@ -1,10 +1,10 @@
1
- import { SignedIntent, NetworkConfig } from './types';
1
+ import { SignedIntent, NetworkConfig, SponsorshipOptions } from './types';
2
2
  export declare class VelumXClient {
3
3
  private config;
4
4
  private relayerUrl;
5
5
  constructor(config: NetworkConfig);
6
6
  /**
7
- * Get a fee estimation from the SGAL relayer for a specific intent
7
+ * Get a fee estimation from the relayer for a specific intent
8
8
  */
9
9
  estimateFee(intent: any): Promise<{
10
10
  maxFeeUSDCx: string;
@@ -17,10 +17,19 @@ export declare class VelumXClient {
17
17
  txid: string;
18
18
  status: string;
19
19
  }>;
20
+ /**
21
+ * [New Recommended Method] Request sponsorship for a Stacks transaction
22
+ * @param txHex The raw transaction hex
23
+ * @param options Metadata like developer-reported fee and userId
24
+ */
25
+ sponsor(txHex: string, options?: SponsorshipOptions): Promise<{
26
+ txid: string;
27
+ status: string;
28
+ }>;
20
29
  /**
21
30
  * Submit a raw Stacks transaction hex for native sponsorship
22
31
  */
23
- submitRawTransaction(txHex: string): Promise<{
32
+ submitRawTransaction(txHex: string, options?: SponsorshipOptions): Promise<{
24
33
  txid: string;
25
34
  status: string;
26
35
  }>;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VelumXClient = void 0;
4
4
  class VelumXClient {
5
5
  constructor(config) {
6
- if (!config.apiKey) {
6
+ if (!config.apiKey && !config.paymasterUrl?.includes('/api/velumx/proxy')) {
7
7
  throw new Error("VelumX Client Error: API Key is required. Please obtain your key from the VelumX Developer Dashboard.");
8
8
  }
9
9
  this.config = config;
@@ -11,12 +11,12 @@ class VelumXClient {
11
11
  this.relayerUrl = config.paymasterUrl || 'https://relayer.velumx.com/api/v1';
12
12
  }
13
13
  /**
14
- * Get a fee estimation from the SGAL relayer for a specific intent
14
+ * Get a fee estimation from the relayer for a specific intent
15
15
  */
16
16
  async estimateFee(intent) {
17
17
  try {
18
18
  const headers = { 'Content-Type': 'application/json' };
19
- if (this.config.apiKey) {
19
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
20
20
  headers['x-api-key'] = this.config.apiKey;
21
21
  }
22
22
  const response = await fetch(`${this.relayerUrl}/estimate`, {
@@ -41,7 +41,7 @@ class VelumXClient {
41
41
  async submitIntent(signedIntent) {
42
42
  try {
43
43
  const headers = { 'Content-Type': 'application/json' };
44
- if (this.config.apiKey) {
44
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
45
45
  headers['x-api-key'] = this.config.apiKey;
46
46
  }
47
47
  const response = await fetch(`${this.relayerUrl}/sponsor`, {
@@ -60,19 +60,31 @@ class VelumXClient {
60
60
  throw error;
61
61
  }
62
62
  }
63
+ /**
64
+ * [New Recommended Method] Request sponsorship for a Stacks transaction
65
+ * @param txHex The raw transaction hex
66
+ * @param options Metadata like developer-reported fee and userId
67
+ */
68
+ async sponsor(txHex, options) {
69
+ return this.submitRawTransaction(txHex, options);
70
+ }
63
71
  /**
64
72
  * Submit a raw Stacks transaction hex for native sponsorship
65
73
  */
66
- async submitRawTransaction(txHex) {
74
+ async submitRawTransaction(txHex, options) {
67
75
  try {
68
76
  const headers = { 'Content-Type': 'application/json' };
69
- if (this.config.apiKey) {
77
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
70
78
  headers['x-api-key'] = this.config.apiKey;
71
79
  }
72
80
  const response = await fetch(`${this.relayerUrl}/broadcast`, {
73
81
  method: 'POST',
74
82
  headers,
75
- body: JSON.stringify({ txHex })
83
+ body: JSON.stringify({
84
+ txHex,
85
+ userId: options?.userId,
86
+ feeAmount: options?.feeAmount
87
+ })
76
88
  });
77
89
  if (!response.ok) {
78
90
  const errData = await response.json().catch(() => ({ error: 'Unknown error' }));
package/dist/types.d.ts CHANGED
@@ -14,3 +14,7 @@ export interface NetworkConfig {
14
14
  paymasterUrl?: string;
15
15
  apiKey?: string;
16
16
  }
17
+ export interface SponsorshipOptions {
18
+ userId?: string;
19
+ feeAmount?: string;
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velumx/sdk",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "VelumX Gas Abstraction Layer SDK for dApps",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,6 +38,24 @@ export interface SwapParams {
38
38
  onCancel?: () => void;
39
39
  }
40
40
 
41
+ export interface TransferParams {
42
+ token: string; // Contract principal of token to transfer (e.g. 'SP...usdcx')
43
+ amount: string; // Amount in micro units
44
+ recipient: string; // Stacks address
45
+ feeUsdcx: string; // Fee in micro units
46
+ onFinish?: (data: any) => void;
47
+ onCancel?: () => void;
48
+ }
49
+
50
+ export interface ExecuteParams {
51
+ target: string; // Contract principal implementing executor-trait-v1
52
+ actionId: string; // 32-byte hex string (e.g., hash of action)
53
+ param: string; // Numeric parameter for the action
54
+ feeUsdcx: string; // Fee in micro units
55
+ onFinish?: (data: any) => void;
56
+ onCancel?: () => void;
57
+ }
58
+
41
59
  export class SimplePaymaster {
42
60
  private config: SimplePaymasterConfig;
43
61
 
@@ -104,6 +122,64 @@ export class SimplePaymaster {
104
122
  });
105
123
  }
106
124
 
125
+ /**
126
+ * Execute gasless token transfer
127
+ */
128
+ async transferGasless(params: TransferParams): Promise<void> {
129
+ const [contractAddress, contractName] = this.config.paymasterContract.split('.');
130
+ const [tokenAddress, tokenName] = params.token.split('.');
131
+
132
+ const functionArgs: ClarityValue[] = [
133
+ contractPrincipalCV(tokenAddress, tokenName),
134
+ uintCV(params.amount),
135
+ principalCV(params.recipient),
136
+ uintCV(params.feeUsdcx),
137
+ principalCV(this.config.relayerAddress),
138
+ contractPrincipalCV(this.config.usdcxContract.split('.')[0], this.config.usdcxContract.split('.')[1])
139
+ ];
140
+
141
+ await openContractCall({
142
+ contractAddress,
143
+ contractName,
144
+ functionName: 'transfer-gasless',
145
+ functionArgs,
146
+ network: this.config.network,
147
+ sponsored: true,
148
+ postConditionMode: PostConditionMode.Allow,
149
+ onFinish: params.onFinish || (() => {}),
150
+ onCancel: params.onCancel || (() => {}),
151
+ });
152
+ }
153
+
154
+ /**
155
+ * Execute universal gasless action
156
+ */
157
+ async executeGasless(params: ExecuteParams): Promise<void> {
158
+ const [contractAddress, contractName] = this.config.paymasterContract.split('.');
159
+ const [targetAddress, targetName] = params.target.split('.');
160
+
161
+ const functionArgs: ClarityValue[] = [
162
+ contractPrincipalCV(targetAddress, targetName),
163
+ bufferCV(Buffer.from(params.actionId.replace(/^0x/, ''), 'hex')),
164
+ uintCV(params.param),
165
+ uintCV(params.feeUsdcx),
166
+ principalCV(this.config.relayerAddress),
167
+ contractPrincipalCV(this.config.usdcxContract.split('.')[0], this.config.usdcxContract.split('.')[1])
168
+ ];
169
+
170
+ await openContractCall({
171
+ contractAddress,
172
+ contractName,
173
+ functionName: 'execute-gasless',
174
+ functionArgs,
175
+ network: this.config.network,
176
+ sponsored: true,
177
+ postConditionMode: PostConditionMode.Allow,
178
+ onFinish: params.onFinish || (() => {}),
179
+ onCancel: params.onCancel || (() => {}),
180
+ });
181
+ }
182
+
107
183
  /**
108
184
  * Estimate fee for gasless transaction
109
185
  */
@@ -1,11 +1,11 @@
1
- import { SignedIntent, NetworkConfig } from './types';
1
+ import { SignedIntent, NetworkConfig, SponsorshipOptions } from './types';
2
2
 
3
3
  export class VelumXClient {
4
4
  private config: NetworkConfig;
5
5
  private relayerUrl: string;
6
6
 
7
7
  constructor(config: NetworkConfig) {
8
- if (!config.apiKey) {
8
+ if (!config.apiKey && !config.paymasterUrl?.includes('/api/velumx/proxy')) {
9
9
  throw new Error("VelumX Client Error: API Key is required. Please obtain your key from the VelumX Developer Dashboard.");
10
10
  }
11
11
  this.config = config;
@@ -14,12 +14,12 @@ export class VelumXClient {
14
14
  }
15
15
 
16
16
  /**
17
- * Get a fee estimation from the SGAL relayer for a specific intent
17
+ * Get a fee estimation from the relayer for a specific intent
18
18
  */
19
19
  public async estimateFee(intent: any): Promise<{ maxFeeUSDCx: string, estimatedGas: number }> {
20
20
  try {
21
21
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
22
- if (this.config.apiKey) {
22
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
23
23
  headers['x-api-key'] = this.config.apiKey;
24
24
  }
25
25
 
@@ -47,7 +47,7 @@ export class VelumXClient {
47
47
  public async submitIntent(signedIntent: SignedIntent): Promise<{ txid: string, status: string }> {
48
48
  try {
49
49
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
50
- if (this.config.apiKey) {
50
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
51
51
  headers['x-api-key'] = this.config.apiKey;
52
52
  }
53
53
 
@@ -69,20 +69,33 @@ export class VelumXClient {
69
69
  }
70
70
  }
71
71
 
72
+ /**
73
+ * [New Recommended Method] Request sponsorship for a Stacks transaction
74
+ * @param txHex The raw transaction hex
75
+ * @param options Metadata like developer-reported fee and userId
76
+ */
77
+ public async sponsor(txHex: string, options?: SponsorshipOptions): Promise<{ txid: string, status: string }> {
78
+ return this.submitRawTransaction(txHex, options);
79
+ }
80
+
72
81
  /**
73
82
  * Submit a raw Stacks transaction hex for native sponsorship
74
83
  */
75
- public async submitRawTransaction(txHex: string): Promise<{ txid: string, status: string }> {
84
+ public async submitRawTransaction(txHex: string, options?: SponsorshipOptions): Promise<{ txid: string, status: string }> {
76
85
  try {
77
86
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
78
- if (this.config.apiKey) {
87
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
79
88
  headers['x-api-key'] = this.config.apiKey;
80
89
  }
81
90
 
82
91
  const response = await fetch(`${this.relayerUrl}/broadcast`, {
83
92
  method: 'POST',
84
93
  headers,
85
- body: JSON.stringify({ txHex })
94
+ body: JSON.stringify({
95
+ txHex,
96
+ userId: options?.userId,
97
+ feeAmount: options?.feeAmount
98
+ })
86
99
  });
87
100
 
88
101
  if (!response.ok) {
package/src/types.ts CHANGED
@@ -15,6 +15,11 @@ export interface SignedIntent extends WalletIntent {
15
15
  export interface NetworkConfig {
16
16
  coreApiUrl: string;
17
17
  network: 'mainnet' | 'testnet' | 'devnet';
18
- paymasterUrl?: string; // URL for the SGAL relayer service
19
- apiKey?: string; // SGAL API Key
18
+ paymasterUrl?: string; // URL for the VelumX relayer service
19
+ apiKey?: string; // VelumX API Key
20
+ }
21
+
22
+ export interface SponsorshipOptions {
23
+ userId?: string;
24
+ feeAmount?: string;
20
25
  }