@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 +151 -5
- package/dist/VelumXClient.d.ts +12 -3
- package/dist/VelumXClient.js +21 -6
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
- package/src/VelumXClient.ts +23 -7
- package/src/types.ts +7 -2
package/README.md
CHANGED
|
@@ -113,13 +113,28 @@ const result = await openContractCall({
|
|
|
113
113
|
### Fee Calculation
|
|
114
114
|
|
|
115
115
|
```
|
|
116
|
-
Fee in
|
|
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
|
|
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.
|
package/dist/VelumXClient.d.ts
CHANGED
|
@@ -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
|
|
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
|
}>;
|
package/dist/VelumXClient.js
CHANGED
|
@@ -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
|
|
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({
|
|
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
package/package.json
CHANGED
package/src/VelumXClient.ts
CHANGED
|
@@ -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
|
|
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({
|
|
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
|
|
19
|
-
apiKey?: string; //
|
|
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
|
}
|