@velumx/sdk 1.0.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/dist/IntentBuilder.d.ts +22 -0
- package/dist/IntentBuilder.js +56 -0
- package/dist/VelumXClient.d.ts +20 -0
- package/dist/VelumXClient.js +60 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +23 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +2 -0
- package/package.json +34 -0
- package/src/IntentBuilder.ts +70 -0
- package/src/VelumXClient.ts +67 -0
- package/src/index.ts +8 -0
- package/src/types.ts +21 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WalletIntent, SignedIntent } from './types';
|
|
2
|
+
export declare class IntentBuilder {
|
|
3
|
+
private domainName;
|
|
4
|
+
private domainVersion;
|
|
5
|
+
private chainId;
|
|
6
|
+
constructor(network?: 'mainnet' | 'testnet' | 'devnet');
|
|
7
|
+
/**
|
|
8
|
+
* Builds the SIP-018 structured data domain
|
|
9
|
+
*/
|
|
10
|
+
private getDomain;
|
|
11
|
+
/**
|
|
12
|
+
* Formats the intent into a Clarity Tuple for signing
|
|
13
|
+
* Structure matches the Smart Wallet expectation
|
|
14
|
+
*/
|
|
15
|
+
private formatIntentMessage;
|
|
16
|
+
/**
|
|
17
|
+
* Signs an intent using a private key
|
|
18
|
+
* In a browser environment, this would use a wallet popup (e.g. Leather/Xverse)
|
|
19
|
+
* For Node.js/Backend, it signs directly.
|
|
20
|
+
*/
|
|
21
|
+
signIntent(intent: WalletIntent, privateKey: string): SignedIntent;
|
|
22
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IntentBuilder = void 0;
|
|
4
|
+
const transactions_1 = require("@stacks/transactions");
|
|
5
|
+
class IntentBuilder {
|
|
6
|
+
constructor(network = 'mainnet') {
|
|
7
|
+
this.domainName = "SGAL-Smart-Wallet";
|
|
8
|
+
this.domainVersion = "1.0.0";
|
|
9
|
+
this.chainId = network === 'mainnet' ? 1 : 2147483648; // Testnet chain ID
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Builds the SIP-018 structured data domain
|
|
13
|
+
*/
|
|
14
|
+
getDomain() {
|
|
15
|
+
return (0, transactions_1.tupleCV)({
|
|
16
|
+
name: (0, transactions_1.stringAsciiCV)(this.domainName),
|
|
17
|
+
version: (0, transactions_1.stringAsciiCV)(this.domainVersion),
|
|
18
|
+
'chain-id': (0, transactions_1.uintCV)(this.chainId)
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Formats the intent into a Clarity Tuple for signing
|
|
23
|
+
* Structure matches the Smart Wallet expectation
|
|
24
|
+
*/
|
|
25
|
+
formatIntentMessage(intent) {
|
|
26
|
+
return (0, transactions_1.tupleCV)({
|
|
27
|
+
target: (0, transactions_1.principalCV)(intent.target),
|
|
28
|
+
'function-name': (0, transactions_1.stringAsciiCV)(intent.functionName),
|
|
29
|
+
args: (0, transactions_1.listCV)(intent.args),
|
|
30
|
+
'max-fee-usdcx': (0, transactions_1.uintCV)(intent.maxFeeUSDCx),
|
|
31
|
+
nonce: (0, transactions_1.uintCV)(intent.nonce),
|
|
32
|
+
deadline: intent.deadline ? (0, transactions_1.someCV)((0, transactions_1.uintCV)(intent.deadline)) : (0, transactions_1.noneCV)()
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Signs an intent using a private key
|
|
37
|
+
* In a browser environment, this would use a wallet popup (e.g. Leather/Xverse)
|
|
38
|
+
* For Node.js/Backend, it signs directly.
|
|
39
|
+
*/
|
|
40
|
+
signIntent(intent, privateKey) {
|
|
41
|
+
const domain = this.getDomain();
|
|
42
|
+
const message = this.formatIntentMessage(intent);
|
|
43
|
+
// Uses Stacks.js SIP-018 signing utility
|
|
44
|
+
// Note: For dApps, use the '@stacks/connect' openSignatureRequest instead
|
|
45
|
+
const signature = (0, transactions_1.signStructuredData)({
|
|
46
|
+
message,
|
|
47
|
+
domain,
|
|
48
|
+
privateKey
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
...intent,
|
|
52
|
+
signature
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.IntentBuilder = IntentBuilder;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SignedIntent, NetworkConfig } from './types';
|
|
2
|
+
export declare class VelumXClient {
|
|
3
|
+
private config;
|
|
4
|
+
private relayerUrl;
|
|
5
|
+
constructor(config: NetworkConfig);
|
|
6
|
+
/**
|
|
7
|
+
* Get a fee estimation from the SGAL relayer for a specific intent
|
|
8
|
+
*/
|
|
9
|
+
estimateFee(intent: any): Promise<{
|
|
10
|
+
maxFeeUSDCx: string;
|
|
11
|
+
estimatedGas: number;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Submit a signed intent to the relayer for sponsorship and execution
|
|
15
|
+
*/
|
|
16
|
+
submitIntent(signedIntent: SignedIntent): Promise<{
|
|
17
|
+
txid: string;
|
|
18
|
+
status: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VelumXClient = void 0;
|
|
4
|
+
class VelumXClient {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
// Default to a hosted relayer if not provided
|
|
8
|
+
this.relayerUrl = config.paymasterUrl || 'https://relayer.velumx.com/api/v1';
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get a fee estimation from the SGAL relayer for a specific intent
|
|
12
|
+
*/
|
|
13
|
+
async estimateFee(intent) {
|
|
14
|
+
try {
|
|
15
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
16
|
+
if (this.config.apiKey) {
|
|
17
|
+
headers['x-api-key'] = this.config.apiKey;
|
|
18
|
+
}
|
|
19
|
+
const response = await fetch(`${this.relayerUrl}/estimate`, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
headers,
|
|
22
|
+
body: JSON.stringify({ intent })
|
|
23
|
+
});
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
throw new Error(`Fee estimation failed: ${response.statusText}`);
|
|
26
|
+
}
|
|
27
|
+
return await response.json();
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error("VelumX Client Error (estimateFee):", error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Submit a signed intent to the relayer for sponsorship and execution
|
|
36
|
+
*/
|
|
37
|
+
async submitIntent(signedIntent) {
|
|
38
|
+
try {
|
|
39
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
40
|
+
if (this.config.apiKey) {
|
|
41
|
+
headers['x-api-key'] = this.config.apiKey;
|
|
42
|
+
}
|
|
43
|
+
const response = await fetch(`${this.relayerUrl}/sponsor`, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers,
|
|
46
|
+
body: JSON.stringify({ intent: signedIntent })
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const errData = await response.json().catch(() => ({}));
|
|
50
|
+
throw new Error(`Intent sponsorship failed: ${errData.message || response.statusText}`);
|
|
51
|
+
}
|
|
52
|
+
return await response.json();
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error("VelumX Client Error (submitIntent):", error);
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.VelumXClient = VelumXClient;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./IntentBuilder"), exports);
|
|
19
|
+
__exportStar(require("./VelumXClient"), exports);
|
|
20
|
+
// Core entrypoint for the @velumx/sdk
|
|
21
|
+
// Example Usage:
|
|
22
|
+
// const client = new VelumXClient({ network: 'testnet' });
|
|
23
|
+
// const intentBuilder = new IntentBuilder();
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ClarityValue } from '@stacks/transactions';
|
|
2
|
+
export interface WalletIntent {
|
|
3
|
+
target: string;
|
|
4
|
+
functionName: string;
|
|
5
|
+
args: ClarityValue[];
|
|
6
|
+
maxFeeUSDCx: string | number;
|
|
7
|
+
nonce: string | number;
|
|
8
|
+
deadline?: string | number;
|
|
9
|
+
}
|
|
10
|
+
export interface SignedIntent extends WalletIntent {
|
|
11
|
+
signature: string;
|
|
12
|
+
}
|
|
13
|
+
export interface NetworkConfig {
|
|
14
|
+
coreApiUrl: string;
|
|
15
|
+
network: 'mainnet' | 'testnet' | 'devnet';
|
|
16
|
+
paymasterUrl?: string;
|
|
17
|
+
apiKey?: string;
|
|
18
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@velumx/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "VelumX Gas Abstraction Layer SDK for dApps",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"clean": "if exist dist rmdir /s /q dist",
|
|
9
|
+
"build": "npm run clean && tsc",
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public",
|
|
14
|
+
"registry": "https://registry.npmjs.org/"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"stacks",
|
|
18
|
+
"stx",
|
|
19
|
+
"gasless",
|
|
20
|
+
"paymaster",
|
|
21
|
+
"account-abstraction"
|
|
22
|
+
],
|
|
23
|
+
"author": "VelumX",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@stacks/common": "^7.3.1",
|
|
27
|
+
"@stacks/network": "^7.3.1",
|
|
28
|
+
"@stacks/transactions": "^7.3.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^25.3.2",
|
|
32
|
+
"typescript": "^5.9.3"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
signStructuredData,
|
|
3
|
+
tupleCV,
|
|
4
|
+
uintCV,
|
|
5
|
+
principalCV,
|
|
6
|
+
stringAsciiCV,
|
|
7
|
+
noneCV,
|
|
8
|
+
someCV,
|
|
9
|
+
listCV
|
|
10
|
+
} from '@stacks/transactions';
|
|
11
|
+
import { WalletIntent, SignedIntent } from './types';
|
|
12
|
+
|
|
13
|
+
export class IntentBuilder {
|
|
14
|
+
private domainName = "SGAL-Smart-Wallet";
|
|
15
|
+
private domainVersion = "1.0.0";
|
|
16
|
+
private chainId: number;
|
|
17
|
+
|
|
18
|
+
constructor(network: 'mainnet' | 'testnet' | 'devnet' = 'mainnet') {
|
|
19
|
+
this.chainId = network === 'mainnet' ? 1 : 2147483648; // Testnet chain ID
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Builds the SIP-018 structured data domain
|
|
24
|
+
*/
|
|
25
|
+
private getDomain() {
|
|
26
|
+
return tupleCV({
|
|
27
|
+
name: stringAsciiCV(this.domainName),
|
|
28
|
+
version: stringAsciiCV(this.domainVersion),
|
|
29
|
+
'chain-id': uintCV(this.chainId)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Formats the intent into a Clarity Tuple for signing
|
|
35
|
+
* Structure matches the Smart Wallet expectation
|
|
36
|
+
*/
|
|
37
|
+
private formatIntentMessage(intent: WalletIntent) {
|
|
38
|
+
return tupleCV({
|
|
39
|
+
target: principalCV(intent.target),
|
|
40
|
+
'function-name': stringAsciiCV(intent.functionName),
|
|
41
|
+
args: listCV(intent.args),
|
|
42
|
+
'max-fee-usdcx': uintCV(intent.maxFeeUSDCx),
|
|
43
|
+
nonce: uintCV(intent.nonce),
|
|
44
|
+
deadline: intent.deadline ? someCV(uintCV(intent.deadline)) : noneCV()
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Signs an intent using a private key
|
|
50
|
+
* In a browser environment, this would use a wallet popup (e.g. Leather/Xverse)
|
|
51
|
+
* For Node.js/Backend, it signs directly.
|
|
52
|
+
*/
|
|
53
|
+
public signIntent(intent: WalletIntent, privateKey: string): SignedIntent {
|
|
54
|
+
const domain = this.getDomain();
|
|
55
|
+
const message = this.formatIntentMessage(intent);
|
|
56
|
+
|
|
57
|
+
// Uses Stacks.js SIP-018 signing utility
|
|
58
|
+
// Note: For dApps, use the '@stacks/connect' openSignatureRequest instead
|
|
59
|
+
const signature = signStructuredData({
|
|
60
|
+
message,
|
|
61
|
+
domain,
|
|
62
|
+
privateKey
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
...intent,
|
|
67
|
+
signature
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { SignedIntent, NetworkConfig } from './types';
|
|
2
|
+
|
|
3
|
+
export class VelumXClient {
|
|
4
|
+
private config: NetworkConfig;
|
|
5
|
+
private relayerUrl: string;
|
|
6
|
+
|
|
7
|
+
constructor(config: NetworkConfig) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
// Default to a hosted relayer if not provided
|
|
10
|
+
this.relayerUrl = config.paymasterUrl || 'https://relayer.velumx.com/api/v1';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get a fee estimation from the SGAL relayer for a specific intent
|
|
15
|
+
*/
|
|
16
|
+
public async estimateFee(intent: any): Promise<{ maxFeeUSDCx: string, estimatedGas: number }> {
|
|
17
|
+
try {
|
|
18
|
+
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
|
19
|
+
if (this.config.apiKey) {
|
|
20
|
+
headers['x-api-key'] = this.config.apiKey;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const response = await fetch(`${this.relayerUrl}/estimate`, {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers,
|
|
26
|
+
body: JSON.stringify({ intent })
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
throw new Error(`Fee estimation failed: ${response.statusText}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return await response.json();
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("VelumX Client Error (estimateFee):", error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Submit a signed intent to the relayer for sponsorship and execution
|
|
42
|
+
*/
|
|
43
|
+
public async submitIntent(signedIntent: SignedIntent): Promise<{ txid: string, status: string }> {
|
|
44
|
+
try {
|
|
45
|
+
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
|
46
|
+
if (this.config.apiKey) {
|
|
47
|
+
headers['x-api-key'] = this.config.apiKey;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const response = await fetch(`${this.relayerUrl}/sponsor`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers,
|
|
53
|
+
body: JSON.stringify({ intent: signedIntent })
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const errData = await response.json().catch(() => ({}));
|
|
58
|
+
throw new Error(`Intent sponsorship failed: ${errData.message || response.statusText}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return await response.json();
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error("VelumX Client Error (submitIntent):", error);
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './IntentBuilder';
|
|
3
|
+
export * from './VelumXClient';
|
|
4
|
+
|
|
5
|
+
// Core entrypoint for the @velumx/sdk
|
|
6
|
+
// Example Usage:
|
|
7
|
+
// const client = new VelumXClient({ network: 'testnet' });
|
|
8
|
+
// const intentBuilder = new IntentBuilder();
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { principalCV, uintCV, stringAsciiCV, tupleCV, someCV, noneCV, ClarityValue } from '@stacks/transactions';
|
|
2
|
+
|
|
3
|
+
export interface WalletIntent {
|
|
4
|
+
target: string;
|
|
5
|
+
functionName: string;
|
|
6
|
+
args: ClarityValue[];
|
|
7
|
+
maxFeeUSDCx: string | number; // uint represented as string or number
|
|
8
|
+
nonce: string | number;
|
|
9
|
+
deadline?: string | number; // Future feature
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SignedIntent extends WalletIntent {
|
|
13
|
+
signature: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface NetworkConfig {
|
|
17
|
+
coreApiUrl: string;
|
|
18
|
+
network: 'mainnet' | 'testnet' | 'devnet';
|
|
19
|
+
paymasterUrl?: string; // URL for the SGAL relayer service
|
|
20
|
+
apiKey?: string; // SGAL API Key
|
|
21
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true
|
|
11
|
+
},
|
|
12
|
+
"include": [
|
|
13
|
+
"src/**/*"
|
|
14
|
+
]
|
|
15
|
+
}
|