Starknet Mini-Pay Skill
Simple P2P payments on Starknet. Like Lightning, but native.
Related modules: skills catalog.
When to Use
- Generating payment links, QR codes, invoices, or Telegram payment flows on Starknet.
- Sending simple user-to-user ETH, STRK, or USDC transfers with payment UX around them.
When NOT to Use
- DeFi-specific swaps, staking, or lending flows.
- Cairo contract authoring, deployment-only tasks, or security auditing.
Overview
┌─────────────────────────────────────────────────────────┐ │ STARKNET MINI-PAY │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ QR Codes │ │ Payment │ │ Telegram Bot │ │ │ │ Generator │ │ Links │ │ Interface │ │ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │ │ │ │ │ │ └────────────────┴───────────────────┘ │ │ │ │ │ ┌─────────▼─────────┐ │ │ │ starknet-py │ │ │ │ SDK + RPC │ │ │ └──────────────────┘ │ │ │ │ │ ┌───────────────┼───────────────┐ │ │ ▼ ▼ ▼ │ │ ┌─────────┐ ┌──────────┐ ┌──────────┐ │ │ │ ArgentX │ │ Braavos │ │ Generic │ │ │ │ Account │ │ Account │ │ Account │ │ │ └─────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────┘
Features
| Feature | Description |
|---|---|
| P2P Transfers | Send ETH/STRK/USDC to any Starknet address |
| QR Codes | Generate QR codes for addresses (scan to pay) |
| Payment Links | starknet:<addr>?amount=1&memo=coffee |
| Invoice System | Generate payment requests with expiry |
| Telegram Bot | Payment links, QR codes and invoices via Telegram (non-custodial) |
| Transaction History | Track all transfers with status |
Quick Start
CLI Usage
bash# Send payment python3.12 scripts/cli.py send 0x123... 0.5 --memo "coffee" # Generate QR code for your address python3.12 scripts/cli.py qr 0x123... --output qr.png # Create payment link python3.12 scripts/cli.py link 0x123... --amount 0.1 --memo "lunch" # Create invoice python3.12 scripts/cli.py invoice 0x123... 25.00 --expires 3600 # Check transaction status python3.12 scripts/cli.py status 0xabcdef... # Balance check python3.12 scripts/cli.py balance 0x123...
Payment Link Format
starknet:<address>?amount=<value>&memo=<text>&token=<ETH|STRK|USDC>
Example:
starknet:0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef?amount=0.01&memo=coffee&token=ETH
Telegram Bot Commands
The bot is non-custodial: it never holds keys or sends transactions. It builds links, QR
codes and invoices that the payer opens and signs in their own wallet. Use the CLI send
and balance commands to transfer or check balances.
/start - Welcome message and quick actions /help - Show help /myaddress <address> - Set your receiving address (needed by /link, /qr, /invoice) /link [amount] [memo] - Payment link and QR with wallet buttons /qr - QR code for your address /invoice <amount> [memo] - USDC invoice with expiry /status <tx_hash> - Check transaction status /webhook <url> - Set a notification webhook (not persisted yet)
Architecture
starknet-mini-pay/ ├── SKILL.md ├── README.md ├── scripts/ │ ├── cli.py # Main CLI interface │ ├── mini_pay.py # Core payment logic │ ├── qr_generator.py # QR code generation │ ├── link_builder.py # Payment link builder │ ├── invoice.py # Invoice system │ ├── telegram_bot.py # Telegram bot │ └── starknet_client.py # Starknet RPC client └── requirements.txt
Dependencies
bashpip install -r requirements.txt
requirements.txt pins starknet-py to the tested 0.30.x range. starknet-py 0.30 speaks
Starknet JSON-RPC spec 0.10, so any custom RPC URL must serve a v0_10 endpoint.
Configuration
bash# Environment variables # Keyless public RPC (spec 0.10). Sepolia: https://api.cartridge.gg/x/starknet/sepolia/rpc/v0_10 export STARKNET_RPC="https://api.cartridge.gg/x/starknet/mainnet/rpc/v0_10" export MINI_PAY_PRIVATE_KEY="0x..." export MINI_PAY_ADDRESS="0x..." export TELEGRAM_BOT_TOKEN="..." export TELEGRAM_CHAT_ID="..."
Core Functions
Send Payment
pythonfrom mini_pay import MiniPay, MAINNET_RPC_URL pay = MiniPay(rpc_url=MAINNET_RPC_URL) # Send ETH (V3 transaction: the fee is paid in STRK) tx_hash = await pay.transfer( from_address="0x...", private_key="0x...", to_address="0x123...", amount_wei=5 * 10**17, # 0.5 ETH token="ETH" ) # Check status status = await pay.get_transaction_status(tx_hash) print(f"Status: {status}") # PENDING, CONFIRMED, REJECTED, NOT_FOUND
Generate QR Code
pythonfrom qr_generator import QRGenerator qr = QRGenerator() qr.generate( address="0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", amount=None, # Optional amount memo=None, # Optional memo output_file="address_qr.png" )
Payment Links
pythonfrom link_builder import PaymentLinkBuilder link = PaymentLinkBuilder() # Create link url = link.create( address="0x123...", amount=0.01, memo="coffee", token="ETH" ) # Parse incoming link data = link.parse("starknet:0x123...?amount=0.01&memo=coffee")
Invoice System
pythonimport asyncio from invoice import InvoiceManager async def main(): # Opens (or creates) invoices.db in the working directory async with InvoiceManager() as invoices: # Create invoice invoice = await invoices.create( payer_address="0x...", # also the recipient unless recipient_address is set amount=25.00, token="USDC", expiry_seconds=3600, # 1 hour description="Payment for services" ) print(invoices.create_payment_url(invoice)) # Check invoice status fetched = await invoices.get(invoice.id) print(fetched.status, invoices.format_expiry(fetched)) # pending 1h left asyncio.run(main())
Telegram Bot
Run Bot
bashpython3.12 scripts/telegram_bot.py
Bot Flow
User: /myaddress 0x0123...cdef Bot: ✅ Address Set User: /link 0.05 coffee Bot: 📱 Payment Link (QR code) with "Open in ArgentX" / "Open in Braavos" buttons Payer: opens the link and signs the transfer in their own wallet
Optional: Invoice Contract
This skill does not ship a contract. A trustless invoice contract could follow this sketch:
cairo#[starknet::contract] mod PaymentRequest { #[storage] struct Storage { request_id: u256, requests: Map<u256, Request>, owner: ContractAddress, } #[derive(Drop, Serde)] struct Request { amount: u256, token: ContractAddress, recipient: ContractAddress, expiry: u64, fulfilled: bool, memo: felt252, } #[external(v0)] impl IPaymentRequestImpl of IPaymentRequest<ContractState> { fn create_request( ref self: ContractState, amount: u256, token: ContractAddress, expiry: u64, memo: felt252 ) -> u256 { // Create payment request } fn fulfill_request( ref self: ContractState, request_id: u256 ) { // Execute payment } } }
Error Handling
| Error | Cause | Solution |
|---|---|---|
INSUFFICIENT_BALANCE | Not enough of the token, or not enough STRK for fees | Top up the token and keep STRK for V3 fees |
ACCOUNT_NOT_FOUND | Invalid sender address | Check address format |
INVALID_AMOUNT | Amount <= 0 | Use positive amount |
TX_FAILED | Transaction reverted | Check recipient address |
INVOICE_EXPIRED | Invoice past expiry | Create new invoice |
Payment Flow
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Sender │ │ Mini-Pay │ │ Recipient │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ 1. Initiate │ │ │──────────────────▶│ │ │ │ │ │ │ 2. Execute │ │ │ ETH Transfer │ │ │─────────────────▶ │ │ │ │ │ 3. Confirm │ │ │◀────────────────── │ 4. Success │ │ │◀──────────────────│ │ │ │ │
Security Notes
- Private keys: Never expose in logs or error messages
- Amount validation: Prevent negative/zero amounts
- Expiry checks: Invoices expire automatically
- Address format: Validate Starknet addresses (0x... format)
Comparison with Lightning
| Feature | Lightning | Starknet Mini-Pay |
|---|---|---|
| Setup time | Hours (channels) | Instant |
| Privacy | Onion routing | Native (per txn) |
| Speed | ~1 sec | ~2-3 min |
| Fees | Variable | Predictable |
| Custody | Lightning node | Self-custody |
| Native | No (needs BTC) | Yes (Starknet native) |
Roadmap
- Multi-token support (STRK, USDC, DAI)
- Batch payments
- Payment requests via IPFS
- Web interface
- Mobile app (Flutter)
- MPC wallet integration


