Skill: endogen/xian-sdk-skill (version 0.1.0)

--- name: xian-sdk description: Build applications on the Xian blockchain using the xian-py Python SDK. Use when developing apps that interact with Xian — wallets, transactions, smart contracts, state queries, token transfers. Covers sync and async patterns. --- # Xian SDK Skill Build applications on [Xian](https://xian.org) using the [xian-py](https://github.com/xian-network/xian-py) Python SDK. ## Installation ```bash pip install xian-py # With Ethereum wallet support pip install "xian-py[eth]" ``` ## Quick Reference ```python from xian_py import Xian, Wallet wallet = Wallet() # New wallet xian = Xian('http://node:26657', wallet=wallet) # Common operations balance = xian.get_balance(wallet.public_key) state = xian.get_state('contract', 'variable', 'key') result = xian.send(amount=100, to_address='recipient') result = xian.send_tx('contract', 'function', {'arg': 'value'}) result = xian.submit_contract('name', code) ``` ## Wallets ### Basic Wallet ```python from xian_py import Wallet # Create new wallet (random seed) wallet = Wallet() # From existing private key wallet = Wallet([REDACTED_SECRET]) print(wallet.public_key) # Address print(wallet.private_key) # Keep secret! ``` ### HD Wallet (BIP39/BIP32) ```python from xian_py.wallet import HDWallet # Create with new 24-word mnemonic hd = HDWallet() print(hd.mnemonic_str) # Save this! # Restore from mnemonic hd = HDWallet('word1 word2 word3 ... word24') # Derive Xian wallet path = [44, 0, 0, 0, 0] # m/44'/0'/0'/0'/0' wallet = hd.get_wallet(path) # Derive Ethereum wallet (requires eth extras) eth_wallet = hd.get_ethereum_wallet(0) # First account eth_wallet2 = hd.get_ethereum_wallet(1) # Second account ``` ### Signing & Verification ```python wallet = Wallet() # Sign message signature = wallet.sign_msg("Hello Xian") # Verify is_valid = wallet.verify_msg("Hello Xian", signature) # Validate key format Wallet.is_valid_key(wallet.public_key) # True ``` ## Blockchain Queries ```python from xian_py import Xian xian = Xian('http://node:26657') # Balance (default: currency contract) balance = xian.get_balance('address') # Custom token balance balance = xian.get_balance('address', contract='token_contract') # Contract state state = xian.get_state('contract_name', 'variable', 'key') # Get contract source source = xian.get_contract('contract_name', clean=True) ``` ## Transactions ### Simple Token Transfer ```python from xian_py import Xian, Wallet wallet = Wallet('your_private_key') xian = Xian('http://node:26657', wallet=wallet) # Send tokens (auto stamp calculation) result = xian.send(amount=100, to_address='recipient') if result['success']: print(f"TX: {result['tx_hash']}") ``` ### Contract Interaction ```python # Call any contract function result = xian.send_tx( contract='currency', function='transfer', kwargs={'to': 'recipient', 'amount': 1000} ) # With custom token result = xian.send_tx( contract='my_token', function='transfer', kwargs={'to': 'recipient', 'amount': 500} ) ``` ### Stamp Estimation ```python from xian_py.transaction import simulate_tx, get_nonce # Simulate to get stamp cost payload = { "contract": "currency", "function": "transfer", "kwargs": {"to": "recipient", "amount": 100}, "sender": wallet.public_key, } result = simulate_tx('http://node:26657', payload) print(f"Stamps needed: {result['stamps_used']}") ``` ## Smart Contracts ### Deploy Contract ```python code = ''' balances = Hash(default_value=0) @construct def seed(): balances[ctx.caller] = 1_000_000 @export def transfer(to: str, amount: float): assert amount > 0, "Amount must be positive" assert balances[ctx.caller] >= amount, "Insufficient balance" balances[ctx.caller] -= amount balances[to] += amount @export def balance_of(address: str) -> float: return balances[address] ''' result = xian.submit_contract('my_token', code) print(f"Deployed: {result['success']}") ``` ### Contract Patterns See `references/contract-patterns.md` for common patterns (tokens, access control, pausable, upgrades). ### Contract Validation Validate against [Xian standards](https://github.com/xian-network/xian-standard-contracts): ```python from xian_py.validator import validate_contract, XianStandard is_valid, errors = validate_contract(code) # XSC001 default # Specific standard is_valid, errors = validate_contract(code, standard=XianStandard.XSC001) if not is_valid: print(errors) ``` ### Read-Only Execution Query contract without spending stamps: ```python from xian_py.transaction import simulate_tx payload = { "contract": "my_token", "function": "balance_of", "kwargs": {"address": "some_address"}, "sender": wallet.public_key, } result = simulate_tx('http://node:26657', payload) print(f"Balance: {result['result']}") ``` ## Async Operations For high-performance applications: ```python import asyncio from xian_py import XianAsync, Wallet async def main(): wallet = Wallet() async with XianAsync('http://node:26657', wallet=wallet) as xian: # Concurrent queries balance, state = await asyncio.gather( xian.get_balance(wallet.public_key), xian.get_state('currency', 'balances', 'address') ) # Send transaction result = await xian.send(amount=100, to_address='recipient') asyncio.run(main()) ``` ### Batch Operations ```python async def check_balances(addresses: list[str]): async with XianAsync('http://node:26657') as xian: balances = await asyncio.gather(*[ xian.get_balance(addr) for addr in addresses ]) return dict(zip(addresses, balances)) ``` ### Sync Wrapper Call async from sync code: ```python from xian_py import XianAsync, run_sync def get_balance_sync(address: str) -> float: async def _get(): async with XianAsync('http://node:26657') as xian: return await xian.get_balance(address) return run_sync(_get()) balance = get_balance_sync('address') ``` ## Encryption Two-way encrypted messaging: ```python from xian_py import Wallet from xian_py.crypto import encrypt, decrypt_as_sender, decrypt_as_receiver sender = Wallet() receiver = Wallet() # Encrypt encrypted = encrypt(sender.private_key, receiver.public_key, "Secret message") # Decrypt as sender msg = decrypt_as_sender(sender.private_key, receiver.public_key, encrypted) # Decrypt as receiver msg = decrypt_as_receiver(sender.public_key, receiver.private_key, encrypted) ``` ## Error Handling ```python from xian_py import Xian, XianException try: result = xian.send_tx('contract', 'function', {}) except XianException as e: print(f"Blockchain error: {e}") ``` ## Common Patterns ### Token Transfer Service ```python class TokenService: def __init__(self, node_url: str, private_key: str): self.wallet = Wallet(private_key) self.xian = Xian(node_url, wallet=self.wallet) def transfer(self, to: str, amount: float, token: str = 'currency'): balance = self.xian.get_balance(self.wallet.public_key, contract=token) if balance < amount: raise ValueError(f"Insufficient: {balance} < {amount}") return self.xian.send_tx(token, 'transfer', {'to': to, 'amount': amount}) ``` ### DEX Swap ```python async def swap(xian, dex: str, token_in: str, token_out: str, amount: float, min_out: float): # Approve DEX await xian.send_tx(token_in, 'approve', {'to': dex, 'amount': amount}) # Execute swap return await xian.send_tx(dex, 'swap', { 'token_in': token_in, 'token_out': token_out, 'amount_in': amount, 'min_amount_out': min_out }) ``` ## Resources - [xian-py GitHub](https://github.com/xian-network/xian-py) — Full SDK docs - [Xian Standard Contracts](https://github.com/xian-network/xian-standard-contracts) — Token standards - [xian.org](https://xian.org) — Project site

