nexa-wallet-sdk
Version:
Wallet SDK for the Nexa blockchain
500 lines (388 loc) • 12.6 kB
Markdown
# Nexa Wallet SDK
Production-ready TypeScript SDK for building Nexa blockchain wallets and dApps.
## Features
- **Wallet Management**: Create wallets from seed phrases or private keys
- **Account Types**: Support for multiple account types (NEXA, Vault, DApp)
- **Transaction Building**: Fluent API for building and signing transactions
- **Token Operations**: Create, mint, melt, and transfer tokens and NFTs
- **Watch-Only Wallets**: Monitor addresses without storing private keys
- **Network Support**: Mainnet and testnet compatibility
- **Multiple Formats**: CommonJS, ES modules, and browser bundles
## Installation
```bash
npm install nexa-wallet-sdk
```
## Quick Start
### Basic Wallet Setup
```typescript
import { Wallet, rostrumProvider } from 'nexa-wallet-sdk'
// Connect to the default mainnet node
await rostrumProvider.connect()
// Connect to a specific network (mainnet or testnet)
await rostrumProvider.connect('testnet') // Uses predefined testnet node
await rostrumProvider.connect('mainnet') // Uses predefined mainnet node
// Connect to a custom node (ignores network parameter)
await rostrumProvider.connect({
host: 'your-custom-node.example.com',
port: 30004,
scheme: 'wss' // or 'ws' for unencrypted connection
})
// Create wallet from seed phrase
const wallet = new Wallet(
'your twelve word seed phrase goes here for wallet creation',
'testnet' // or 'mainnet'
)
// Initialize wallet to discover accounts
await wallet.initialize()
// Get the default account
const account = wallet.accountStore.getAccount('1.0')
```
### Simple Transaction
```typescript
// Send 100 NEXA
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.sendTo('nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc', '10000')
.populate()
.sign()
.build()
console.log('Transaction:', tx)
```
## Core Concepts
### Accounts
The SDK supports different account types:
- **NEXA Account**: Standard accounts for regular transactions
- **Vault Account**: Secure storage accounts
- **DApp Account**: Application-specific accounts
```typescript
// Get a new receiving address (This only returns a different address for default accounts)
const address = account.getNewAddress()
// Check account balance
const balance = account.balance
console.log('Confirmed:', balance.confirmed)
console.log('Unconfirmed:', balance.unconfirmed)
// Get transaction history
const transactions = await account.getTransactions()
```
### Transaction Building
All transactions follow the same pattern: **create → configure → populate → sign → build**
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet') // 1. Set network
.sendTo(address, amount) // 2. Configure outputs
.addOpReturn(data) // 3. Add optional data
.populate() // 4. Find inputs and calculate fees
.sign() // 5. Sign the transaction
.build() // 6. Get final transaction hex
```
## Transaction Examples
### Basic Send Transaction
```typescript
// Send 500 Nexa
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.sendTo('nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc', '50000')
.populate()
.sign()
.build()
```
### Multiple Outputs
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.sendTo('nexatest:address1', '10000')
.sendTo('nexatest:address2', '20000')
.sendTo('nexatest:address3', '30000')
.addOpReturn('Multi-output transaction')
.populate()
.sign()
.build()
```
### Fee From Amount
```typescript
// Deduct transaction fee from the send amount
const tx = await wallet.newTransaction(account)
.sendTo(recipient, '50000')
.feeFromAmount() // Fee will be subtracted from the 50000
.populate()
.sign()
.build()
```
### Consolidate UTXOs
```typescript
// Consolidate all UTXOs to a single address
const tx = await wallet.newTransaction(account)
.consolidate('nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc')
.populate()
.sign()
.build()
```
## Token Operations
### Create a Fungible Token
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.token(
'MyToken', // Token name
'MTK', // Ticker symbol
8, // Decimal places
'https://mytoken.com/info', // Documentation URL
'sha256hash' // Documentation hash
)
.populate()
.sign()
.build()
```
### Create an NFT Collection
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.collection(
'My NFT Collection',
'MNC',
'https://mycollection.com/metadata',
'collectionhash'
)
.populate()
.sign()
.build()
```
### Mint an NFT
```typescript
const parentCollectionId = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx'
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.nft(
parentCollectionId,
'https://mynft.com/content.zip',
'contenthash123'
)
.populate()
.sign()
.build()
```
### Token Transfers
```typescript
const tokenId = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.sendTo('nexatest:recipient', '1000') // Send NEXA
.sendToToken('nexatest:recipient', '500', tokenId) // Send tokens
.populate()
.sign()
.build()
```
### Mint Additional Tokens
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.mint(tokenId, '1000000') // Mint 1,000,000 token units
.populate()
.sign()
.build()
```
### Burn (Melt) Tokens
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.melt(tokenId, '500000') // Burn 500,000 token units
.populate()
.sign()
.build()
```
## Authority Management
### Renew Token Authorities
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.renewAuthority(
tokenId,
['mint', 'melt'], // Permissions to renew
'nexatest:nqtsq5g5...' // Optional: new authority address
)
.populate()
.sign()
.build()
```
### Delete Token Authority
```typescript
const tx = await wallet.newTransaction(account)
.onNetwork('testnet')
.deleteAuthority(tokenId, 'abc123:0') // outpoint of authority to delete
.populate()
.sign()
.build()
```
## Watch-Only Wallets
Watch-only wallets allow you to monitor addresses and create unsigned transactions without storing private keys.
### Create Watch-Only Wallet
```typescript
import { WatchOnlyWallet } from 'nexa-wallet-sdk'
const watchOnlyWallet = new WatchOnlyWallet([
{ address: 'nexatest:nqtsq5g5dsgh6mwjchqypn8hvdrjue0xpmz293fl7rm926xv' }
], 'testnet')
```
### Create Unsigned Transaction
```typescript
const unsignedTx = await watchOnlyWallet.newTransaction()
.sendTo('nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc', '100000')
.addOpReturn("Watch-only transaction")
.populate()
.build()
```
### Sign Watch-Only Transaction
```typescript
// Pass the unsigned transaction to a wallet with private keys
const signedTx = await wallet.newTransaction(account, unsignedTx)
.sign()
.build()
```
### Subscribe to Address Updates
```typescript
const myCallback = (notification) => {
console.log('Address activity:', notification)
}
await watchOnlyWallet.subscribeToAddressNotifications(myCallback)
// Later, to prevent memory leaks:
await watchOnlyWallet.unsubscribeFromAddressNotifications(myCallback)
```
## Advanced Features
### Address Notifications
```typescript
// Define your callback function
const myCallback = (notification) => {
console.log('Address notification:', notification)
}
// Subscribe to a single address
await wallet.subscribeToAddressNotifications(
'nexa:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc',
myCallback
)
// Subscribe to addresses as an array
const addresses = [
'nexa:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
]
await wallet.subscribeToAddressNotifications(addresses, myCallback)
// Subscribe to all wallet addresses
const accounts = wallet.accountStore.listAccounts()
const allAddresses = accounts.flatMap(account =>
account.getAddresses().map(addr => addr.address)
)
await wallet.subscribeToAddressNotifications(allAddresses, myCallback)
// Always unsubscribe when done to prevent memory leaks
await wallet.unsubscribeFromAddressNotifications(allAddresses, myCallback)
```
### Parse Existing Transactions
```typescript
// From hex string
const tx = await wallet.newTransaction(account)
.parseTxHex('0100000001...')
.sign()
.build()
// From buffer
const txBuffer = Buffer.from('0100000001...', 'hex')
const tx = await wallet.newTransaction(account)
.parseTxBuffer(txBuffer)
.sign()
.build()
```
### Export Wallet Data
```typescript
const walletData = wallet.export()
// Contains encrypted seed and account information for backup
```
### Broadcasting Transactions
```typescript
// Broadcast a signed transaction
const txId = await wallet.sendTransaction(signedTxHex)
console.log('Transaction ID:', txId)
// Or use watch-only wallet
const txId = await watchOnlyWallet.sendTransaction(signedTxHex)
```
## Available Exports
The SDK exports the following components:
```typescript
import {
// Core classes
Wallet,
WatchOnlyWallet,
// Account types
BaseAccount,
DefaultAccount,
DappAccount,
VaultAccount,
AccountStore,
// Transaction creators
WalletTransactionCreator,
WatchOnlyTransactionCreator,
// Network provider
rostrumProvider,
// Utility functions
ValidationUtils,
isValidNexaAddress,
// Utility classes
AccountKeysUtils,
// Enums
AccountType,
TxTokenType,
// Types
AccountKeys,
AccountIndexes,
AddressKey,
Balance,
WatchOnlyAddress,
TransactionEntity,
TokenAction
} from 'nexa-wallet-sdk'
```
## Error Handling
```typescript
try {
const tx = await wallet.newTransaction(account)
.sendTo('invalid-address', '1000')
.populate()
.sign()
.build()
} catch (error) {
if (error.message.includes('Invalid address')) {
console.error('Invalid Nexa address provided')
} else if (error.message.includes('Insufficient funds')) {
console.error('Not enough balance for transaction')
} else {
console.error('Transaction failed:', error.message)
}
}
```
## Network Configuration
```typescript
// Testnet (for development)
const testnetWallet = new Wallet(seedPhrase, 'testnet')
// Mainnet (for production)
const mainnetWallet = new Wallet(seedPhrase, 'mainnet')
// Always specify network in transactions
const tx = await wallet.newTransaction(account)
.onNetwork('testnet') // Must match wallet network
.sendTo(address, amount)
.populate()
.sign()
.build()
```
## Best Practices
1. **Always Connect First**: Call `await rostrumProvider.connect()` before wallet operations
2. **Network Consistency**: Ensure wallet and transaction networks match
3. **Amount Precision**: Use strings for amounts to avoid floating-point precision issues
4. **Error Handling**: Wrap wallet operations in try-catch blocks
5. **Private Key Security**: Never log or expose private keys or seed phrases
6. **Address Validation**: Validate addresses before sending transactions
7. **Fee Estimation**: Use `populate()` to estimate fees before signing
8. **Memory Management**: Always unsubscribe from address notifications when done to prevent memory leaks
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## Support
For issues and questions:
- GitHub Issues: [wallet-sdk-ts issues](https://gitlab.com/nexa/wallet-sdk-ts/issues)
- Documentation: [Nexa Documentation](https://docs.nexa.org)
---
**⚠️ Security Notice**: Never share your seed phrases or private keys. Always verify addresses before sending transactions. This SDK is for development purposes - use appropriate security measures in production applications.