@velumx/sdk 2.0.1 → 2.2.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
@@ -113,13 +113,28 @@ const result = await openContractCall({
113
113
  ### Fee Calculation
114
114
 
115
115
  ```
116
- Fee in USDCx = (Gas Cost in STX × STX/USD Rate × 1.08) / USDC/USD Rate
116
+ Fee in any SIP-010 token = (Gas Cost in STX × STX/USD Rate × 1.08) / Token/USD Rate
117
117
 
118
- Example:
118
+ Example with USDCx:
119
119
  - Gas: 100,000 units = 1 STX
120
120
  - STX/USD: $0.50
121
+ - USDC/USD: $1.00
121
122
  - Markup: 8%
122
- - Fee: 1 × $0.50 × 1.08 = $0.54 = 0.54 USDCx
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
123
138
  ```
124
139
 
125
140
  ## API Reference
@@ -368,6 +383,85 @@ async function customGaslessTransaction() {
368
383
  }
369
384
  ```
370
385
 
386
+ ### 4. Using Different Fee Tokens
387
+
388
+ Pay fees in sBTC, ALEX, or any SIP-010 token.
389
+
390
+ ```typescript
391
+ async function gaslessWithSBTC(amount: string) {
392
+ const velumx = getVelumXClient();
393
+
394
+ // 1. Estimate fee (returns USDCx equivalent)
395
+ const estimate = await velumx.estimateFee({
396
+ estimatedGas: 100000
397
+ });
398
+
399
+ // 2. Convert fee to sBTC (example: 0.54 USDCx → 0.000012 BTC)
400
+ const feeInSBTC = convertToSBTC(estimate.maxFeeUSDCx);
401
+
402
+ // 3. Execute with sBTC as fee token
403
+ const result = await openContractCall({
404
+ contractAddress: 'STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P',
405
+ contractName: 'simple-paymaster-v1',
406
+ functionName: 'bridge-gasless',
407
+ functionArgs: [
408
+ Cl.uint(parseUnits(amount, 6)),
409
+ Cl.buffer(recipientBytes),
410
+ Cl.uint(feeInSBTC), // Fee in sBTC
411
+ Cl.principal('STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P'),
412
+ Cl.principal('SM3KNVZS30WM7F89SXKVVFY4SN9RMPZZ9FX929N0V.sbtc') // sBTC token
413
+ ],
414
+ sponsored: true,
415
+ network: 'testnet',
416
+ onFinish: async (data) => {
417
+ const tx = await velumx.submitRawTransaction(data.txRaw);
418
+ console.log(`Transaction: ${tx.txid}`);
419
+ }
420
+ });
421
+ }
422
+
423
+ // Helper: Convert USDCx fee to sBTC
424
+ function convertToSBTC(feeInUSDCx: string): string {
425
+ // Example conversion (fetch real rates from API)
426
+ const usdcAmount = Number(feeInUSDCx) / 1_000_000; // 0.54 USDC
427
+ const btcPrice = 45000; // $45,000 per BTC
428
+ const btcAmount = usdcAmount / btcPrice; // 0.000012 BTC
429
+ const satoshis = Math.ceil(btcAmount * 100_000_000); // 1,200 sats
430
+ return satoshis.toString();
431
+ }
432
+
433
+ // Using ALEX token
434
+ async function gaslessWithALEX(amount: string) {
435
+ const velumx = getVelumXClient();
436
+
437
+ const estimate = await velumx.estimateFee({
438
+ estimatedGas: 100000
439
+ });
440
+
441
+ // Convert to ALEX (example: 0.54 USDCx → 5.4 ALEX)
442
+ const feeInALEX = convertToALEX(estimate.maxFeeUSDCx);
443
+
444
+ const result = await openContractCall({
445
+ contractAddress: 'STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P',
446
+ contractName: 'simple-paymaster-v1',
447
+ functionName: 'bridge-gasless',
448
+ functionArgs: [
449
+ Cl.uint(parseUnits(amount, 6)),
450
+ Cl.buffer(recipientBytes),
451
+ Cl.uint(feeInALEX), // Fee in ALEX
452
+ Cl.principal('STKYNF473GQ1V0WWCF24TV7ZR1WYAKTC79V25E3P'),
453
+ Cl.principal('ALEX_TOKEN_ADDRESS') // ALEX token
454
+ ],
455
+ sponsored: true,
456
+ network: 'testnet',
457
+ onFinish: async (data) => {
458
+ const tx = await velumx.submitRawTransaction(data.txRaw);
459
+ console.log(`Transaction: ${tx.txid}`);
460
+ }
461
+ });
462
+ }
463
+ ```
464
+
371
465
  ## Smart Contract Integration
372
466
 
373
467
  To make your contract gasless-compatible, accept a fee parameter and transfer it to the relayer:
@@ -393,6 +487,55 @@ To make your contract gasless-compatible, accept a fee parameter and transfer it
393
487
 
394
488
  ## Configuration
395
489
 
490
+ ### Supported Fee Tokens
491
+
492
+ VelumX accepts ANY SIP-010 token for gas fees. The paymaster contract uses the `<sip-010-trait>` parameter for universal compatibility.
493
+
494
+ **Popular Tokens:**
495
+
496
+ | Token | Contract Address | Decimals | Use Case |
497
+ |-------|-----------------|----------|----------|
498
+ | USDCx | `ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx` | 6 | Stablecoin fees |
499
+ | sBTC | `SM3KNVZS30WM7F89SXKVVFY4SN9RMPZZ9FX929N0V.sbtc` | 8 | Bitcoin fees |
500
+ | ALEX | `ALEX_TOKEN_ADDRESS` | 6 | DeFi token fees |
501
+ | STX | Native | 6 | Native token fees |
502
+
503
+ **Exchange Rate Calculation:**
504
+
505
+ ```typescript
506
+ // Fetch real-time exchange rates
507
+ async function calculateFeeInToken(
508
+ feeInUSDCx: string,
509
+ targetToken: 'sBTC' | 'ALEX' | 'STX'
510
+ ): Promise<string> {
511
+ const usdcAmount = Number(feeInUSDCx) / 1_000_000;
512
+
513
+ // Fetch rates from price oracle or API
514
+ const rates = await fetchExchangeRates();
515
+
516
+ switch (targetToken) {
517
+ case 'sBTC':
518
+ const btcAmount = usdcAmount / rates.BTC_USD;
519
+ return Math.ceil(btcAmount * 100_000_000).toString(); // Convert to satoshis
520
+
521
+ case 'ALEX':
522
+ const alexAmount = usdcAmount / rates.ALEX_USD;
523
+ return Math.ceil(alexAmount * 1_000_000).toString(); // Convert to micro-ALEX
524
+
525
+ case 'STX':
526
+ const stxAmount = usdcAmount / rates.STX_USD;
527
+ return Math.ceil(stxAmount * 1_000_000).toString(); // Convert to micro-STX
528
+
529
+ default:
530
+ return feeInUSDCx;
531
+ }
532
+ }
533
+
534
+ // Example usage
535
+ const estimate = await velumx.estimateFee({ estimatedGas: 100000 });
536
+ const feeInSBTC = await calculateFeeInToken(estimate.maxFeeUSDCx, 'sBTC');
537
+ ```
538
+
396
539
  ### Environment Variables
397
540
 
398
541
  ```bash
@@ -513,10 +656,13 @@ Status: https://sgal-relayer.onrender.com/api/v1/health
513
656
  ## FAQ
514
657
 
515
658
  ### Q: Do users need STX?
516
- **A:** No! Users only need USDCx. The relayer pays STX fees.
659
+ **A:** No! Users only need any SIP-010 token (USDCx, sBTC, ALEX, etc.). The relayer pays STX fees.
660
+
661
+ ### Q: What tokens can I use for fees?
662
+ **A:** Any SIP-010 compliant token! Popular options include USDCx, sBTC, ALEX, and STX. The paymaster contract uses the `<sip-010-trait>` parameter for universal compatibility.
517
663
 
518
664
  ### Q: How much does it cost?
519
- **A:** Fees are calculated in real-time based on STX/USD rates with an 8% markup. Typically 0.001-0.01 USDCx per transaction.
665
+ **A:** Fees are calculated in real-time based on STX/USD rates with an 8% markup. Typically 0.001-0.01 USDCx (or equivalent in other tokens) per transaction.
520
666
 
521
667
  ### Q: Is it secure?
522
668
  **A:** Yes! Uses Stacks' native sponsored transaction feature. No smart wallet complexity.
@@ -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,17 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VelumXClient = void 0;
4
4
  class VelumXClient {
5
5
  constructor(config) {
6
+ if (!config.apiKey && !config.paymasterUrl?.includes('/api/velumx/proxy')) {
7
+ throw new Error("VelumX Client Error: API Key is required. Please obtain your key from the VelumX Developer Dashboard.");
8
+ }
6
9
  this.config = config;
7
10
  // Default to a hosted relayer if not provided
8
11
  this.relayerUrl = config.paymasterUrl || 'https://relayer.velumx.com/api/v1';
9
12
  }
10
13
  /**
11
- * Get a fee estimation from the SGAL relayer for a specific intent
14
+ * Get a fee estimation from the relayer for a specific intent
12
15
  */
13
16
  async estimateFee(intent) {
14
17
  try {
15
18
  const headers = { 'Content-Type': 'application/json' };
16
- if (this.config.apiKey) {
19
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
17
20
  headers['x-api-key'] = this.config.apiKey;
18
21
  }
19
22
  const response = await fetch(`${this.relayerUrl}/estimate`, {
@@ -38,7 +41,7 @@ class VelumXClient {
38
41
  async submitIntent(signedIntent) {
39
42
  try {
40
43
  const headers = { 'Content-Type': 'application/json' };
41
- if (this.config.apiKey) {
44
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
42
45
  headers['x-api-key'] = this.config.apiKey;
43
46
  }
44
47
  const response = await fetch(`${this.relayerUrl}/sponsor`, {
@@ -57,19 +60,31 @@ class VelumXClient {
57
60
  throw error;
58
61
  }
59
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
+ }
60
71
  /**
61
72
  * Submit a raw Stacks transaction hex for native sponsorship
62
73
  */
63
- async submitRawTransaction(txHex) {
74
+ async submitRawTransaction(txHex, options) {
64
75
  try {
65
76
  const headers = { 'Content-Type': 'application/json' };
66
- if (this.config.apiKey) {
77
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
67
78
  headers['x-api-key'] = this.config.apiKey;
68
79
  }
69
80
  const response = await fetch(`${this.relayerUrl}/broadcast`, {
70
81
  method: 'POST',
71
82
  headers,
72
- body: JSON.stringify({ txHex })
83
+ body: JSON.stringify({
84
+ txHex,
85
+ userId: options?.userId,
86
+ feeAmount: options?.feeAmount
87
+ })
73
88
  });
74
89
  if (!response.ok) {
75
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.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "VelumX Gas Abstraction Layer SDK for dApps",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,22 +1,25 @@
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 && !config.paymasterUrl?.includes('/api/velumx/proxy')) {
9
+ throw new Error("VelumX Client Error: API Key is required. Please obtain your key from the VelumX Developer Dashboard.");
10
+ }
8
11
  this.config = config;
9
12
  // Default to a hosted relayer if not provided
10
13
  this.relayerUrl = config.paymasterUrl || 'https://relayer.velumx.com/api/v1';
11
14
  }
12
15
 
13
16
  /**
14
- * Get a fee estimation from the SGAL relayer for a specific intent
17
+ * Get a fee estimation from the relayer for a specific intent
15
18
  */
16
19
  public async estimateFee(intent: any): Promise<{ maxFeeUSDCx: string, estimatedGas: number }> {
17
20
  try {
18
21
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
19
- if (this.config.apiKey) {
22
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
20
23
  headers['x-api-key'] = this.config.apiKey;
21
24
  }
22
25
 
@@ -44,7 +47,7 @@ export class VelumXClient {
44
47
  public async submitIntent(signedIntent: SignedIntent): Promise<{ txid: string, status: string }> {
45
48
  try {
46
49
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
47
- if (this.config.apiKey) {
50
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
48
51
  headers['x-api-key'] = this.config.apiKey;
49
52
  }
50
53
 
@@ -66,20 +69,33 @@ export class VelumXClient {
66
69
  }
67
70
  }
68
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
+
69
81
  /**
70
82
  * Submit a raw Stacks transaction hex for native sponsorship
71
83
  */
72
- public async submitRawTransaction(txHex: string): Promise<{ txid: string, status: string }> {
84
+ public async submitRawTransaction(txHex: string, options?: SponsorshipOptions): Promise<{ txid: string, status: string }> {
73
85
  try {
74
86
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
75
- if (this.config.apiKey) {
87
+ if (this.config.apiKey && this.config.apiKey !== 'proxied') {
76
88
  headers['x-api-key'] = this.config.apiKey;
77
89
  }
78
90
 
79
91
  const response = await fetch(`${this.relayerUrl}/broadcast`, {
80
92
  method: 'POST',
81
93
  headers,
82
- body: JSON.stringify({ txHex })
94
+ body: JSON.stringify({
95
+ txHex,
96
+ userId: options?.userId,
97
+ feeAmount: options?.feeAmount
98
+ })
83
99
  });
84
100
 
85
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
  }