path: references/contract-patterns.md
content: # Xian Contract Patterns

Common patterns for Xian smart contracts written in Python.

## Table of Contents

- [Basic Token (XSC001)](#basic-token-xsc001)
- [Access Control](#access-control)
- [Pausable Contract](#pausable-contract)
- [Upgradeable Pattern](#upgradeable-pattern)

## Basic Token (XSC001)

Minimal fungible token following XSC001 standard:

```python
balances = Hash(default_value=0)
metadata = Hash()

@construct
def seed():
    metadata['token_name'] = 'My Token'
    metadata['token_symbol'] = 'MTK'
    metadata['token_logo_url'] = 'https://example.com/logo.png'
    metadata['token_website'] = 'https://example.com'
    metadata['operator'] = ctx.caller
    
    # Initial supply to deployer
    balances[ctx.caller] = 1_000_000

@export
def transfer(amount: float, to: str):
    assert amount > 0, 'Amount must be positive'
    assert balances[ctx.caller] >= amount, 'Insufficient balance'
    
    balances[ctx.caller] -= amount
    balances[to] += amount

@export
def approve(amount: float, to: str):
    balances[ctx.caller, to] = amount

@export
def transfer_from(amount: float, to: str, main_account: str):
    assert amount > 0, 'Amount must be positive'
    assert balances[main_account, ctx.caller] >= amount, 'Not approved'
    assert balances[main_account] >= amount, 'Insufficient balance'
    
    balances[main_account, ctx.caller] -= amount
    balances[main_account] -= amount
    balances[to] += amount

@export
def balance_of(address: str) -> float:
    return balances[address]
```

## Access Control

Owner-only functions:

```python
owner = Variable()

@construct
def seed():
    owner.set(ctx.caller)

def only_owner():
    assert ctx.caller == owner.get(), 'Only owner'

@export
def admin_function():
    only_owner()
    # ... privileged logic

@export
def transfer_ownership(new_owner: str):
    only_owner()
    owner.set(new_owner)
```

Multi-role access:

```python
roles = Hash(default_value=False)

@construct
def seed():
    roles['admin', ctx.caller] = True

@export
def grant_role(role: str, account: str):
    assert roles['admin', ctx.caller], 'Only admin'
    roles[role, account] = True

@export
def revoke_role(role: str, account: str):
    assert roles['admin', ctx.caller], 'Only admin'
    roles[role, account] = False

@export
def minter_function():
    assert roles['minter', ctx.caller], 'Only minter'
    # ... minting logic
```

## Pausable Contract

Emergency stop pattern:

```python
paused = Variable()
owner = Variable()

@construct
def seed():
    owner.set(ctx.caller)
    paused.set(False)

def when_not_paused():
    assert not paused.get(), 'Contract is paused'

def only_owner():
    assert ctx.caller == owner.get(), 'Only owner'

@export
def pause():
    only_owner()
    paused.set(True)

@export
def unpause():
    only_owner()
    paused.set(False)

@export
def transfer(to: str, amount: float):
    when_not_paused()
    # ... transfer logic
```

## Upgradeable Pattern

Proxy pattern for upgrades:

```python
# Proxy contract
implementation = Variable()
owner = Variable()

@construct
def seed(impl_contract: str):
    implementation.set(impl_contract)
    owner.set(ctx.caller)

@export
def upgrade(new_impl: str):
    assert ctx.caller == owner.get(), 'Only owner'
    implementation.set(new_impl)

@export
def execute(function: str, kwargs: dict):
    impl = importlib.import_module(implementation.get())
    fn = getattr(impl, function)
    return fn(**kwargs)
```

## State Patterns

### Mapping with Default

```python
balances = Hash(default_value=0)

# No need to initialize - returns 0 for unknown keys
balance = balances['new_address']  # Returns 0
```

### Nested Mapping

```python
# Allowances: owner -> spender -> amount
allowances = Hash(default_value=0)

allowances[owner, spender] = 100
allowed = allowances[owner, spender]
```

### List-like Storage

```python
items = Hash()
item_count = Variable()

@construct
def seed():
    item_count.set(0)

@export
def add_item(data: str):
    idx = item_count.get()
    items[idx] = data
    item_count.set(idx + 1)

@export
def get_item(idx: int) -> str:
    assert idx < item_count.get(), 'Index out of bounds'
    return items[idx]
```

## Event Logging

Emit events for off-chain indexing:

```python
@export
def transfer(to: str, amount: float):
    # ... transfer logic
    
    # Log event (captured by BDS)
    return {
        'event': 'Transfer',
        'from': ctx.caller,
        'to': to,
        'amount': amount
    }
```

## Time-based Logic

```python
import datetime

lock_until = Hash()

@export
def lock_tokens(amount: float, days: int):
    unlock_time = datetime.datetime.now() + datetime.timedelta(days=days)
    lock_until[ctx.caller] = unlock_time
    # ... lock logic

@export
def unlock():
    assert datetime.datetime.now() >= lock_until[ctx.caller], 'Still locked'
    # ... unlock logic
```


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)