---
url: /guides/advanced-transactions.md
---
# Advanced Transactions
The Movement SDK supports multiple transaction types beyond basic transfers. These advanced patterns enable complex on-chain interactions.
***
## Multi-Agent Transactions
Multi-agent transactions allow multiple accounts to participate in a single transaction. This is useful for:
* Multi-signature wallets
* Escrow services
* Collaborative actions
### How It Works
1. **Primary sender** initiates the transaction
2. **Secondary signers** provide additional signatures
3. All signatures are verified on-chain
4. Transaction executes with all signers' permissions
### Example: Multi-Sig Approval
```typescript
import { useMovementSDK } from '@movement-labs/miniapp-sdk';
const { sdk } = useMovementSDK();
// Execute a multi-sig transaction
> Note: `sendMultiAgentTransaction()` is not implemented in the current host.
const result = await sdk.sendMultiAgentTransaction({
function: '0x1::multisig::approve_transaction',
arguments: [
multisigAddress,
transactionId,
],
type_arguments: [],
secondarySigners: [
'0xabc...', // Second approver
'0xdef...', // Third approver
],
});
console.log('Multi-sig approved:', result.hash);
```
### Security Notes
* All secondary signers must be valid addresses
* The Move function must accept the correct number of signers
* Rate limiting applies per sender account
***
## Fee Payer (Sponsored) Transactions
Fee payer transactions allow a different account to cover gas fees. Perfect for:
* Onboarding new users (sponsor their first transactions)
* App-funded operations
* Gasless user experiences
### How It Works
1. **User** signs the transaction payload
2. **Fee payer** (sponsor) signs as the gas payer
3. Fee payer's account is charged for gas
4. Transaction executes on behalf of the user
### Example: Sponsored NFT Mint
```typescript
const { sdk, address } = useMovementSDK();
// User mints NFT, sponsor pays gas
> Note: `sendFeePayerTransaction()` is not implemented in the current host.
const result = await sdk.sendFeePayerTransaction({
function: '0x1::nft::mint',
arguments: [
'Cool NFT',
'An awesome NFT',
'https://example.com/nft.png',
],
type_arguments: [],
feePayer: '0x_sponsor_address_...', // This account pays gas
});
console.log('NFT minted (gas-free for user):', result.hash);
```
### Use Cases
* **Free trials**: Let users try your app without MOVE tokens
* **Rewards**: Sponsor claim transactions for users
* **Onboarding**: Remove gas fee friction for new users
***
## Batch Transactions
Submit multiple transactions in a single call. Useful for:
* Bulk token transfers
* Sequential operations
* Reducing transaction overhead
### How It Works
1. Provide an array of transaction payloads
2. SDK submits them sequentially
3. Returns results for all transactions
4. Partial failures are tracked
### Example: Bulk Airdrops
```typescript
const { sdk } = useMovementSDK();
// Airdrop tokens to multiple users
const recipients = [
{ address: '0xabc...', amount: '1000000' },
{ address: '0xdef...', amount: '2000000' },
{ address: '0x123...', amount: '1500000' },
];
> Note: `sendBatchTransactions()` is not implemented in the current host.
const result = await sdk.sendBatchTransactions({
transactions: recipients.map(r => ({
function: '0x1::aptos_account::transfer',
arguments: [r.address, r.amount],
type_arguments: [],
})),
});
console.log(`Success: ${result.successCount}/${recipients.length}`);
console.log('Failed:', result.failureCount);
```
### Best Practices
* **Error handling**: Check individual results for failures
* **Gas estimation**: Ensure sufficient balance for all transactions
* **Rate limits**: Batch size affects rate limiting
***
## Script Transactions
Execute complex Move scripts with multiple function calls. For advanced use cases:
* Custom logic composition
* Multi-step operations
* Dynamic contract interactions
### How It Works
1. Compile a Move script to bytecode
2. Pass bytecode and arguments to SDK
3. Script executes on-chain with full composability
### Example: Complex Swap & Stake
```typescript
const { sdk } = useMovementSDK();
// Pre-compiled Move script that swaps tokens and stakes them
const swapAndStakeScript = '0x...'; // Compiled bytecode
const result = await sdk.sendScriptTransaction({
script: swapAndStakeScript,
arguments: [
'1000000', // Amount to swap
'0xabc...', // Pool address
],
type_arguments: [
'0x1::aptos_coin::AptosCoin',
'0x1::usdc::USDC',
],
});
console.log('Swap & stake completed:', result.hash);
```
### When to Use Scripts
* **Complex workflows**: Multiple contract calls in one transaction
* **Gas optimization**: Reduce multiple transactions to one
* **Atomic operations**: All-or-nothing execution
***
## Transaction Options
All transaction types support additional options:
```typescript
// Coming soon: Gas configuration
{
maxGasAmount: '100000',
gasUnitPrice: '100',
expirationTimestamp: Date.now() + 60000, // 1 minute
}
```
***
## Error Handling
Always handle errors appropriately:
```typescript
try {
const result = await sdk.sendMultiAgentTransaction(payload);
console.log('Success:', result.hash);
} catch (error) {
if (error.message.includes('rate limit')) {
// Rate limit exceeded
alert('Too many requests. Please wait.');
} else if (error.message.includes('Invalid')) {
// Validation error
console.error('Invalid payload:', error);
} else {
// Other errors
console.error('Transaction failed:', error);
}
}
```
***
## Security Considerations
All advanced transaction types include:
* **Rate limiting** - Prevents spam and abuse
* **Payload validation** - Ensures correct format
* **Address verification** - Validates all addresses
* **Amount limits** - Configurable transaction caps
See [Security Guide](/guides/security) for more details.
***
## Next Steps
* **[API Reference](/reference/sdk-api)** - Complete method documentation
* **[Security Guide](/guides/security)** - Best practices
* **[SDK Overview](/sdk/overview)** - Core features
---
---
url: /ai-builder.md
---
# AI Mini App Builder
Build Movement mini apps with the help of AI. Describe your idea and get instant code generation with best practices built in.
## How It Works
The AI Builder uses Claude (Anthropic's AI model) with deep knowledge of the Movement Mini App SDK to help you:
1. **Design your mini app** - Discuss features and architecture
2. **Generate code** - Get complete React/Next.js components with Movement SDK integration
3. **Create smart contracts** - Generate Move contracts when needed
4. **Write tests** - Get comprehensive test coverage
5. **Deploy** - Get deployment instructions and best practices
### LLM-Optimized Documentation
Our documentation includes an [/llms.txt](/llms.txt) file that provides structured information to AI tools. This helps ensure AI-generated code follows best practices and uses the latest SDK patterns.
**AI tools can access:**
* Complete SDK API reference with `isInstalled()` and `ready()` patterns
* Transaction and error handling patterns
* TypeScript type definitions
* Security best practices
* Design guidelines
## What You Can Build
* **DeFi Apps**: Token swaps, staking dashboards, yield farms
* **NFT Apps**: Galleries, marketplaces, minting platforms
* **Gaming**: On-chain games, leaderboards, achievements
* **Social**: Chat apps, social feeds, reputation systems
* **Payments**: P2P payments, invoicing, tipping
* **Utilities**: Multi-sig wallets, batch senders, portfolio trackers
## Tips for Best Results
1. **Be specific**: Instead of "token app", try "token swap app with slippage protection"
2. **Mention features**: List the specific features you need (QR scanning, haptic feedback, notifications)
3. **Request patterns**: Ask for proper SDK initialization with `isInstalled()` and `ready()` checks
4. **Ask questions**: The AI can explain concepts and suggest improvements
5. **Iterate**: Start simple and add features incrementally
6. **Review code**: Always review generated code for your use case
7. **Use TypeScript**: Request TypeScript code with full type definitions for best results
## Example Prompts
### Simple Apps
* "Create a token transfer app with QR code scanner for addresses, balance display, and haptic feedback"
* "Build an NFT gallery that shows my owned NFTs with proper SDK initialization using isInstalled() and ready()"
* "Make a simple staking dashboard with transaction notifications"
### SDK Patterns
* "Show me how to properly initialize the SDK with isInstalled() and ready() checks in a Next.js app"
* "Create a connect wallet button that uses the useMovementSDK hook with loading and error states"
* "Implement a transaction flow with waitForTransaction() and success notifications"
### Complex Apps
* "Create a P2P marketplace with escrow functionality and dispute resolution. Use a Move contract for escrow logic."
* "Build a decentralized social feed where users can post messages to the blockchain and follow other users"
* "Make a gaming leaderboard with on-chain score verification and rewards distribution"
### With Smart Contracts
* "Create a token vesting app with a Move contract that handles time-locked releases"
* "Build a DAO voting system with proposal creation, voting, and execution via Move contracts"
* "Make a lottery app where users buy tickets and winners are selected randomly on-chain"
## Features
* **Real-time code generation** - See code as it's being generated
* **Complete project structure** - Get package.json, components, contracts, and more
* **Best practices** - Security, error handling, and UX built in
* **TypeScript support** - Fully typed code generation
* **Smart contract generation** - Move contracts when blockchain logic is needed
* **Test generation** - Unit and integration tests
## Prerequisites
Before using the generated code:
1. Install Node.js 18+
2. Set up Movement wallet (for testing)
3. Get testnet MOVE tokens from faucet
4. Familiarity with React/Next.js (helpful but not required)
### For Local Development
If you're running the docs locally and want to use the AI Builder:
1. Get an Anthropic API key from [console.anthropic.com](https://console.anthropic.com/)
2. Set the environment variable:
```bash
export ANTHROPIC_API_KEY=your-key-here
npm run dev
```
The AI Builder requires the API server to be running (started automatically with `npm run dev`) and the `ANTHROPIC_API_KEY` environment variable to be set.
## Next Steps
After generating your mini app:
1. **Download the code** - Copy the generated files to your project
2. **Install dependencies** - Run `npm install`
3. **Test locally** - Run `npm run dev`
4. **Deploy** - Follow our [Publishing Guide](/guides/publishing)
5. **Submit to Movement** - Get your app listed in the Movement Everything wallet
## Support
Need help? Check out:
* [SDK Documentation](/sdk/overview)
* [API Reference](/reference/sdk-api)
* [Security Guide](/guides/security)
* [Discord Community](https://discord.gg/movementlabs)
***
**Ready to build?** Start chatting with the AI Builder above! 🚀
---
---
url: /publishing/publisher.md
---
# App Publisher
---
---
url: /commands.md
---
# Commands
Commands are the primary way your mini app interacts with the Movement SDK. They enable blockchain transactions, device features, and platform capabilities.
## Available Commands
### Blockchain
**[View Function](/commands/view)**
Call read-only Move view functions to fetch on-chain data
**[Send Transaction](/commands/send-transaction)**
Execute blockchain transactions with user approval
**Sign Message** *(Coming Soon)*
Sign messages for authentication and verification
### Device Features
**[Scan QR Code](/commands/scan-qr)**
Scan wallet addresses and QR codes
**[Haptic Feedback](/commands/haptic)**
Provide tactile feedback for user actions
**Camera** *(Coming Soon)*
Capture photos and access media library
**Biometrics** *(Coming Soon)*
Authenticate with Face ID / Touch ID
**Location** *(Coming Soon)*
Access device GPS location
### Platform
**[Notifications](/commands/notifications)**
Send push notifications to users
**Share** *(Coming Soon)*
Open native share sheet
**Storage** *(Coming Soon)*
Save data locally on device
### Analytics
**[Analytics](/reference/sdk-api#analytics)**
Track events, screens, and user properties
## Usage Patterns
All commands are available through the SDK instance:
```typescript
// Get SDK instance
const sdk = window.movementSDK;
// Or use React hook
const { sdk } = useMovementSDK();
// Call command
const result = await sdk.sendTransaction({...});
```
## Response Handling
Commands return promises that resolve with results or reject with errors:
```typescript
try {
const result = await sdk.sendTransaction({...});
console.log('Success:', result);
} catch (error) {
console.error('Error:', error.message);
}
```
See [Responses](/quick-start/responses) for detailed error handling patterns.
## Rate Limits
Commands are rate-limited to prevent abuse:
* **Transactions**: 300 per day per user
* **Notifications**: 50 per day per user
* **Other commands**: 1000 per hour
Rate limit errors return status code `429`.
---
---
url: /quick-start/commands.md
---
# Commands
Commands are methods you call on the SDK to interact with the blockchain, device features, and platform capabilities.
## How Commands Work
All commands are available through the SDK instance:
```typescript
const sdk = window.movementSDK;
// Call a command
const result = await sdk.sendTransaction({...});
```
Commands return promises that resolve with results or reject with errors.
## Command Categories
### Blockchain Commands
Execute on-chain operations:
```typescript
// Send transaction
const tx = await sdk.sendTransaction({
function: '0x1::aptos_account::transfer',
arguments: [recipient, amount],
type_arguments: []
});
// Sign message
const signature = await sdk.signMessage({
message: 'Hello Movement',
nonce: '12345'
});
// Get balance
const balance = await sdk.getBalance();
> Note: `sdk.getAccount()` is not exposed on `window.movementSDK` in the current host. Use `window.aptos.account()` instead.
// Get account info
const account = await sdk.getAccount();
```
### Device Commands
Access device features:
```typescript
// Scan QR code
const address = await sdk.scanQRCode();
// Trigger haptic feedback
await sdk.haptic({ type: 'impact', style: 'medium' });
> Note: `sdk.camera.*` is not implemented in the current host.
// Take photo
const photo = await sdk.camera.takePicture();
> Note: `sdk.biometric.*` is not implemented in the current host.
// Authenticate with biometrics
const auth = await sdk.biometric.authenticate({
promptMessage: 'Confirm transaction'
});
> Note: `sdk.location.*` is not implemented in the current host.
// Get location
const location = await sdk.location.getCurrentPosition();
```
### Platform Commands
Use platform features:
```typescript
// Send notification
await sdk.notify({
title: 'Transaction Complete',
body: 'Your transfer was successful'
});
// Share content
await sdk.share({
message: 'Check out my mini app!',
url: 'https://moveeverything.app/apps/my-app'
});
> Note: Use `sdk.CloudStorage.setItem/getItem` instead of `sdk.storage.*` in the current host.
// Save to storage
await sdk.storage.set('user_prefs', JSON.stringify(prefs));
// Get from storage
const data = await sdk.storage.get('user_prefs');
```
## Async Pattern
All commands are asynchronous and return promises:
```typescript
// Using async/await
async function sendTokens() {
try {
const result = await sdk.sendTransaction({...});
console.log('Success:', result.hash);
} catch (error) {
console.error('Error:', error.message);
}
}
// Using .then/.catch
sdk.sendTransaction({...})
.then(result => {
console.log('Success:', result.hash);
})
.catch(error => {
console.error('Error:', error.message);
});
```
## Event Pattern (Advanced)
Subscribe to real-time updates:
```typescript
> Note: `sdk.onTransactionUpdate` is not implemented in the current host.
// Listen for transaction updates
sdk.onTransactionUpdate(hash, (status) => {
if (status.status === 'success') {
console.log('Transaction confirmed!');
} else if (status.status === 'failed') {
console.error('Transaction failed:', status.error);
}
});
// Listen for balance changes
sdk.on('balance:updated', (balance) => {
updateBalanceUI(balance);
});
// Cleanup when done
sdk.off('balance:updated', handler);
```
## Command Options
Most commands accept optional parameters:
```typescript
// Basic usage
await sdk.sendTransaction({
function: '0x1::aptos_account::transfer',
arguments: [recipient, amount],
type_arguments: []
});
// With options
await sdk.sendTransaction({
function: '0x1::aptos_account::transfer',
arguments: [recipient, amount],
type_arguments: [],
// Display metadata
title: 'Send MOVE',
description: 'Transfer 1 MOVE to Alice',
toAddress: recipient,
amount: '1',
// Advanced options
maxGasAmount: '1000',
gasUnitPrice: '100'
});
```
## Chaining Commands
Chain multiple commands together:
```typescript
async function claimAndSend() {
// Claim reward
const claimTx = await sdk.sendTransaction({
function: '0xGame::rewards::claim',
arguments: [playerId]
});
// Wait for confirmation
await sdk.waitForTransaction(claimTx.hash);
// Get new balance
const balance = await sdk.getBalance();
// Send to another address
const sendTx = await sdk.sendTransaction({
function: '0x1::aptos_account::transfer',
arguments: [friendAddress, amount]
});
return sendTx.hash;
}
```
## Error Handling
Always handle errors gracefully:
```typescript
try {
const result = await sdk.sendTransaction({...});
// Check result
if (result.success) {
await sdk.notify({
title: 'Success!',
body: 'Transaction confirmed'
});
}
} catch (error) {
// Handle specific errors
switch (error.code) {
case 'USER_REJECTED':
console.log('User cancelled transaction');
break;
case 'INSUFFICIENT_BALANCE':
showError('Not enough balance');
break;
case 'RATE_LIMIT_EXCEEDED':
showError('Too many requests, try again later');
break;
default:
showError('Transaction failed: ' + error.message);
}
}
```
## Rate Limiting
Commands are rate-limited to prevent abuse:
| Command Type | Limit | Window |
|--------------|-------|--------|
| Transactions | 300 | Per day |
| Notifications | 50 | Per day |
| Storage operations | 1000 | Per hour |
| Other commands | 1000 | Per hour |
Check remaining quota:
```typescript
const limits = await sdk.getRateLimitStatus();
console.log('Remaining transactions:', limits.transactions.remaining);
console.log('Resets at:', new Date(limits.transactions.reset));
```
## Best Practices
::: tip USER FEEDBACK
Always provide loading states and feedback:
```typescript
setLoading(true);
try {
const result = await sdk.sendTransaction({...});
showSuccess('Transaction sent!');
} catch (error) {
showError(error.message);
} finally {
setLoading(false);
}
```
:::
::: tip ERROR HANDLING
Handle all error cases explicitly:
```typescript
try {
await sdk.sendTransaction({...});
} catch (error) {
if (error.code === 'USER_REJECTED') {
// User cancelled - don't show error
} else if (error.code === 'INSUFFICIENT_BALANCE') {
showError('Insufficient balance');
} else {
// Log unexpected errors
console.error('Unexpected error:', error);
showError('Something went wrong');
}
}
```
:::
::: warning VALIDATION
Validate inputs before calling commands:
```typescript
// ❌ Bad
await sdk.sendTransaction({
function: '0x1::aptos_account::transfer',
arguments: [userInput, amount] // Not validated!
});
// ✅ Good
if (!isValidAddress(recipient)) {
throw new Error('Invalid address');
}
if (amount <= 0) {
throw new Error('Amount must be positive');
}
await sdk.sendTransaction({
function: '0x1::aptos_account::transfer',
arguments: [recipient, amount]
});
```
:::
## Next Steps
* **[Responses →](/quick-start/responses)** - Handle command results
* **[Testing →](/quick-start/testing)** - Test your commands
* **[Commands Reference →](/commands/)** - See all available commands
---
---
url: /guidelines/design.md
---
# Design Guidelines
Build beautiful, intuitive mini apps that feel native to Movement wallet using the Movement Design System.
## Design Principles
### 1. Mobile-First
Design for mobile screens from the start. Most users will never see your app on desktop.
```css
/* ✅ Good - Mobile-first approach */
.card {
padding: 1rem;
font-size: 16px;
}
@media (min-width: 768px) {
.card {
padding: 2rem;
font-size: 18px;
}
}
/* ❌ Bad - Desktop-first */
.card {
padding: 2rem;
font-size: 18px;
}
@media (max-width: 768px) {
.card {
padding: 1rem; /* Often forgotten */
}
}
```
### 2. Thumb-Friendly
Design for one-handed use. Place important actions within thumb reach.
**Guidelines:**
* Primary actions in bottom third
* Minimum touch target: 44x44px
* Spacing between targets: 8px minimum
### 3. Fast & Responsive
Users expect instant feedback. Optimize for performance.
* **First load:** < 3 seconds
* **Subsequent loads:** < 1 second (cached)
* **Animations:** 60 FPS
* **Touch response:** < 100ms
### 4. Consistent with Movement
Match Movement wallet's design language for familiar UX. Use the Movement Design System components for consistency.
## Movement Design System
The Movement Design System provides a complete set of components, tokens, and patterns for building consistent mini apps.
### Getting Started
Install the design system:
```bash
npm install movement-design-system
# or
pnpm add movement-design-system
```
Import styles in your app:
```css
@import "movement-design-system/component-styles";
@import "movement-design-system/theme";
```
### Documentation
::: tip Design System Docs
Browse the complete [Movement Design System documentation](https://movement-design-system-docs-git-shadcn-movement-labs.vercel.app/) for:
* All available components (Card, Button, Badge, etc.)
* Component variants and props
* Interactive examples
* Theme customization
:::
**Note:** The design system docs require login to view.
### Available Components
The design system includes:
* **Layout**: Card, CardHeader, CardContent, CardFooter, CardTitle, CardDescription
* **Buttons**: Button (with variants: default, outline, ghost, link)
* **Forms**: Input, Textarea, Select, Checkbox, Radio
* **Feedback**: Badge, Alert, Toast
* **Navigation**: Tabs, Accordion
* **Display**: Avatar, Separator
* **Icons**: Comprehensive icon library
See the [design system docs](https://movement-design-system-docs-git-shadcn-movement-labs.vercel.app/) for complete component documentation.
## Color Palette
The Movement Design System provides all color tokens. Import the theme to access them:
```css
@import "movement-design-system/theme";
/* Primary brand color */
--movement-primary: #00D4AA;
/* Semantic colors */
--success: #00D4AA;
--warning: #FFB020;
--error: #FF4444;
--info: #3B82F6;
```
For complete color documentation, see the [design system theme docs](https://movement-design-system-docs-git-shadcn-movement-labs.vercel.app/?path=/story/movement-design-system-theme--colors).
## Typography
### Font Stack
```css
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
'Roboto', 'Helvetica', 'Arial', sans-serif;
}
```
### Font Sizes
```css
/* Scale */
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
```
### Usage
```css
/* Body text */
body {
font-size: var(--text-base);
line-height: 1.5;
}
/* Headings */
h1 { font-size: var(--text-3xl); font-weight: 700; }
h2 { font-size: var(--text-2xl); font-weight: 600; }
h3 { font-size: var(--text-xl); font-weight: 600; }
/* Labels */
.label {
font-size: var(--text-sm);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Captions */
.caption {
font-size: var(--text-xs);
color: var(--text-secondary);
}
```
## Spacing
Use consistent spacing based on 4px grid:
```css
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
```
### Layout Example
```tsx
Send MOVE
```
## Components
Use the Movement Design System components instead of building custom ones. This ensures consistency and reduces maintenance.
### Using Design System Components
```tsx
import { Button, Card, CardContent, CardHeader, CardTitle, Badge } from 'movement-design-system';
// Button with variants
// Card components
Card Title
Card content goes here
// Badge
SuccessWarning
```
### Component Documentation
For complete component documentation, including:
* All available props and variants
* Usage examples
* Interactive playgrounds
* Accessibility guidelines
See the [Movement Design System component docs](https://movement-design-system-docs-git-shadcn-movement-labs.vercel.app/?path=/story/movement-design-system-card--grid-layout-dots).
## Layout Patterns
### Full-Screen Card
```tsx
);
}
```
### Spinners
```tsx
function Spinner() {
return (
);
}
```
## Error States
Show clear, actionable error messages:
```tsx
function ErrorMessage({ message, onRetry }) {
return (
⚠️
Transaction Failed
{message}
{onRetry && (
)}
);
}
```
## Best Practices
::: tip CONSISTENCY
Use consistent spacing, colors, and patterns throughout your app.
:::
::: tip FEEDBACK
Provide immediate feedback for all user actions (haptics, animations, messages).
:::
::: tip PERFORMANCE
Optimize images, lazy-load content, minimize bundle size.
:::
::: warning AVOID
* Don't use pure black (#000) - use dark gray
* Don't animate expensive properties (use `transform` and `opacity`)
* Don't hide errors - show helpful messages
:::
## Resources
* **[Movement Design System Docs](https://movement-design-system-docs-git-shadcn-movement-labs.vercel.app/)** - Complete component library and documentation
* **[Design System GitHub](https://github.com/movementlabsxyz/movement-design-system)** - Source code and issues
## Examples
Check out these real mini apps that use the Movement Design System:
* **[Scaffold App](/examples/scaffold)** - Complete SDK reference implementation with design system components
* **[Social App](/examples/social)** - Social features with on-chain interactions
These examples demonstrate:
* Proper use of design system components (Card, Button, Badge)
* Consistent styling and theming
* Mobile-first responsive layouts
* Best practices for mini app design
---
---
url: /commands/haptic.md
---
# Haptic Feedback
Provide tactile feedback to enhance user experience with physical sensations.
## Basic Usage
```typescript
await sdk.haptic({ type: 'impact', style: 'medium' });
```
## Parameters
### `type`
Type of haptic feedback:
* `'impact'` - Physical collision (button press, tap)
* `'notification'` - Alerts and results (success, warning, error)
* `'selection'` - UI selection changed (picker, toggle)
### `style`
Intensity of feedback (for `impact` and `selection` types):
* `'light'` - Subtle feedback
* `'medium'` - Standard feedback (default)
* `'heavy'` - Strong feedback
For `notification` type:
* `'success'` - Positive outcome
* `'warning'` - Cautionary
* `'error'` - Negative outcome
## Examples
### Button Press
```typescript
function SubmitButton({ onClick }) {
async function handleClick() {
await sdk.haptic({ type: 'impact', style: 'medium' });
onClick();
}
return ;
}
```
### Transaction Result
```typescript
try {
const result = await sdk.sendTransaction({...});
// Success haptic
await sdk.haptic({ type: 'notification', style: 'success' });
} catch (error) {
// Error haptic
await sdk.haptic({ type: 'notification', style: 'error' });
}
```
### Toggle Switch
```typescript
function Toggle({ checked, onChange }) {
async function handleToggle() {
await sdk.haptic({ type: 'selection' });
onChange(!checked);
}
return (
);
}
```
### Picker Selection
```typescript
function TokenPicker({ tokens, onSelect }) {
async function handleSelect(token) {
await sdk.haptic({ type: 'selection' });
onSelect(token);
}
return (
{tokens.map(token => (
))}
);
}
```
### Long Press
```typescript
function DeleteButton({ onDelete }) {
async function handleLongPress() {
await sdk.haptic({ type: 'impact', style: 'heavy' });
const confirmed = await sdk.showConfirm(
'Are you sure you want to delete this?'
);
if (confirmed) {
onDelete();
await sdk.haptic({ type: 'notification', style: 'success' });
}
}
return (
);
}
```
## Haptic Patterns
### Common Patterns
```typescript
// Button tap
sdk.haptic({ type: 'impact', style: 'light' });
// Important action
sdk.haptic({ type: 'impact', style: 'medium' });
// Delete/destructive action
sdk.haptic({ type: 'impact', style: 'heavy' });
// Success
sdk.haptic({ type: 'notification', style: 'success' });
// Warning
sdk.haptic({ type: 'notification', style: 'warning' });
// Error
sdk.haptic({ type: 'notification', style: 'error' });
// Picker/dropdown selection
sdk.haptic({ type: 'selection' });
```
### Transaction Flow
```typescript
async function sendTokens() {
// Button press
await sdk.haptic({ type: 'impact', style: 'medium' });
try {
// Sending...
const result = await sdk.sendTransaction({...});
// Success
await sdk.haptic({ type: 'notification', style: 'success' });
await sdk.notify({
title: 'Success!',
body: 'Transaction confirmed'
});
} catch (error) {
// Error
await sdk.haptic({ type: 'notification', style: 'error' });
}
}
```
## Platform Support
| Platform | Support | Notes |
|----------|---------|-------|
| iOS | ✅ Full | Taptic Engine |
| Android | ✅ Full | Vibration API |
## Best Practices
::: tip USE SPARINGLY
Don't overuse haptics - they should enhance, not distract.
```typescript
// ✅ Good - meaningful actions
button.onClick = () => {
sdk.haptic({ type: 'impact', style: 'light' });
navigate();
};
// ❌ Bad - every UI change
div.onMouseEnter = () => {
sdk.haptic({ type: 'impact' }); // Too much!
};
```
:::
::: tip MATCH INTENSITY
Match haptic intensity to action importance:
```typescript
// Light - minor actions
sdk.haptic({ type: 'impact', style: 'light' }); // Tap button
// Medium - standard actions
sdk.haptic({ type: 'impact', style: 'medium' }); // Submit form
// Heavy - important/destructive actions
sdk.haptic({ type: 'impact', style: 'heavy' }); // Delete item
```
:::
::: tip COMBINE WITH VISUAL FEEDBACK
Haptics should complement, not replace, visual feedback:
```typescript
async function handleSubmit() {
setLoading(true); // Visual feedback
await sdk.haptic({ type: 'impact' }); // Haptic feedback
const result = await submit();
if (result.success) {
setSuccess(true); // Visual
await sdk.haptic({ type: 'notification', style: 'success' }); // Haptic
}
}
```
:::
::: warning ACCESSIBILITY
Some users may have haptics disabled. Never rely solely on haptics for critical feedback.
:::
## Error Handling
Haptics may fail silently if unsupported:
```typescript
try {
await sdk.haptic({ type: 'impact' });
} catch (error) {
// Haptic failed - continue anyway
console.log('Haptic unavailable');
}
```
## Related
* [Notifications](/commands/notifications) - Alert users
* [Scan QR Code](/commands/scan-qr) - Scan with haptic feedback
---
---
url: /quick-start/installing.md
---
# Installing
Get the Movement SDK integrated into your project.
## Quick Start
Create a new mini app with our starter template:
```bash
npx create-movement-app@latest my-app
cd my-app
npm run dev
```
This creates a fully configured Next.js app with the SDK pre-installed.
## Manual Installation
### For Next.js / React
Install the SDK package:
```bash
npm install @movement-labs/miniapp-sdk
```
Use the React hook in your components:
```tsx
// app/page.tsx or any component
'use client';
import { useMovementSDK } from '@movement-labs/miniapp-sdk';
export default function MyComponent() {
const { sdk, isConnected, address, isLoading } = useMovementSDK();
// Loading state while SDK initializes
if (isLoading) {
return
Loading...
;
}
// Check if app is running in Movement wallet
if (!sdk?.isInstalled()) {
return (
Not in Movement App
Please open this app inside Movement wallet
);
}
// SDK is ready
return (
Connected: {isConnected ? 'Yes' : 'No'}
Address: {address || 'Not connected'}
);
}
```
The `useMovementSDK()` hook automatically:
* Checks if SDK is installed with `isInstalled()`
* Waits for SDK to be ready with `ready()`
* Returns connection state and user address
* Handles loading states
### For Vanilla JavaScript
The SDK is automatically injected by Movement wallet:
```html
My Mini App
Loading...
```
### For Unity
1. Download the Movement Unity SDK package:
```bash
# Coming soon
```
2. Import into Unity:
* Assets → Import Package → Custom Package
* Select `MovementSDK.unitypackage`
3. Add to your scene:
```csharp
using MovementSDK;
public class GameManager : MonoBehaviour {
void Start() {
if (MovementSDK.Instance.IsInstalled()) {
string address = MovementSDK.Instance.GetAddress();
Debug.Log("Connected: " + address);
}
}
}
```
## SDK Detection & Ready State
Movement SDK provides two key methods for reliable initialization:
### `isInstalled()`
Returns `true` if your app is running inside Movement wallet:
```typescript
const isInMovementApp = window.movementSDK?.isInstalled();
if (!isInMovementApp) {
// Show error: "Please open in Movement wallet"
}
```
### `ready()`
Waits for the SDK to be fully initialized before allowing method calls:
```typescript
await window.movementSDK.ready();
// Now safe to call any SDK method
const account = await window.movementSDK.getAccount();
```
### Complete Pattern
Always use both methods together. The `useMovementSDK()` hook automatically calls `ready()` for you:
::: code-group
```typescript [React]
import { useMovementSDK } from '@movement-labs/miniapp-sdk';
function App() {
const { sdk, isLoading, error } = useMovementSDK();
// useMovementSDK() automatically calls sdk.ready() internally
if (isLoading) {
return
);
}
```
## Error Handling
```typescript
try {
const address = await sdk.scanQRCode();
} catch (error) {
switch (error.code) {
case 'PERMISSION_DENIED':
showError('Camera permission denied');
break;
case 'USER_CANCELLED':
// User cancelled scan - don't show error
console.log('Scan cancelled');
break;
case 'NOT_SUPPORTED':
showError('QR scanning not supported on this device');
break;
default:
showError('Failed to scan QR code');
}
}
```
## Use Cases
* Scanning wallet addresses for transfers
* Scanning payment request QR codes
* Scanning deep links to other mini apps
* Scanning authentication codes
## Best Practices
::: tip VALIDATION
Always validate scanned data:
```typescript
const scanned = await sdk.scanQRCode();
if (!isValidAddress(scanned)) {
throw new Error('Invalid address format');
}
```
:::
::: tip FEEDBACK
Provide haptic feedback on successful scan:
```typescript
const address = await sdk.scanQRCode();
await sdk.haptic({ type: 'notification', style: 'success' });
```
:::
::: warning PERMISSIONS
Scanner may fail if camera permission is denied. Handle gracefully.
:::
## Related
* [Haptic Feedback](/commands/haptic) - Provide tactile feedback
* Camera *(Coming Soon)* - Capture photos
---
---
url: /reference/sdk-api.md
---
# SDK API Reference
Complete reference for all Movement SDK methods and properties.
## Installation
```bash
npm install @movement-labs/miniapp-sdk
```
## SDK Status
### `isInstalled()`
Check if the app is running inside Movement wallet.
**Returns:** `boolean`
```typescript
const isInMovementApp = window.movementSDK.isInstalled();
if (!isInMovementApp) {
console.error('App must run in Movement wallet');
}
```
**When to use:**
* Always check before using any SDK method
* Show error messages if not in Movement app
* Conditionally render UI based on environment
**Example:**
```tsx
function App() {
if (!window.movementSDK?.isInstalled()) {
return (
Not Available
Please open this app inside Movement wallet
);
}
return ;
}
```
***
### `ready()`
Wait for the SDK to be fully initialized before using methods.
**Returns:** `Promise`
```typescript
await window.movementSDK.ready();
console.log('SDK is ready!');
```
**When to use:**
* After checking `isInstalled()`
* Before calling any SDK methods
* In initialization code
**Example:**
```typescript
async function initApp() {
if (!window.movementSDK?.isInstalled()) {
return;
}
// Wait for SDK to be ready
await window.movementSDK.ready();
// Now safe to use SDK
const account = await window.movementSDK.getAccount();
console.log('Account:', account);
}
```
**Timeout:**
The `ready()` method has a 2-second timeout. If initialization takes longer, it resolves anyway:
```typescript
try {
await window.movementSDK.ready();
} catch (error) {
console.error('SDK initialization timeout:', error);
}
```
***
## Properties
### `isConnected`
**Type:** `boolean`
Whether a wallet is currently connected.
```typescript
if (sdk.isConnected) {
console.log('Wallet is connected');
}
```
***
### `address`
**Type:** `string | undefined`
The connected wallet address (if connected).
```typescript
const address = sdk.address;
console.log('Address:', address);
// Address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
```
***
### `network`
**Type:** `'mainnet' | 'testnet' | 'devnet'`
Current network the wallet is connected to.
```typescript
const network = sdk.network;
console.log('Network:', network);
// Network: mainnet
```
***
## Account Methods
### `connect()`
Connect to the user's wallet and request access.
**Returns:** `Promise`
```typescript
const account = await sdk.connect();
console.log('Connected:', account.address);
```
**Example:**
```tsx
function ConnectButton() {
const [account, setAccount] = useState(null);
async function handleConnect() {
try {
const acc = await sdk.connect();
setAccount(acc);
} catch (error) {
console.error('Connection failed:', error);
}
}
return (
);
}
```
***
### `getAccount()`
> Note: Not exposed on `window.movementSDK` in the current host. Use `window.aptos.account()` instead. A future update may expose `sdk.getAccount()` directly.
Get the current account information.
**Returns:** `Promise`
```typescript
interface MovementAccount {
address: string;
publicKey: string;
balance?: string;
}
```
**Example:**
```typescript
const account = await sdk.getAccount();
console.log('Account:', account);
// { address: '0x...', publicKey: '0x...', balance: '1.5' }
```
***
### `getBalance()`
Get the current MOVE token balance.
**Returns:** `Promise`
```typescript
const balance = await sdk.getBalance();
console.log('Balance:', balance, 'MOVE');
// Balance: 1.5 MOVE
```
***
### `getContext()`
> Note: Handler exists in host, but `sdk.getContext()` is not exposed on `window.movementSDK` yet.
Get comprehensive app context including user, app, and platform info.
**Returns:** `Promise`
```typescript
interface AppContext {
user: {
address: string;
publicKey: string;
verified: boolean;
};
app: {
id: string;
name: string;
version: string;
};
platform: {
os: 'ios' | 'android';
version: string;
};
features: {
haptics: boolean;
notifications: boolean;
camera: boolean;
biometrics: boolean;
location: boolean;
};
}
```
**Example:**
```typescript
const context = await sdk.getContext();
console.log('Platform:', context.platform.os);
console.log('Features:', context.features);
```
***
### `getTheme()`
Get the current theme (light or dark mode) from the host app.
**Returns:** `Promise`
```typescript
interface ThemeInfo {
colorScheme: 'light' | 'dark';
}
```
**Example:**
```typescript
const theme = await sdk.getTheme();
if (theme.colorScheme === 'dark') {
// Apply dark mode styles
document.body.classList.add('dark-mode');
} else {
// Apply light mode styles
document.body.classList.remove('dark-mode');
}
```
***
## Transaction Methods
### `view()`
Call a Move view function (read-only, no wallet required).
**Parameters:**
```typescript
interface ViewPayload {
function: string; // address::module::function
function_arguments?: any[]; // function args (preferred key)
type_arguments?: string[]; // generic type args
// Backwards-compat: some hosts also accept camelCase
functionArguments?: any[];
typeArguments?: string[];
}
```
**Returns:** `Promise` (the decoded view result)
The result may be a primitive, struct, or array. Some hosts may wrap results in an extra array.
**Example:**
```typescript
const result = await sdk.view({
function: '0xabc::leaderboard::get_leaderboard',
function_arguments: ['50'],
type_arguments: [],
});
// Handle wrapped arrays
const entries = Array.isArray(result)
? (Array.isArray(result[0]) ? result[0] : result)
: [];
```
### `sendTransaction()`
Send a transaction on the Movement blockchain.
**Parameters:**
```typescript
interface TransactionPayload {
function: string; // Module function to call
arguments: any[]; // Function arguments
type_arguments: string[]; // Type arguments (generics)
}
```
**Returns:** `Promise`
```typescript
interface TransactionResult {
hash: string;
success: boolean;
version?: string;
vmStatus?: string;
}
```
**Example:**
```typescript
const result = await sdk.sendTransaction({
function: '0x1::aptos_account::transfer',
arguments: ['0x123...', '1000000'],
type_arguments: []
});
console.log('Transaction hash:', result.hash);
```
***
### `waitForTransaction()`
Wait for a transaction to be confirmed on-chain.
**Parameters:** `hash: string`
**Returns:** `Promise`
```typescript
interface TransactionStatus {
hash: string;
status: 'pending' | 'success' | 'failed';
gasUsed?: string;
timestamp?: number;
error?: string;
}
```
**Example:**
```typescript
const result = await sdk.sendTransaction({...});
const status = await sdk.waitForTransaction(result.hash);
if (status.status === 'success') {
console.log('Transaction confirmed!');
} else {
console.error('Transaction failed:', status.error);
}
```
***
### `onTransactionUpdate()`
Subscribe to real-time transaction status updates.
**Parameters:** `hash: string, callback: (status: TransactionStatus) => void`
**Returns:** `() => void` (unsubscribe function)
```typescript
// Subscribe to transaction updates
const unsubscribe = sdk.onTransactionUpdate?.(result.hash, (status) => {
console.log('Transaction status:', status.status);
if (status.status === 'success') {
console.log('Transaction confirmed!');
unsubscribe();
} else if (status.status === 'failed') {
console.error('Transaction failed:', status.error);
unsubscribe();
}
});
// Clean up when component unmounts
useEffect(() => {
return () => unsubscribe?.();
}, []);
```
***
### `signMessage()`
> Note: Not yet implemented in the current host. Calls will fail. Prefer server-side challenges or wait for host support.
Sign an arbitrary message with the user's private key.
**Parameters:**
```typescript
interface SignMessagePayload {
message: string;
nonce?: string; // Optional nonce for replay protection
}
```
**Returns:** `Promise`
```typescript
interface SignMessageResult {
signature: string;
publicKey: string;
fullMessage?: string;
}
```
**Example:**
```typescript
const result = await sdk.signMessage({
message: 'Welcome to my app!',
nonce: Date.now().toString()
});
console.log('Signature:', result.signature);
```
***
## MNS (Movement Name Service)
The MNS API allows you to resolve human-readable `.move` names to wallet addresses and perform reverse lookups.
### `mns.getTargetAddress()`
Resolve a `.move` name to its associated wallet address.
**Parameters:** `name: string` - The name to resolve (e.g., "alice" or "alice.move")
**Returns:** `Promise` - An AccountAddress object or null if not found
The result is an `AccountAddress` object from the Movement SDK, which may need to be converted to a hex string:
**Example:**
```typescript
const result = await sdk.mns.getTargetAddress('alice.move');
if (!result) {
console.log('Name not found');
return;
}
// Handle AccountAddress object - convert to hex string
let address: string | null = null;
if (typeof result === 'string') {
address = result;
} else if (result && typeof result === 'object' && 'data' in result) {
// Convert byte array to hex address
const data = (result as any).data;
const bytes = Object.keys(data)
.sort((a, b) => Number(a) - Number(b))
.map(k => data[k]);
if (bytes.length > 0 && bytes.some((b: number) => b !== 0)) {
address = '0x' + bytes.map((b: number) => b.toString(16).padStart(2, '0')).join('');
}
}
console.log('Resolved address:', address);
```
***
### `mns.getPrimaryName()`
Get the primary `.move` name associated with a wallet address (reverse lookup).
**Parameters:** `address: string`
**Returns:** `Promise`
**Example:**
```typescript
const name = await sdk.mns.getPrimaryName('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb...');
console.log('Name:', name);
// alice
```
***
**Use Cases:**
* Allow users to send tokens to `.move` names instead of addresses
* Display human-readable names in transaction history
* Verify name ownership before transfers
***
## Device Features
### `scanQRCode()`
Open the camera to scan a QR code.
**Returns:** `Promise`
```typescript
const scannedData = await sdk.scanQRCode();
console.log('Scanned:', scannedData);
```
**Example:**
```tsx
async function handleScan() {
try {
const address = await sdk.scanQRCode();
setRecipient(address);
} catch (error) {
if (error.message !== 'QR code scan cancelled') {
console.error('Scan failed:', error);
}
}
}
```
***
### `haptic()`
Provide tactile feedback to the user.
**Parameters:**
```typescript
interface HapticOptions {
type: 'impact' | 'notification' | 'selection';
style?: 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error';
}
```
**Example:**
```typescript
// Button press
await sdk.haptic({ type: 'impact', style: 'light' });
// Success feedback
await sdk.haptic({ type: 'notification', style: 'success' });
// Selection change
await sdk.haptic({ type: 'selection' });
```
***
### `notify()`
Send a push notification to the user.
**Parameters:**
```typescript
interface NotificationOptions {
title: string;
body: string;
data?: Record;
}
```
**Example:**
```typescript
await sdk.notify({
title: 'Transaction Complete',
body: 'Your transfer was successful',
data: {
deepLink: '/transactions',
txHash: result.hash
}
});
```
***
### `share()`
Open the native share sheet.
**Parameters:**
```typescript
interface ShareOptions {
title?: string;
message: string;
url?: string;
}
```
**Returns:** `Promise<{ success: boolean }>`
**Example:**
```typescript
await sdk.share({
title: 'Check out this mini app!',
message: 'Play this awesome game on Movement',
url: 'https://moveeverything.app/apps/my-game'
});
```
***
### `Clipboard`
Copy and paste text.
**Methods:**
```typescript
// Copy text to clipboard
await sdk.Clipboard.writeText(text: string): Promise
// Read text from clipboard
const text = await sdk.Clipboard.readText(): Promise
```
**Example:**
```typescript
// Copy wallet address
await sdk.Clipboard.writeText(address);
await sdk.showAlert('Address copied to clipboard!');
// Paste from clipboard
const pastedText = await sdk.Clipboard.readText();
setRecipientAddress(pastedText);
```
***
### `camera`
> Note: Not yet implemented in the current host.
Access device camera and photo library.
```typescript
// Take picture
await sdk.camera.takePicture(options?: CameraOptions): Promise
// Pick from library
await sdk.camera.pickImage(options?: CameraOptions): Promise
```
**Options:**
```typescript
interface CameraOptions {
quality?: number; // 0-1
allowsEditing?: boolean;
mediaTypes?: 'photo' | 'video' | 'all';
}
```
**Returns:**
```typescript
interface CameraResult {
uri: string;
width: number;
height: number;
type: 'image' | 'video';
}
```
***
### `location`
> Note: Not yet implemented in the current host.
Access device location.
```typescript
// Get current position
await sdk.location.getCurrentPosition(): Promise
// Watch position changes
const unsubscribe = sdk.location.watchPosition((position) => {
console.log(position);
});
```
**LocationResult:**
```typescript
interface LocationResult {
latitude: number;
longitude: number;
accuracy: number;
altitude?: number;
heading?: number;
speed?: number;
}
```
***
### `biometric`
> Note: Not yet implemented in the current host.
Authenticate with FaceID/TouchID.
```typescript
// Check availability
await sdk.biometric.isAvailable(): Promise
// Authenticate
await sdk.biometric.authenticate(options?: BiometricOptions): Promise
```
**Options:**
```typescript
interface BiometricOptions {
promptMessage?: string;
cancelText?: string;
fallbackToPasscode?: boolean;
}
```
**Returns:**
```typescript
interface BiometricResult {
success: boolean;
biometricType?: 'FaceID' | 'TouchID' | 'Fingerprint';
}
```
***
## Storage
### `CloudStorage`
Persistent storage for user data, preferences, and app state.
**Limits:** 1024 items per user
**Methods:**
```typescript
// Store data
await sdk.CloudStorage.setItem(key: string, value: string): Promise
// Get data
const value = await sdk.CloudStorage.getItem(key: string): Promise
// Remove data
await sdk.CloudStorage.removeItem(key: string): Promise
// Get all keys
const keys = await sdk.CloudStorage.getKeys(): Promise
```
**Example:**
```typescript
// Save user preferences
await sdk.CloudStorage.setItem('theme', 'dark');
await sdk.CloudStorage.setItem('language', 'en');
// Load preferences
const theme = await sdk.CloudStorage.getItem('theme') || 'light';
const language = await sdk.CloudStorage.getItem('language') || 'en';
// Save game progress
await sdk.CloudStorage.setItem('level', '5');
await sdk.CloudStorage.setItem('score', '1250');
// Load on app start
const level = await sdk.CloudStorage.getItem('level');
if (level) {
resumeGame(parseInt(level));
}
// Get all saved data
const allKeys = await sdk.CloudStorage.getKeys();
console.log('Saved keys:', allKeys);
```
**Use Cases:**
* Save game progress
* Store user preferences (theme, language)
* Cache frequently accessed data
* Persist form drafts
***
### `storage.get()`
> Note: The simple `storage.*` API is not exposed in the current host. Use `CloudStorage.*` instead.
Get a value from local storage.
**Parameters:** `key: string`
**Returns:** `Promise`
```typescript
const value = await sdk.storage.get('user_preferences');
```
***
### `storage.set()`
> Note: Use `CloudStorage.setItem(key, value)` instead.
Set a value in local storage.
**Parameters:** `key: string, value: string`
**Returns:** `Promise`
```typescript
await sdk.storage.set('user_preferences', JSON.stringify(prefs));
```
***
### `storage.remove()`
> Note: Use `CloudStorage.removeItem(key)` instead.
Remove a value from local storage.
**Parameters:** `key: string`
**Returns:** `Promise`
```typescript
await sdk.storage.remove('user_preferences');
```
***
### `storage.clear()`
> Note: Not exposed. You can emulate by iterating `CloudStorage.getKeys()` and removing each.
Clear all storage data for this app.
**Returns:** `Promise`
```typescript
await sdk.storage.clear();
```
***
### `storage.getAll()`
Get all stored key-value pairs.
**Returns:** `Promise<{ key: string; value: string }[]>`
```typescript
const allData = await sdk.storage?.getAll();
console.log('All stored data:', allData);
// [{ key: 'theme', value: 'dark' }, { key: 'language', value: 'en' }]
```
***
## UI Components
### `MainButton`
Fixed bottom button for primary actions.
**Methods:**
```typescript
// Set button text
sdk.MainButton.setText(text: string): void
// Show button
sdk.MainButton.show(): void
// Hide button
sdk.MainButton.hide(): void
// Handle click
sdk.MainButton.onClick(callback: () => void): void
```
**Example:**
```typescript
// Set up send button
sdk.MainButton.setText('Send 10 MOVE');
sdk.MainButton.show();
sdk.MainButton.onClick(async () => {
const confirmed = await sdk.showConfirm('Send 10 MOVE to recipient?');
if (confirmed) {
await sendTransaction();
}
});
```
***
### `SecondaryButton`
Secondary fixed bottom button.
**Methods:**
```typescript
sdk.SecondaryButton.setText(text: string): void
sdk.SecondaryButton.show(): void
sdk.SecondaryButton.hide(): void
sdk.SecondaryButton.onClick(callback: () => void): void
```
**Example:**
```typescript
sdk.MainButton.setText('Send');
sdk.SecondaryButton.setText('Cancel');
sdk.SecondaryButton.show();
sdk.SecondaryButton.onClick(() => {
sdk.MainButton.hide();
sdk.SecondaryButton.hide();
resetForm();
});
```
***
### `BackButton`
Back button for navigation.
**Methods:**
```typescript
sdk.BackButton.show(): void
sdk.BackButton.hide(): void
sdk.BackButton.onClick(callback: () => void): void
```
**Example:**
```typescript
sdk.BackButton.show();
sdk.BackButton.onClick(() => {
// Navigate back or close modal
window.history.back();
});
```
***
### `showPopup()`
Show a popup dialog with custom buttons.
**Parameters:**
```typescript
interface PopupOptions {
title?: string;
message: string;
buttons?: PopupButton[];
}
interface PopupButton {
id?: string;
type?: 'default' | 'ok' | 'close' | 'cancel' | 'destructive';
text: string;
}
```
**Returns:** `Promise`
```typescript
const result = await sdk.showPopup({
title: 'Confirm',
message: 'Are you sure?',
buttons: [
{ id: 'yes', text: 'Yes', type: 'default' },
{ id: 'no', text: 'No', type: 'cancel' }
]
});
if (result.button_id === 'yes') {
console.log('User confirmed');
}
```
***
### `showAlert()`
Show a simple alert message.
**Parameters:** `message: string`
**Returns:** `Promise`
```typescript
await sdk.showAlert('Transaction submitted successfully!');
```
***
### `showConfirm()`
Show a confirmation dialog with OK/Cancel buttons.
**Parameters:** `message: string, okText?: string, cancelText?: string`
**Returns:** `Promise`
```typescript
const confirmed = await sdk.showConfirm(
'Delete this item?',
'Delete',
'Cancel'
);
if (confirmed) {
deleteItem();
}
```
***
## React Hooks
### `useMovementSDK()`
React hook for accessing the SDK. The hook automatically handles SDK initialization by calling `isInstalled()` and `ready()` internally.
**How it works:**
The hook internally performs these steps:
1. Checks if SDK is installed: `window.movementSDK?.isInstalled()`
2. Waits for SDK to be ready: `await window.movementSDK.ready()`
3. Returns the SDK instance and connection state
The `isLoading` state is `true` while waiting for `ready()` to complete. Once `isLoading` is `false`, the SDK is ready to use.
**Conceptually, the hook does this internally:**
```typescript
// Simplified internal implementation
function useMovementSDK() {
const [sdk, setSdk] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
async function init() {
// Step 1: Check if installed
if (!window.movementSDK?.isInstalled()) {
setIsLoading(false);
return;
}
// Step 2: Wait for ready (this is what you don't see!)
await window.movementSDK.ready();
// Step 3: SDK is ready
setSdk(window.movementSDK);
setIsLoading(false);
}
init();
}, []);
return { sdk, isLoading, ... };
}
```
**Returns:**
```typescript
interface UseMovementSDKResult {
sdk: MovementSDK | null;
isConnected: boolean;
address: string | null;
isLoading: boolean; // true while waiting for ready() to complete
error: Error | null;
connect: () => Promise;
sendTransaction: (payload: TransactionPayload) => Promise;
}
```
**Example:**
```tsx
import { useMovementSDK } from '@movement-labs/miniapp-sdk';
function MyComponent() {
const {
sdk,
isConnected,
address,
isLoading,
error,
connect,
sendTransaction
} = useMovementSDK();
if (isLoading) return
```
## Development
### Run Locally
Use any local server:
```bash
# Python
python3 -m http.server 3000
# Node.js
npx serve .
# PHP
php -S localhost:3000
```
### Test in Movement App
1. Open Movement Everything
2. Settings → Developer Mode → ON
3. Mini App Testing section
4. Enter `http://localhost:3000`
5. Click "Test App"
## Deployment
### Build
No build step needed! Just upload your files.
### Deploy
#### GitHub Pages
```bash
git init
git add .
git commit -m "Initial commit"
git branch -M gh-pages
git remote add origin https://github.com/username/repo.git
git push -u origin gh-pages
```
#### Netlify
```bash
# Drag and drop your folder to netlify.com
# Or use CLI:
netlify deploy --prod
```
#### Vercel
```bash
vercel deploy
```
## Tips
1. **Keep it simple**: Vanilla JS apps load faster
2. **Mobile first**: Design for touch interactions
3. **Test offline**: Handle network errors gracefully
4. **Progressive enhancement**: Work without SDK, enhance when available
## Next Steps
* Explore the [SDK API Reference](/reference/sdk-api)
* Check out [example projects](https://github.com/movementlabsxyz/miniapp-examples)
* Join [Movement Discord](https://discord.gg/movement)
---
---
url: /commands/view.md
---
# View Function
Call read-only Move view functions to fetch on-chain data. View calls are gasless and do not require a connected wallet.
## Basic Usage
```typescript
const result = await sdk.view({
function: '0x1::some_module::some_view',
function_arguments: [],
type_arguments: []
});
```
## Parameters
### `function`
Fully qualified function name: `address::module::function`
```typescript
function: '0xabc::leaderboard::get_leaderboard'
```
### `function_arguments`
Array of function arguments. Use strings for u64 and other large numeric types.
```typescript
function_arguments: [
'50' // u64 as string
]
```
### `type_arguments`
Generic type arguments.
```typescript
type_arguments: ['0x1::aptos_coin::AptosCoin']
```
## Return Value
Returns a `Promise` with the decoded result from the Move view function:
```typescript
// Result can be:
// - A primitive (number-like string, bool, address string)
// - An object (struct with named fields)
// - An array (vector) – sometimes wrapped like [[...]]
```
## Examples
### Top 50 Leaderboard
```typescript
const result = await sdk.view({
function: '0xabc::leaderboard::get_leaderboard',
function_arguments: ['50'],
type_arguments: []
});
// Handle wrapped arrays
const entries = Array.isArray(result) && Array.isArray(result[0]) ? result[0] : result;
```
### Read a Struct
```typescript
const postRes = await sdk.view({
function: '0xsocial::social::get_post',
function_arguments: [owner, `${index}`],
type_arguments: []
});
// Unwrap if needed
const post = Array.isArray(postRes) ? postRes[0] : postRes;
console.log(post.author, post.content);
```
### Read a Single Value
```typescript
const feeRes = await sdk.view({
function: '0xabc::leaderboard::get_game_fee',
function_arguments: [],
type_arguments: []
});
const feeOctas = Array.isArray(feeRes) ? feeRes[0] : feeRes;
const feeMove = Number(feeOctas) / 100_000_000;
```
## Error Handling
Always wrap view calls in try-catch:
```typescript
try {
const data = await sdk.view({
function: '0xabc::leaderboard::get_leaderboard',
function_arguments: ['50'],
type_arguments: []
});
// Use data
console.log('Leaderboard:', data);
} catch (error) {
if (error.code === 'FUNCTION_NOT_FOUND') {
console.error('View function does not exist');
} else if (error.code === 'INVALID_ARGUMENTS') {
console.error('Invalid function arguments');
} else {
console.error('View failed:', error.message);
}
}
```
## Best Practices
::: tip NO WALLET REQUIRED
You can call `view()` before a user connects their wallet. Great for loading public data in splash screens.
:::
::: tip STRINGS FOR NUMBERS
Always pass large integers as strings to avoid precision loss in JS.
```typescript
// ✅ Good
function_arguments: ['100000000']
// ❌ Bad - may lose precision
function_arguments: [100000000]
```
:::
::: tip UNWRAP RESULTS
The host app may wrap results in an extra array. Handle both `result` and `[result]` shapes.
```typescript
// Safely unwrap possibly-wrapped arrays
const unwrap = (val: any) =>
Array.isArray(val) && val.length === 1 && Array.isArray(val[0])
? val[0]
: val;
const entries = unwrap(result);
```
:::
::: tip CAMEL CASE COMPAT
Some hosts also accept `functionArguments` and `typeArguments` (camelCase). Prefer snake\_case for consistency.
:::
## Common Errors
| Error Code | Description | Solution |
|------------|-------------|----------|
| `FUNCTION_NOT_FOUND` | View function does not exist | Check function name and module address |
| `INVALID_ARGUMENTS` | Arguments don't match function signature | Verify argument types and count |
| `NETWORK_ERROR` | Connection issue | Retry with exponential backoff |
| `RATE_LIMIT_EXCEEDED` | Too many requests | Wait before retrying |
## Related
* [Send Transaction](./send-transaction.md) – write functions that modify state
* [SDK API Reference](../reference/sdk-api.md) – complete API documentation