@smoothsend/sdk
v2.2.0
Published
Multi-chain gasless transaction SDK with C-Address (Soroban Smart Account) support for Stellar, Aptos & more
Readme
SmoothSend SDK
Multi-chain gasless transaction SDK. Enable gas-free transactions with just 3 lines of code. Supports Aptos and Stellar.
🚀 Features
- Gasless Transactions: Users don't need APT or XLM for gas fees
- Multi-Chain: Aptos + Stellar (same 3-line API)
- 3-Line Integration: Works with Aptos Wallet Adapter and Stellar wallets (Freighter, etc.)
- Type-Safe: Full TypeScript support with comprehensive type definitions
- Testnet & Mainnet: Supports both networks on each chain
- Fee-in-Token: On Aptos mainnet, tiny fee deducted from token (not APT)
📦 Installation
npm install @smoothsend/sdk⚡ Quick Start - Wallet Adapter (EASIEST - All Transactions Gasless)
The simplest integration — pass transactionSubmitter to your wallet provider and every transaction becomes gasless automatically. Ideal when you want to sponsor all functions.
import { SmoothSendTransactionSubmitter } from '@smoothsend/sdk';
import { AptosWalletAdapterProvider } from '@aptos-labs/wallet-adapter-react';
import { Network } from '@aptos-labs/ts-sdk';
// 1. Create the transaction submitter (one line!)
const transactionSubmitter = new SmoothSendTransactionSubmitter({
apiKey: 'pk_nogas_your_api_key_here',
network: 'testnet'
});
// 2. Add to your wallet provider
function App() {
return (
<AptosWalletAdapterProvider
dappConfig={{
network: Network.TESTNET,
transactionSubmitter: transactionSubmitter // <-- That's it!
}}
>
<YourApp />
</AptosWalletAdapterProvider>
);
}
// 3. Use normal wallet functions - they're now gasless!
function TransferButton() {
const { signAndSubmitTransaction } = useWallet();
const handleTransfer = async () => {
// This is now gasless! No code changes needed!
const result = await signAndSubmitTransaction({
data: {
function: "0x1::coin::transfer",
typeArguments: ["0x1::aptos_coin::AptosCoin"],
functionArguments: [recipientAddress, amount],
}
});
console.log('Gasless transaction:', result.hash);
};
return <button onClick={handleTransfer}>Send (Gasless!)</button>;
}🎯 useSmoothSend Hook (Per-Function Routing)
Use useSmoothSend when you want some functions gasless and others not — for example, free to create but user pays to delete. The hook automatically routes each transaction based on your project's sponsored-functions allowlist configured in the dashboard.
import { useSmoothSend, SmoothSendTransactionSubmitter } from '@smoothsend/sdk';
// Create once at module scope (not inside the component)
const submitter = new SmoothSendTransactionSubmitter({
apiKey: process.env.NEXT_PUBLIC_SMOOTHSEND_API_KEY!,
network: 'testnet',
});
function MyComponent() {
// Drop-in replacement for useWallet().signAndSubmitTransaction
const { signAndSubmitTransaction } = useSmoothSend(submitter);
const handleAction = async () => {
// Automatically routed:
// function in allowlist → fee-payer gasless (user pays 0 gas)
// function not in list → walletSignAndSubmit fallback (user pays gas)
await signAndSubmitTransaction({
data: {
function: '0xABC::mymodule::my_function',
functionArguments: [arg1, arg2],
}
});
};
}Requirements for useSmoothSend:
react >= 17@aptos-labs/wallet-adapter-react >= 8@aptos-labs/ts-sdk >= 5.0.0← required forwithFeePayer: truesupport
Do NOT use transactionSubmitter in AptosWalletAdapterProvider when using useSmoothSend — the hook handles all routing directly.
When to use which
| Want to... | Use |
|---|---|
| Make ALL transactions gasless, zero config | transactionSubmitter in AptosWalletAdapterProvider |
| Sponsor only specific functions (allowlist) | useSmoothSend(submitter) hook |
| Mainnet free tier — deduct fee from token | ScriptComposerClient |
💰 Script Composer - Fee-in-Token Transfers
For mainnet with free tier, use Script Composer to deduct fees from the token being transferred:
import { ScriptComposerClient } from '@smoothsend/sdk';
// Create client for mainnet
const client = new ScriptComposerClient({
apiKey: 'pk_nogas_your_api_key',
network: 'mainnet'
});
// Step 1: Build transfer (fee calculated automatically)
const { transactionBytes, fee, totalAmount } = await client.buildTransfer({
sender: wallet.address,
recipient: '0x123...',
amount: '1000000', // 1 USDC
assetType: '0xf22bede...::usdc::USDC',
decimals: 6,
symbol: 'USDC'
});
console.log(`Sending 1 USDC, fee: ${fee} (deducted from token)`);
// Step 2: Sign with wallet
const signedTx = await wallet.signTransaction(transactionBytes);
// Step 3: Submit
const result = await client.submitSignedTransaction({
transactionBytes: signedTx.transactionBytes,
authenticatorBytes: signedTx.authenticatorBytes
});
console.log('Transaction:', result.txHash);When to Use Each Method
| Scenario | Method | Why | |----------|--------|-----| | Testnet (any tier) | TransactionSubmitter | Always free on testnet | | Mainnet + Free tier | ScriptComposerClient | Fee deducted from token ($0.01/tx) | | Mainnet + Paid tier | TransactionSubmitter | Zero fees included in subscription | | Swaps, NFTs, contracts | TransactionSubmitter | Script Composer only supports transfers | | Token transfers (monetize) | ScriptComposerClient | Pass fee to users |
Script Composer Methods
// Estimate fee without building transaction
const estimate = await client.estimateFee({
sender: '0x...',
recipient: '0x...',
amount: '1000000',
assetType: USDC_ADDRESS,
decimals: 6,
symbol: 'USDC'
});
console.log('Fee:', estimate.estimation.formatted.fee);
console.log('Total:', estimate.estimation.formatted.totalAmount);
// Or use the convenience method for complete flow
const result = await client.transfer(transferParams, wallet);⚠️ Important Security Update
For Aptos transactions, the SDK uses a secure serialized transaction approach that requires proper wallet integration using the Aptos Wallet Standard.
See the Wallet Adapter Integration section for the recommended implementation.
🔑 Authentication
SmoothSend uses API keys for authentication. There are two types of keys:
Public Keys (pk_nogas_*)
- Safe for frontend applications - Can be embedded in client-side code
- CORS-protected - Only work from configured domains
- Use in: React apps, Vue apps, browser extensions, mobile apps
Secret Keys (sk_nogas_*)
- Server-side only - Must never be exposed in client-side code
- No CORS restrictions - Work from any server environment
- Use in: Node.js backends, serverless functions, API servers
Getting Your API Keys
- Sign up at dashboard.smoothsend.xyz
- Create a project
- Generate an API key pair - you'll receive both a public and secret key
- Configure CORS origins for your public key
Security Best Practices
⚠️ Never commit secret keys to version control ⚠️ Never expose secret keys in client-side code ✅ Use public keys for frontend applications ✅ Use secret keys for backend services ✅ Configure CORS origins for production domains
🏁 Classic SDK Usage
If you prefer more control over the transaction flow, you can use the classic SDK approach:
Frontend Example (Public Key)
import { SmoothSendSDK } from '@smoothsend/sdk';
// Initialize with public key (safe for frontend)
const smoothSend = new SmoothSendSDK({
apiKey: 'pk_nogas_your_public_key_here',
network: 'testnet',
timeout: 30000,
retries: 3
});
// Create a transfer request
const transferRequest = {
from: '0x742d35cc6634c0532925a3b8d2d2d2d2d2d2d2d2',
to: '0x742d35cc6634c0532925a3b8d2d2d2d2d2d2d2d3',
token: 'USDC',
amount: '1000000', // 1 USDC (6 decimals)
chain: 'aptos-testnet' as const
};
// Execute transfer (with wallet signer)
try {
const result = await smoothSend.transfer(transferRequest, walletSigner);
console.log('Transfer successful:', result.txHash);
} catch (error) {
console.error('Transfer failed:', error.message);
}Backend Example (Secret Key)
import { SmoothSendSDK } from '@smoothsend/sdk';
// Initialize with secret key (server-side only)
const smoothSend = new SmoothSendSDK({
apiKey: 'sk_nogas_your_secret_key_here',
network: 'mainnet',
timeout: 30000,
retries: 3
});
// Execute Aptos transfer from backend
const result = await smoothSend.executeGaslessTransfer({
transactionBytes: signedTx.transactionBytes,
authenticatorBytes: signedTx.authenticatorBytes,
chain: 'aptos-mainnet',
network: 'mainnet'
});
// Or Stellar - submit signed XDR
const stellarResult = await smoothSend.submitStellarTransaction(signedXdr);
console.log('Transfer successful:', result.txHash);⭐ Stellar - Gasless XLM & USDC
Same 3-line API for Stellar. Use with Freighter, Stellar Wallets Kit, or any Stellar-compatible wallet.
import { SmoothSendSDK } from '@smoothsend/sdk';
const sdk = new SmoothSendSDK({ apiKey: 'pk_nogas_xxx', network: 'testnet' });
// Option 1: Full transfer (build + sign + submit)
const result = await sdk.transfer(
{ from: 'G...', to: 'G...', amount: '100', token: 'XLM', chain: 'stellar-testnet' },
stellarWallet
);
// Option 2: Submit pre-signed XDR
const signedXdr = await wallet.signTransaction(tx);
const result = await sdk.submitStellarTransaction(signedXdr);Stellar wallet interface:
const stellarWallet = {
buildTransaction: (params) => buildPaymentTransaction(params.from, params.to, params.amount, params.token),
signTransaction: (tx) => walletKit.signTransaction(tx.toXDR()).then(r => r.signedTxXdr),
};🔧 Supported Networks
| Network | Status | Features | |---------|--------|----------| | Aptos Testnet | ✅ Active | Gasless transactions, Ed25519 signatures | | Aptos Mainnet | ✅ Active | Gasless transactions, Fee-in-token option | | Stellar Testnet | ✅ Active | Gasless XLM, USDC, EURC via Fee Bump | | Stellar Mainnet | ✅ Active | Gasless XLM, USDC, EURC via Fee Bump |
📚 API Reference
SmoothSendTransactionSubmitter
The recommended way to integrate - works with Aptos Wallet Adapter.
import { SmoothSendTransactionSubmitter } from '@smoothsend/sdk';
const submitter = new SmoothSendTransactionSubmitter({
apiKey: 'pk_nogas_your_api_key',
network: 'testnet' // or 'mainnet'
});
// Pass to AptosWalletAdapterProvider
<AptosWalletAdapterProvider
dappConfig={{
network: Network.TESTNET,
transactionSubmitter: submitter
}}
>ScriptComposerClient
For mainnet transfers with fee-in-token (fee deducted from transferred amount).
import { ScriptComposerClient } from '@smoothsend/sdk';
const client = new ScriptComposerClient({
apiKey: 'pk_nogas_your_api_key',
network: 'mainnet'
});
// Build transfer
const { transactionBytes, fee } = await client.buildTransfer({
sender: '0x...',
recipient: '0x...',
amount: '1000000',
assetType: USDC_ADDRESS,
decimals: 6,
symbol: 'USDC'
});
// Estimate fee
const estimate = await client.estimateFee(transferParams);
// Submit signed transaction
const result = await client.submitSignedTransaction({
transactionBytes,
authenticatorBytes
});SmoothSendSDK (Classic)
Direct SDK usage for more control. Works for both Aptos and Stellar.
import { SmoothSendSDK } from '@smoothsend/sdk';
const smoothSend = new SmoothSendSDK({
apiKey: 'pk_nogas_your_api_key',
network: 'testnet',
timeout: 30000,
retries: 3
});
// Aptos - execute gasless transfer
const result = await smoothSend.executeGaslessTransfer({
transactionBytes: signedTx.transactionBytes,
authenticatorBytes: signedTx.authenticatorBytes,
chain: 'aptos-testnet',
network: 'testnet'
});
// Stellar - submit signed XDR
const stellarResult = await smoothSend.submitStellarTransaction(signedXdr);🔐 Security
- All transactions require user signature approval
- Private keys never leave the client
- Rate limiting and validation on relayer endpoints
- Comprehensive input validation
- Public keys are CORS-protected (safe for frontend)
- Secret keys for backend only
🔗 Links
- Dashboard: dashboard.smoothsend.xyz
- Documentation: docs.smoothsend.xyz
- GitHub: github.com/smoothsend
📄 License
MIT
Built with ❤️ by the SmoothSend team
