DApp Developer
Getting Started with SORA Development
Getting Started with SORA Development
Section titled “Getting Started with SORA Development”Welcome to SORA development! This guide will help you set up your environment, understand the ecosystem, and start building applications on the SORA network.
Choose Your Path
Section titled “Choose Your Path”Smart Contract Developer
Integration Developer
Connect existing systems to SORA via APIs and bridges.
Infrastructure
Run nodes, validators, or indexing services.
Prerequisites
Section titled “Prerequisites”Required Knowledge
Section titled “Required Knowledge”| Topic | Level | Why |
|---|---|---|
| JavaScript/TypeScript | Intermediate | Frontend + SDK usage |
| Blockchain Basics | Beginner | Transaction concepts |
| React (optional) | Beginner | Frontend development |
| Rust (optional) | Beginner | Smart contracts (v3) |
System Requirements
Section titled “System Requirements”# Node.js 18+node --version # v18.0.0 or higher
# pnpm (recommended) or npmpnpm --version # 8.0.0 or higher
# Gitgit --versionQuick Start
Section titled “Quick Start”Option 1: Polkaswap Integration
Section titled “Option 1: Polkaswap Integration”The fastest way to integrate with SORA:
-
Install the SDK
Terminal window pnpm add @sora-substrate/sdk @polkadot/api -
Initialize Connection
import { Api } from '@sora-substrate/sdk';const api = new Api();await api.connect('wss://mof3.sora.org');console.log('Connected to SORA mainnet'); -
Query Data
// Get XOR balanceconst balance = await api.query.assets.freeBalance(XOR_ASSET_ID,accountAddress);console.log('XOR Balance:', balance.toString()); -
Submit Transaction
// Transfer XORconst tx = api.tx.assets.transfer(XOR_ASSET_ID,recipientAddress,amount);await tx.signAndSend(keypair);
Option 2: Web3 Wallet Integration
Section titled “Option 2: Web3 Wallet Integration”Connect to user wallets:
import { web3Accounts, web3Enable } from '@polkadot/extension-dapp';
// Request wallet accessconst extensions = await web3Enable('My SORA App');
if (extensions.length === 0) { throw new Error('No wallet found. Install Fearless or Polkadot.js');}
// Get accountsconst accounts = await web3Accounts();console.log('Available accounts:', accounts);Development Environment
Section titled “Development Environment”Local Setup
Section titled “Local Setup”Connect to SORA testnet for development:
const TESTNET_WS = 'wss://ws.stage.sora2.soramitsu.co.jp';
const api = new Api();await api.connect(TESTNET_WS);Get test tokens:
- Join SORA Discord
- Use #faucet channel
- Request test XOR
Run a local SORA node:
# Clone repositorygit clone https://github.com/sora-xor/sora2-network.gitcd sora2-network
# Buildcargo build --release
# Run development chain./target/release/sora2-node --devConnect to local:
await api.connect('ws://127.0.0.1:9944');Production endpoints:
// Primary endpointconst MAINNET_WS = 'wss://mof3.sora.org';
// Backup endpointsconst BACKUP_WS = [ 'wss://ws.mof.sora.org', 'wss://sora.api.onfinality.io/public-ws',];Common Operations
Section titled “Common Operations”Asset Operations
Section titled “Asset Operations”import { XOR, VAL, PSWAP } from '@sora-substrate/sdk/assets';
// Get asset infoconst xorInfo = await api.query.assets.assetInfos(XOR);console.log('XOR Decimals:', xorInfo.precision.toString());
// Get all balancesconst balances = await api.query.assets.freeBalance.multi([ [XOR, account], [VAL, account], [PSWAP, account],]);
// Register new asset (requires permission)const registerTx = api.tx.assets.register( symbol, name, totalSupply, isMintable, isIndivisible, optionalContent);Trading on Polkaswap
Section titled “Trading on Polkaswap”// Get quote for swapconst quote = await api.rpc.liquidityProxy.quote( dexId, inputAssetId, outputAssetId, amount, 'WithDesiredInput', // or 'WithDesiredOutput' [], // filter sources 'Disabled' // filter mode);
console.log('Expected output:', quote.amount.toString());console.log('Price impact:', quote.priceImpact.toString());
// Execute swapconst swapTx = api.tx.liquidityProxy.swap( dexId, inputAssetId, outputAssetId, swapAmount, minAmountOut, [], // sources 'Disabled');
await swapTx.signAndSend(keypair);Liquidity Operations
Section titled “Liquidity Operations”// Add liquidity to XYK poolconst addLiquidityTx = api.tx.poolXYK.depositLiquidity( dexId, assetA, assetB, amountADesired, amountBDesired, amountAMin, amountBMin);
// Remove liquidityconst removeLiquidityTx = api.tx.poolXYK.withdrawLiquidity( dexId, assetA, assetB, markerAssetId, liquidityAmount, amountAMin, amountBMin);Bridge Integration
Section titled “Bridge Integration”HASHI (Ethereum)
Section titled “HASHI (Ethereum)”// Request outgoing transfer to Ethereumconst bridgeTx = api.tx.ethBridge.transferToSidechain( assetId, ethRecipientAddress, amount, bridgeNetworkId);
// Listen for bridge eventsapi.query.system.events((events) => { events.forEach(({ event }) => { if (event.section === 'ethBridge') { console.log('Bridge event:', event.method, event.data); } });});TONSWAP
Section titled “TONSWAP”// TONSWAP uses its own SDKimport { TonSwapSDK } from '@tonswap/sdk';
const tonswap = new TonSwapSDK();
// Bridge XOR to TONawait tonswap.bridge.toTon({ asset: 'XOR', amount: '100', tonRecipient: 'EQ...',});Best Practices
Section titled “Best Practices”Error Handling
Section titled “Error Handling”try { const result = await tx.signAndSend(keypair, ({ status, events }) => { if (status.isInBlock) { console.log('Transaction in block:', status.asInBlock.toHex());
// Check for errors in events events.forEach(({ event }) => { if (api.events.system.ExtrinsicFailed.is(event)) { const [error] = event.data; if (error.isModule) { const decoded = api.registry.findMetaError(error.asModule); console.error('Error:', decoded.name, decoded.docs); } } }); } });} catch (error) { console.error('Transaction failed:', error.message);}Performance
Section titled “Performance”| Practice | Reason |
|---|---|
| Batch queries | Reduce RPC calls |
| Cache responses | Avoid redundant requests |
| Use subscriptions | Real-time updates |
| Handle reconnects | Network reliability |
// Batch multiple queriesconst [balance1, balance2, balance3] = await Promise.all([ api.query.assets.freeBalance(asset1, account), api.query.assets.freeBalance(asset2, account), api.query.assets.freeBalance(asset3, account),]);
// Subscribe to changesconst unsub = await api.query.assets.freeBalance( XOR, account, (balance) => { console.log('Balance updated:', balance.toString()); });
// Cleanupunsub();Security
Section titled “Security”- ✅ Use wallet extensions for signing
- ✅ Validate all user inputs
- ✅ Handle transaction errors gracefully
- ✅ Test on testnet first
- ❌ Don’t hardcode private keys
- ❌ Don’t trust client-side data
Resources
Section titled “Resources”SDKs and Libraries
Section titled “SDKs and Libraries”| Library | Purpose | Install |
|---|---|---|
| @sora-substrate/sdk | Core SORA SDK | pnpm add @sora-substrate/sdk |
| @polkadot/api | Substrate base | pnpm add @polkadot/api |
| @polkadot/extension-dapp | Wallet integration | pnpm add @polkadot/extension-dapp |
Documentation
Section titled “Documentation”- SORA Wiki — Official documentation
- Polkaswap Guide — DEX documentation
- Substrate Docs — Framework reference
Community
Section titled “Community”Next Steps
Section titled “Next Steps”Iroha Overview
Smart Contracts
Bridges
Polkaswap