SPB Git

spb/os-vault Public

Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.

Swift 96% Shell 3.4% Makefile 0.6%

OS Vault 1.0.0 — self-custody multi-chain wallet for macOS

One BIP-39 phrase drives six chain families: 11 EVM chains, Bitcoin
(BIP-84 via bdk-swift), Solana (SPL), Tron (TRC-20 via vendored Trust
wallet-core), XRP Ledger (RLUSD trustlines) and TON (jettons). Keys are
sealed in OS Vault's own PBKDF2→AES-GCM vault (no Keychain); every send
re-derives and discards the key. All endpoints keyless with failover;
32 unit tests incl. BIP-39/BIP-84 vectors and cross-stack derivation
checks; signed, notarized, stapled release pipeline with DMG.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed 4 days ago (Aug 6, 2026)

Showing 142 changed files with +20,001 and −0

added .gitignore +14 −0
@@ -0,0 +1,14 @@
1 +# Build products
2 +.build/
3 +dist/
4 +*.xcodeproj
5 +
6 +# Vendored binary too large for git (270 MB) — regenerate with
7 +# scripts/vendor-walletcore.sh
8 +vendor/WalletCoreSPM/WalletCoreCommon.xcframework/
9 +
10 +# macOS
11 +.DS_Store
12 +
13 +# Local state
14 +*.sqlite
added CLAUDE.md +157 −0
@@ -0,0 +1,157 @@
1 +# CLAUDE.md — Zyquo Wallet
2 +
3 +## Project Overview
4 +
5 +**Zyquo Wallet** is a native **macOS** self-custody stablecoin wallet built in **Swift + SwiftUI**. It manages **real on-chain USDC** on **Base** (Ethereum L2 by Coinbase — chosen for sub-cent gas fees and native Circle-issued USDC).
6 +
7 +This is NOT a mock/demo app. Every feature must work against a real blockchain:
8 +1. Real HD wallet creation (BIP-39 mnemonic → secp256k1 keys)
9 +2. Receive USDC (real address + QR code)
10 +3. Send USDC (real signed ERC-20 transfers broadcast via JSON-RPC)
11 +
12 +**Development rule: build and test everything on Base Sepolia testnet first. Mainnet support is enabled last, behind an explicit network switch.**
13 +
14 +---
15 +
16 +## Tech Stack
17 +
18 +| Layer | Choice |
19 +|---|---|
20 +| Language | Swift 5.10+ (strict concurrency where possible) |
21 +| UI | SwiftUI, macOS 14+ target |
22 +| Project | Xcode project, dependencies via Swift Package Manager only |
23 +| Web3 | `web3swift` (https://github.com/web3swift-team/web3swift) — actively maintained, macOS support, BIP-39/BIP-32, ERC-20, EIP-1559 |
24 +| QR codes | CoreImage (`CIQRCodeGenerator`) — no extra dependency |
25 +| Key storage | macOS Keychain (Security framework) |
26 +| Persistence | UserDefaults for settings; no database needed for v1 (history read from chain/explorer API) |
27 +
28 +If `web3swift` causes build issues on macOS, fallback is `argentlabs/web3.swift`. Never mix both.
29 +
30 +---
31 +
32 +## Network Configuration (source of truth)
33 +
34 +```swift
35 +enum Network {
36 + case baseSepolia // DEFAULT during development
37 + case baseMainnet
38 +}
39 +```
40 +
41 +| | Base Sepolia (testnet) | Base Mainnet |
42 +|---|---|---|
43 +| Chain ID | 84532 | 8453 |
44 +| RPC (dev) | https://sepolia.base.org | https://mainnet.base.org |
45 +| USDC contract | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
46 +| Explorer | https://sepolia.basescan.org | https://basescan.org |
47 +| Faucets | Circle faucet (https://faucet.circle.com — 20 USDC / 2h) + Base Sepolia ETH faucet for gas | — |
48 +
49 +- **USDC has 6 decimals.** Always convert with `BigUInt` / decimal math — never `Double`. 1 USDC = 1_000_000 base units.
50 +- Public RPCs are fine for dev. For production, make the RPC URL configurable (Alchemy/QuickNode) via Settings — but never require an API key to run the app.
51 +- Gas is paid in **ETH**, not USDC. The UI must clearly warn when the ETH balance is too low to send.
52 +
53 +---
54 +
55 +## Architecture
56 +
57 +MVVM + service layer. Keep views dumb; all blockchain logic lives in services.
58 +
59 +```
60 +ZyquoWallet/
61 +├── App/ ZyquoWalletApp.swift, AppState (ObservableObject / @Observable)
62 +├── Models/ Wallet, Transaction, Network, TokenAmount
63 +├── Services/
64 +│ ├── KeyManager.swift // mnemonic gen/import, keystore, Keychain I/O
65 +│ ├── WalletService.swift // address derivation, wallet lifecycle
66 +│ ├── RPCService.swift // web3 provider, network switching
67 +│ ├── BalanceService.swift // ETH + USDC balances, polling every 15s
68 +│ └── TransactionService.swift// build, estimate gas, sign, send, track receipt
69 +├── ViewModels/ OnboardingVM, HomeVM, SendVM, ReceiveVM, SettingsVM
70 +├── Views/
71 +│ ├── Onboarding/ Welcome, CreateWallet (show + verify mnemonic), ImportWallet
72 +│ ├── Home/ Balance card, tx list, Send/Receive buttons
73 +│ ├── Send/ recipient + amount + gas preview + confirm sheet
74 +│ ├── Receive/ address display, QR, copy button
75 +│ └── Settings/ network switch, RPC override, export seed (auth-gated), reset
76 +└── Utils/ formatting, address validation (EIP-55), errors
77 +```
78 +
79 +- Use `async/await` everywhere; wrap web3swift callbacks if needed.
80 +- One `AppState` injected via `.environment`; services are protocol-backed for testability.
81 +- Every service method that touches the network returns typed errors (`WalletError` enum), never `fatalError`.
82 +
83 +---
84 +
85 +## Security Requirements (non-negotiable)
86 +
87 +1. **Mnemonic & private key never leave the device.** No analytics, no telemetry, no network calls except JSON-RPC and explorer API.
88 +2. Store the mnemonic (or derived keystore) in **Keychain** with `kSecAttrAccessibleWhenUnlockedThisDeviceOnly`. Never in UserDefaults, files, or iCloud.
89 +3. Gate seed export and every send behind **LocalAuthentication** (Touch ID / password).
90 +4. **Never log** mnemonics, private keys, or signatures. Never put them in error messages.
91 +5. Never hardcode keys, mnemonics, or API keys anywhere in the repo — including tests. Test wallets are generated at runtime.
92 +6. Onboarding must force a **mnemonic backup verification** step (user re-enters 3 random words) before showing the wallet.
93 +7. Validate recipient addresses: hex format + EIP-55 checksum. Warn (don't block) on all-lowercase addresses.
94 +8. Enable **App Sandbox** (with network client entitlement) and **Hardened Runtime**.
95 +9. Confirm screen before send must show: recipient, amount, network, estimated gas, and total — no one-tap sends.
96 +10. If the clipboard is used for addresses, never auto-paste into the recipient field without user action (clipboard-hijack protection).
97 +
98 +---
99 +
100 +## Feature Phases (implement in order, each must compile + pass tests)
101 +
102 +### Phase 1 — Wallet core
103 +- Generate 12-word BIP-39 mnemonic, derive account at `m/44'/60'/0'/0/0`
104 +- Import from mnemonic
105 +- Persist via KeyManager/Keychain; app relaunch restores wallet
106 +- Onboarding flow with backup verification
107 +
108 +### Phase 2 — Receive
109 +- Show checksummed address, copy button, QR code (address only, no `ethereum:` URI needed for v1)
110 +
111 +### Phase 3 — Balances
112 +- ETH balance (`eth_getBalance`) + USDC balance (`balanceOf(address)`)
113 +- Poll every 15s while app is active; manual refresh; loading/error states
114 +
115 +### Phase 4 — Send USDC
116 +- ERC-20 `transfer(to, amount)` with EIP-1559 fees
117 +- Gas estimation shown in ETH + rough USD
118 +- Sign locally, broadcast, then poll `eth_getTransactionReceipt` until confirmed
119 +- Pending/confirmed/failed states surfaced in UI, link to BaseScan
120 +
121 +### Phase 5 — History & polish
122 +- Transaction list from BaseScan API (USDC transfers in/out) with graceful fallback if API unavailable
123 +- Network switcher (Sepolia ⇄ Mainnet) with a prominent "TESTNET" badge on Sepolia
124 +- Settings: custom RPC, export seed (auth-gated), delete wallet (typed confirmation)
125 +
126 +---
127 +
128 +## Build & Test Commands
129 +
130 +```bash
131 +# Build
132 +xcodebuild -scheme ZyquoWallet -destination 'platform=macOS' build
133 +
134 +# Tests
135 +xcodebuild -scheme ZyquoWallet -destination 'platform=macOS' test
136 +```
137 +
138 +- Unit-test: mnemonic → address derivation (against known BIP-39 test vectors), USDC decimal conversion, address validation, amount formatting.
139 +- Never write tests that send real mainnet funds. Network-dependent tests run against Base Sepolia and must be skippable offline.
140 +
141 +## Manual test checklist (Base Sepolia)
142 +1. Create wallet → relaunch app → same address restored
143 +2. Fund via Circle faucet (USDC) + Base faucet (ETH for gas)
144 +3. Balance appears within one polling cycle
145 +4. Send 1 USDC to a second test wallet → confirm on sepolia.basescan.org
146 +5. Import that second wallet from mnemonic → balance matches
147 +
148 +---
149 +
150 +## Conventions & Pitfalls
151 +
152 +- All amounts are `BigUInt` in base units internally; convert to display strings only at the UI edge.
153 +- USDC = 6 decimals, ETH = 18 decimals. Mixing these up is the #1 bug source.
154 +- Chain ID must match the selected network in every signed transaction (replay protection).
155 +- Handle RPC failures with retry + user-visible error; the app must never crash on network errors.
156 +- Comments and UI strings in English; French localization can come later via String Catalog.
157 +- Small, focused commits per phase. Do not start a later phase before the earlier one builds and passes tests.
added Makefile +60 −0
@@ -0,0 +1,60 @@
1 +#
2 +# Makefile
3 +# OS Vault
4 +#
5 +# Author: Simon-Pierre Boucher
6 +# Mail: contact@spboucher.ai
7 +#
8 +
9 +APP_NAME := OS Vault
10 +EXEC_NAME := OSVault
11 +BUNDLE_ID := com.zyquo.osvault
12 +VERSION := 1.0.0
13 +BUILD_DIR := .build
14 +DIST_DIR := dist
15 +APP_BUNDLE := $(DIST_DIR)/$(APP_NAME).app
16 +SIGN_IDENTITY := Developer ID Application: Simon-Pierre Boucher (3YM54G49SN)
17 +NOTARY_PROFILE := MacLustr-Notarize
18 +
19 +.PHONY: build release-build test clean dev bundle-debug bundle-release run release
20 +
21 +build:
22 + swift build
23 +
24 +release-build:
25 + swift build -c release
26 +
27 +test:
28 + swift test
29 +
30 +clean:
31 + swift package clean
32 + rm -rf $(DIST_DIR)
33 +
34 +# ── App bundle assembly ──────────────────────────────────────────────────────
35 +# $(1) = built products dir (.build/debug or .build/release)
36 +define assemble_bundle
37 + rm -rf "$(APP_BUNDLE)"
38 + mkdir -p "$(APP_BUNDLE)/Contents/MacOS" "$(APP_BUNDLE)/Contents/Resources"
39 + cp "$(1)/$(EXEC_NAME)" "$(APP_BUNDLE)/Contents/MacOS/$(EXEC_NAME)"
40 + cp Support/Info.plist "$(APP_BUNDLE)/Contents/Info.plist"
41 + printf 'APPL????' > "$(APP_BUNDLE)/Contents/PkgInfo"
42 + [ -f assets/icon/AppIcon.icns ] && cp assets/icon/AppIcon.icns "$(APP_BUNDLE)/Contents/Resources/AppIcon.icns" || true
43 +endef
44 +
45 +bundle-debug: build
46 + $(call assemble_bundle,$(BUILD_DIR)/debug)
47 + codesign --force --deep --entitlements Support/entitlements.plist --sign - "$(APP_BUNDLE)"
48 +
49 +bundle-release: release-build
50 + $(call assemble_bundle,$(BUILD_DIR)/release)
51 +
52 +# Debug bundle, ad-hoc signed, launched.
53 +dev: bundle-debug
54 + open "$(APP_BUNDLE)"
55 +
56 +run: dev
57 +
58 +# Signed, notarized, stapled release: scripts/release.sh
59 +release:
60 + scripts/release.sh
added Package.resolved +78 −0
@@ -0,0 +1,78 @@
1 +{
2 + "originHash" : "a8d3a77901f33178ea03447308323e177a207103fb42a71c5911e627b913f154",
3 + "pins" : [
4 + {
5 + "identity" : "bdk-swift",
6 + "kind" : "remoteSourceControl",
7 + "location" : "https://github.com/bitcoindevkit/bdk-swift",
8 + "state" : {
9 + "revision" : "5bc9c3cddf203f6aa147d77364782bf095e4f84e",
10 + "version" : "3.0.0"
11 + }
12 + },
13 + {
14 + "identity" : "bigint",
15 + "kind" : "remoteSourceControl",
16 + "location" : "https://github.com/attaswift/BigInt.git",
17 + "state" : {
18 + "revision" : "793a7fac0bfc318e85994bf6900652e827aef33e",
19 + "version" : "5.4.1"
20 + }
21 + },
22 + {
23 + "identity" : "cryptoswift",
24 + "kind" : "remoteSourceControl",
25 + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
26 + "state" : {
27 + "revision" : "039f56c5d7960f277087a0be51f5eb04ed0ec073",
28 + "version" : "1.5.1"
29 + }
30 + },
31 + {
32 + "identity" : "secp256k1.swift",
33 + "kind" : "remoteSourceControl",
34 + "location" : "https://github.com/GigaBitcoin/secp256k1.swift",
35 + "state" : {
36 + "revision" : "48fb20fce4ca3aad89180448a127d5bc16f0e44c",
37 + "version" : "0.10.0"
38 + }
39 + },
40 + {
41 + "identity" : "swift-protobuf",
42 + "kind" : "remoteSourceControl",
43 + "location" : "https://github.com/apple/swift-protobuf.git",
44 + "state" : {
45 + "revision" : "55d7a1cc5666b85c13464aea1c4b4a90feccb4c8",
46 + "version" : "1.38.1"
47 + }
48 + },
49 + {
50 + "identity" : "task-retrying-swift",
51 + "kind" : "remoteSourceControl",
52 + "location" : "https://github.com/bigearsenal/task-retrying-swift.git",
53 + "state" : {
54 + "revision" : "208f1e8dfa93022a7d39ab5b334d5f43a934d4b1",
55 + "version" : "2.0.0"
56 + }
57 + },
58 + {
59 + "identity" : "tweetnacl-swiftwrap",
60 + "kind" : "remoteSourceControl",
61 + "location" : "https://github.com/bitmark-inc/tweetnacl-swiftwrap.git",
62 + "state" : {
63 + "revision" : "f8fd111642bf2336b11ef9ea828510693106e954",
64 + "version" : "1.1.0"
65 + }
66 + },
67 + {
68 + "identity" : "web3swift",
69 + "kind" : "remoteSourceControl",
70 + "location" : "https://github.com/web3swift-team/web3swift.git",
71 + "state" : {
72 + "revision" : "b9c771bf3b94983d2f9b22096b4a267a72c16006",
73 + "version" : "3.3.2"
74 + }
75 + }
76 + ],
77 + "version" : 3
78 +}
added Package.swift +47 −0
@@ -0,0 +1,47 @@
1 +// swift-tools-version:5.10
2 +//
3 +// Package.swift
4 +// OS Vault
5 +//
6 +// Author: Simon-Pierre Boucher
7 +// Mail: contact@spboucher.ai
8 +//
9 +
10 +import PackageDescription
11 +
12 +let package = Package(
13 + name: "OSVault",
14 + platforms: [
15 + .macOS(.v14)
16 + ],
17 + dependencies: [
18 + .package(url: "https://github.com/web3swift-team/web3swift.git", from: "3.3.2"),
19 + .package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"),
20 + .package(url: "https://github.com/bitcoindevkit/bdk-swift", exact: "3.0.0"),
21 + .package(path: "vendor/solana-swift"),
22 + .package(path: "vendor/WalletCoreSPM")
23 + ],
24 + targets: [
25 + .target(
26 + name: "OSVaultKit",
27 + dependencies: [
28 + .product(name: "web3swift", package: "web3swift"),
29 + .product(name: "BigInt", package: "BigInt"),
30 + .product(name: "BitcoinDevKit", package: "bdk-swift"),
31 + .product(name: "SolanaSwift", package: "solana-swift"),
32 + .product(name: "WalletCore", package: "WalletCoreSPM")
33 + ],
34 + path: "Sources/OSVaultKit"
35 + ),
36 + .executableTarget(
37 + name: "OSVault",
38 + dependencies: ["OSVaultKit"],
39 + path: "Sources/OSVault"
40 + ),
41 + .testTarget(
42 + name: "OSVaultTests",
43 + dependencies: ["OSVaultKit"],
44 + path: "Tests/OSVaultTests"
45 + )
46 + ]
47 +)
added README.md +154 −0
@@ -0,0 +1,154 @@
1 +<div align="center">
2 +
3 +<img src="assets/icon/os-vault.svg" width="128" alt="OS Vault icon"/>
4 +
5 +# OS Vault
6 +
7 +**Self-custody, multi-chain crypto wallet for macOS.**
8 +One recovery phrase. Six chain families. Zero API keys. Nothing ever leaves your Mac.
9 +
10 +[![Platform](https://img.shields.io/badge/platform-macOS%2015.5%2B-111?logo=apple&logoColor=white)](#requirements)
11 +[![Swift](https://img.shields.io/badge/Swift-6-F05138?logo=swift&logoColor=white)](#build)
12 +[![SwiftUI](https://img.shields.io/badge/UI-SwiftUI-0A84FF)](#architecture)
13 +[![Tests](https://img.shields.io/badge/tests-32%20passing-2EA043?logo=github)](#tests)
14 +[![Release](https://img.shields.io/badge/release-v1.0.0-blueviolet)](../../releases)
15 +[![Notarized](https://img.shields.io/badge/Apple-notarized%20%2B%20stapled-000?logo=apple&logoColor=white)](#release-pipeline)
16 +[![Keyless](https://img.shields.io/badge/API%20keys-zero-2EA043)](#infrastructure--no-api-keys)
17 +[![Self--custody](https://img.shields.io/badge/custody-yours%20only-orange)](#security-model)
18 +
19 +[![Bitcoin](https://img.shields.io/badge/Bitcoin-BIP--84-F7931A?logo=bitcoin&logoColor=white)](#chains)
20 +[![Ethereum](https://img.shields.io/badge/EVM-11%20chains-3C3C3D?logo=ethereum&logoColor=white)](#chains)
21 +[![Solana](https://img.shields.io/badge/Solana-SPL-9945FF?logo=solana&logoColor=white)](#chains)
22 +[![Tron](https://img.shields.io/badge/Tron-TRC--20-EB0029)](#chains)
23 +[![XRPL](https://img.shields.io/badge/XRPL-RLUSD-25A768?logo=xrp&logoColor=white)](#chains)
24 +[![TON](https://img.shields.io/badge/TON-jettons-0098EA?logo=ton&logoColor=white)](#chains)
25 +
26 +</div>
27 +
28 +---
29 +
30 +## Why OS Vault
31 +
32 +Most wallets make you choose: convenience (custodial, tracked, keyed APIs) or
33 +sovereignty (CLI tools, manual everything). OS Vault refuses the trade:
34 +
35 +- 🔐 **Your keys, your Mac, your encryption.** The BIP-39 mnemonic is sealed
36 + with OS Vault's **own vault format** — PBKDF2-HMAC-SHA512 (600k rounds) →
37 + AES-256-GCM — in a local file. No macOS Keychain, no iCloud, no telemetry.
38 +- 🌐 **One phrase, every chain.** The same 12 words derive Bitcoin (BIP-84),
39 + 11 EVM chains, Solana, Tron, XRPL and TON — cross-validated against
40 + independent crypto stacks in the test suite.
41 +- 🗝️ **Zero mandatory API keys.** Every endpoint is public and keyless, with
42 + automatic failover. The only egress is blockchain RPC (+ optional CoinGecko
43 + prices, one toggle to kill).
44 +- ✍️ **Sign-and-forget.** The private key exists only for the milliseconds a
45 + transaction is being signed — every send re-derives it from your password
46 + and discards it.
47 +
48 +## Chains
49 +
50 +| Family | Assets | Fees handled | Testnet default |
51 +|---|---|---|---|
52 +| **EVM × 11** — Ethereum, Base, Arbitrum, OP, Polygon, BNB, Avalanche, Gnosis, Linea, Scroll (+ Base Sepolia) | USDC, USDC.e, USDT, DAI, USDS, EURC + native coin | EIP-1559, BSC zero-base-fee, **OP-stack/Scroll L1 data fee via oracle**, Arbitrum inclusive estimates, Linea pinned base | Base Sepolia |
53 +| **Bitcoin** | BTC (native SegWit `bc1q…`) | sat/vB presets live from mempool.space, RBF on | Signet |
54 +| **Solana** | SOL + USDC (SPL) | ATA rent surfaced when the recipient has no token account | Devnet |
55 +| **Tron** | TRX + USDT (TRC-20) | **Energy burn estimated pre-send** (~13–27 TRX), fee_limit capped | Nile |
56 +| **XRP Ledger** | XRP + RLUSD | Reserves shown as locked; **one-tap RLUSD trustline**; recipient trustline checked | Testnet |
57 +| **TON** | TON + USDT (jetton) | Jetton-wallet indirection handled; ~0.07 TON attached, excess refunded | Testnet |
58 +
59 +Every stablecoin contract address and decimal count was **verified live
60 +on-chain** before registration — including the traps: BNB-peg USDT/USDC are
61 +18 decimals, bridged USDC.e is indistinguishable from native USDC by
62 +`symbol()` alone, DAI is 18 while USDC is 6. See
63 +[`docs/STABLECOINS.md`](docs/STABLECOINS.md).
64 +
65 +## Security model
66 +
67 +```
68 +password ──▶ PBKDF2-HMAC-SHA512 (600k) ──▶ AES-256-GCM ──▶ vault.json (0600)
69 +
70 + wrong password / tampering ─┘ indistinguishable (GCM auth)
71 +
72 +unlock ──▶ public addresses only stay in memory
73 +send ──▶ password → derive key → sign → discard (every single time)
74 +```
75 +
76 +- Forced written-backup verification (3 random words) before the wallet exists
77 +- Confirm screen with recipient, amount, network, worst-case fees — always
78 +- EIP-55 checksums; per-chain address validation; TESTNET badges everywhere
79 +- App Sandbox + Hardened Runtime; signed, **notarized and stapled** by Apple
80 +- The watch-only Bitcoin wallet holds public descriptors only; a throwaway
81 + in-memory signer signs PSBTs
82 +
83 +## Infrastructure — no API keys
84 +
85 +| Concern | Source (keyless) | Fallback |
86 +|---|---|---|
87 +| EVM RPC | PublicNode (11/11 verified) | official chain RPCs, health-scored failover |
88 +| Bitcoin | mempool.space Esplora | blockstream.info |
89 +| Solana | PublicNode | api.mainnet-beta.solana.com |
90 +| Tron | TronGrid (anonymous, backoff) | — |
91 +| XRPL | xrplcluster.com | s1.ripple.com |
92 +| TON | toncenter v2/v3 (1 req/s, throttled client-side) | — |
93 +| Prices | CoinGecko batched (USD/CAD/EUR), stale-while-revalidate, **off switch** | DefiLlama |
94 +
95 +## Build
96 +
97 +Pure SwiftPM — no `.xcodeproj`, no CocoaPods, no manual steps:
98 +
99 +```sh
100 +scripts/vendor-walletcore.sh # one-time: vendors Trust wallet-core for macOS (~270 MB, not in git)
101 +swift build # compile
102 +swift test # 32 tests: BIP-39/BIP-84 vectors, vault crypto, decimals, validators
103 +make dev # debug bundle, ad-hoc signed, launched
104 +make release # Developer ID + notarize + staple + DMG with volume icon
105 +```
106 +
107 +The wallet-core vendoring is this repo's party trick: upstream ships no macOS
108 +SwiftPM support, so the script repackages the official CocoaPods tarball as a
109 +local `binaryTarget` — including a surgical `ld -r` pass that demotes the
110 +duplicate Rust runtime symbol it shares with the Bitcoin Dev Kit. Details in
111 +[`docs/RESEARCH-MULTICHAIN.md`](docs/RESEARCH-MULTICHAIN.md).
112 +
113 +## Architecture
114 +
115 +```
116 +Sources/OSVaultKit
117 +├── Services
118 +│ ├── VaultCrypto ← the encryption mechanism (no Keychain)
119 +│ ├── KeyManager ← BIP-39, HD derivation, vault lifecycle
120 +│ ├── RPCService ← EVM JSON-RPC with endpoint failover
121 +│ ├── TransactionService ← EIP-1559 + 5 other real fee models
122 +│ ├── BitcoinService ← bdk-swift, watch-only + transient signer
123 +│ ├── SolanaService ← solana-swift (vendored), SPL + ATA
124 +│ ├── TronService ← wallet-core signing + TronGrid REST
125 +│ ├── XRPLService ← wallet-core signing + xrplcluster JSON-RPC
126 +│ ├── TONService ← wallet-core signing + toncenter v2/v3
127 +│ └── PriceService ← CoinGecko keyless, cached, optional
128 +├── Models ← Network (chain registry), Token (verified matrix)…
129 +└── Views ← SwiftUI: onboarding, home, per-chain panels
130 +```
131 +
132 +## Requirements
133 +
134 +- macOS 15.5+ (Apple silicon or Intel)
135 +- That's it. No accounts, no keys, no configuration.
136 +
137 +## Testnet quickstart
138 +
139 +1. Create a wallet (write the 12 words down — the app makes you prove it).
140 +2. Fund: [Circle faucet](https://faucet.circle.com) (USDC on Base Sepolia +
141 + Solana devnet), a Base Sepolia ETH faucet, [mempool.space signet
142 + faucet](https://signetfaucet.com), [nileex.io](https://nileex.io) (TRX +
143 + test USDT), [XRPL faucet](https://xrpl.org/resources/dev-tools/xrp-faucets),
144 + [@testgiver_ton_bot](https://t.me/testgiver_ton_bot).
145 +3. Send. Watch it confirm on the linked explorer.
146 +
147 +---
148 +
149 +<div align="center">
150 +
151 +**Built with Swift, paranoia, and a refusal to type API keys.**
152 +© 2026 Simon-Pierre Boucher · [contact@spboucher.ai](mailto:contact@spboucher.ai)
153 +
154 +</div>
added Sources/OSVault/main.swift +11 −0
@@ -0,0 +1,11 @@
1 +//
2 +// main.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import OSVaultKit
10 +
11 +OSVaultApp.main()
added Sources/OSVaultKit/App/AppState.swift +344 −0
@@ -0,0 +1,344 @@
1 +//
2 +// AppState.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import SwiftUI
11 +import BigInt
12 +
13 +/// Single source of truth for the UI. Holds the public wallet address and
14 +/// balances; never the private key — signing re-derives it from the vault
15 +/// password at confirmation time and discards it immediately.
16 +@MainActor
17 +public final class AppState: ObservableObject {
18 +
19 + public enum Phase: Equatable {
20 + case onboarding
21 + case locked
22 + case unlocked
23 + }
24 +
25 + @Published public var phase: Phase
26 + @Published public var address: String?
27 + @Published public var network: Network {
28 + didSet {
29 + UserDefaults.standard.set(network.rawValue, forKey: Self.networkKey)
30 + restartPollingIfUnlocked()
31 + }
32 + }
33 + @Published public var balances = Balances()
34 + @Published public var balancesLoaded = false
35 + @Published public var balanceError: String?
36 + @Published public var history: [TransactionRecord] = []
37 + @Published public var fiatPrices: [String: Decimal] = [:]
38 + @Published public var pricesEnabled: Bool {
39 + didSet {
40 + UserDefaults.standard.set(pricesEnabled, forKey: PriceService.enabledKey)
41 + if pricesEnabled { Task { await refreshPrices() } } else { fiatPrices = [:] }
42 + }
43 + }
44 + @Published public var fiatCurrency: String {
45 + didSet {
46 + UserDefaults.standard.set(fiatCurrency, forKey: PriceService.fiatKey)
47 + Task { await refreshPrices() }
48 + }
49 + }
50 +
51 + public let priceService = PriceService()
52 + public let bitcoinService = BitcoinService()
53 + public let solanaService = SolanaService()
54 + public let tronService = TronService()
55 + public let xrplService = XRPLService()
56 + @Published public var xrplBalances: XRPLService.XRPLBalances?
57 + @Published public var xrplAddress: String?
58 + @Published public var xrplError: String?
59 + @Published public var xrplNetwork: XRPLService.XRPLNetwork = .testnet
60 + public let tonService = TONService()
61 + @Published public var tonBalancesState: TONService.TONBalances?
62 + @Published public var tonAddress: String?
63 + @Published public var tonError: String?
64 + @Published public var tonNetwork: TONService.TONNetwork = .testnet
65 + @Published public var tronBalances: TronService.TronBalances?
66 + @Published public var tronAddress: String?
67 + @Published public var tronError: String?
68 + @Published public var tronNetwork: TronService.TronNetwork = .nile
69 + @Published public var solBalances: SolanaService.SOLBalances?
70 + @Published public var solAddress: String?
71 + @Published public var solError: String?
72 + @Published public var solNetwork: SolanaService.SOLNetwork = .devnet
73 + @Published public var btcBalance: BitcoinService.BTCBalance?
74 + @Published public var btcSyncing = false
75 + @Published public var btcError: String?
76 + @Published public var btcNetwork: BitcoinService.BTCNetwork = .signet
77 + public let keyManager: KeyManager
78 + let historyStore: HistoryStore
79 + private var pollTask: Task<Void, Never>?
80 +
81 + static let networkKey = "osvault.network"
82 + public static let pollInterval: Duration = .seconds(15)
83 +
84 + public init(keyManager: KeyManager = KeyManager(), historyStore: HistoryStore = HistoryStore()) {
85 + self.keyManager = keyManager
86 + self.historyStore = historyStore
87 + let saved = UserDefaults.standard.string(forKey: Self.networkKey)
88 + self.network = saved.flatMap(Network.init(rawValue:)) ?? .baseSepolia
89 + self.phase = keyManager.hasVault ? .locked : .onboarding
90 + self.history = historyStore.load()
91 + self.pricesEnabled = UserDefaults.standard.object(forKey: PriceService.enabledKey) as? Bool ?? true
92 + self.fiatCurrency = UserDefaults.standard.string(forKey: PriceService.fiatKey) ?? "USD"
93 + }
94 +
95 + public func rpc() -> RPCService {
96 + RPCService(urls: network.rpcURLs)
97 + }
98 +
99 + // MARK: - Session
100 +
101 + public func didUnlock(wallet: KeyManager.UnlockedWallet) {
102 + self.address = wallet.address
103 + self.phase = .unlocked
104 + let mnemonic = wallet.mnemonic
105 + Task {
106 + do {
107 + try await bitcoinService.configure(mnemonic: mnemonic)
108 + btcNetwork = await bitcoinService.currentNetwork
109 + await refreshBitcoin()
110 + } catch {
111 + btcError = error.localizedDescription
112 + }
113 + }
114 + Task {
115 + do {
116 + try await solanaService.configure(mnemonic: mnemonic)
117 + solNetwork = await solanaService.currentNetwork
118 + solAddress = await solanaService.publicAddress
119 + await refreshSolana()
120 + } catch {
121 + solError = error.localizedDescription
122 + }
123 + }
124 + Task {
125 + do {
126 + try await tronService.configure(mnemonic: mnemonic)
127 + tronNetwork = await tronService.currentNetwork
128 + tronAddress = await tronService.publicAddress
129 + await refreshTron()
130 + } catch {
131 + tronError = error.localizedDescription
132 + }
133 + }
134 + Task {
135 + do {
136 + try await xrplService.configure(mnemonic: mnemonic)
137 + xrplNetwork = await xrplService.currentNetwork
138 + xrplAddress = await xrplService.publicAddress
139 + await refreshXRPL()
140 + } catch {
141 + xrplError = error.localizedDescription
142 + }
143 + }
144 + Task {
145 + do {
146 + try await tonService.configure(mnemonic: mnemonic)
147 + tonNetwork = await tonService.currentNetwork
148 + tonAddress = await tonService.publicAddress
149 + await refreshTON()
150 + } catch {
151 + tonError = error.localizedDescription
152 + }
153 + }
154 + startPolling()
155 + }
156 +
157 + public func refreshBitcoin() async {
158 + guard await bitcoinService.isConfigured else { return }
159 + btcSyncing = true
160 + defer { btcSyncing = false }
161 + do {
162 + try await bitcoinService.sync()
163 + btcBalance = await bitcoinService.balance()
164 + btcError = nil
165 + } catch {
166 + btcError = error.localizedDescription
167 + }
168 + }
169 +
170 + public func refreshSolana() async {
171 + guard await solanaService.isConfigured else { return }
172 + do {
173 + solBalances = try await solanaService.fetchBalances()
174 + solError = nil
175 + } catch {
176 + solError = error.localizedDescription
177 + }
178 + }
179 +
180 + public func refreshTron() async {
181 + guard await tronService.isConfigured else { return }
182 + do {
183 + tronBalances = try await tronService.fetchBalances()
184 + tronError = nil
185 + } catch {
186 + tronError = error.localizedDescription
187 + }
188 + }
189 +
190 + public func switchTronNetwork(to newNetwork: TronService.TronNetwork) async {
191 + await tronService.switchNetwork(to: newNetwork)
192 + tronNetwork = newNetwork
193 + tronBalances = nil
194 + await refreshTron()
195 + }
196 +
197 + public func refreshXRPL() async {
198 + guard await xrplService.isConfigured else { return }
199 + do {
200 + xrplBalances = try await xrplService.fetchBalances()
201 + xrplError = nil
202 + } catch {
203 + xrplError = error.localizedDescription
204 + }
205 + }
206 +
207 + public func switchXRPLNetwork(to newNetwork: XRPLService.XRPLNetwork) async {
208 + await xrplService.switchNetwork(to: newNetwork)
209 + xrplNetwork = newNetwork
210 + xrplBalances = nil
211 + await refreshXRPL()
212 + }
213 +
214 + public func refreshTON() async {
215 + guard await tonService.isConfigured else { return }
216 + do {
217 + tonBalancesState = try await tonService.fetchBalances()
218 + tonError = nil
219 + } catch {
220 + tonError = error.localizedDescription
221 + }
222 + }
223 +
224 + public func switchTONNetwork(to newNetwork: TONService.TONNetwork) async {
225 + await tonService.switchNetwork(to: newNetwork)
226 + tonNetwork = newNetwork
227 + tonBalancesState = nil
228 + await refreshTON()
229 + }
230 +
231 + public func switchSolanaNetwork(to newNetwork: SolanaService.SOLNetwork) async {
232 + await solanaService.switchNetwork(to: newNetwork)
233 + solNetwork = newNetwork
234 + solBalances = nil
235 + await refreshSolana()
236 + }
237 +
238 + /// Re-derives descriptors for the new BTC network; needs the password.
239 + public func switchBitcoinNetwork(to newNetwork: BitcoinService.BTCNetwork, password: String) async throws {
240 + let mnemonic = try await Task.detached { [keyManager] in
241 + try keyManager.unlock(password: password).mnemonic
242 + }.value
243 + try await bitcoinService.switchNetwork(to: newNetwork, mnemonic: mnemonic)
244 + btcNetwork = newNetwork
245 + btcBalance = nil
246 + await refreshBitcoin()
247 + }
248 +
249 + public func lock() {
250 + pollTask?.cancel()
251 + pollTask = nil
252 + address = nil
253 + balances = Balances()
254 + balancesLoaded = false
255 + phase = .locked
256 + }
257 +
258 + public func walletDeleted() {
259 + pollTask?.cancel()
260 + pollTask = nil
261 + address = nil
262 + balances = Balances()
263 + balancesLoaded = false
264 + history = []
265 + historyStore.clear()
266 + btcBalance = nil
267 + solBalances = nil
268 + solAddress = nil
269 + tronBalances = nil
270 + tronAddress = nil
271 + xrplBalances = nil
272 + xrplAddress = nil
273 + tonBalancesState = nil
274 + tonAddress = nil
275 + // Remove the BDK watch-only databases and scan flags with the vault.
276 + let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
277 + for network in BitcoinService.BTCNetwork.allCases {
278 + try? FileManager.default.removeItem(
279 + at: support.appendingPathComponent("OSVault/bdk-\(network.rawValue).sqlite"))
280 + UserDefaults.standard.removeObject(forKey: "osvault.bitcoin.scanned.\(network.rawValue)")
281 + }
282 + phase = .onboarding
283 + }
284 +
285 + // MARK: - Balances
286 +
287 + public func refreshBalances() async {
288 + guard let address else { return }
289 + do {
290 + let fetched = try await BalanceService.fetch(address: address, network: network, rpc: rpc())
291 + balances = fetched
292 + balancesLoaded = true
293 + balanceError = nil
294 + } catch {
295 + balanceError = error.localizedDescription
296 + }
297 + }
298 +
299 + public func refreshPrices() async {
300 + guard pricesEnabled else { return }
301 + let symbols = Token.available(on: network).map(\.symbol)
302 + + [network.config.nativeSymbol, "BTC", "SOL", "TRX", "USDT", "XRP", "TON"]
303 + fiatPrices = await priceService.prices(for: symbols, fiat: fiatCurrency)
304 + }
305 +
306 + private func startPolling() {
307 + pollTask?.cancel()
308 + pollTask = Task { [weak self] in
309 + var tick = 0
310 + while !Task.isCancelled {
311 + await self?.refreshBalances()
312 + await self?.refreshPrices()
313 + // Bitcoin blocks are ~10 min; sync every 4th tick (60 s).
314 + if tick % 4 == 0 { await self?.refreshBitcoin() }
315 + if tick % 2 == 0 { await self?.refreshSolana() }
316 + if tick % 2 == 1 { await self?.refreshTron() }
317 + if tick % 4 == 1 { await self?.refreshXRPL() }
318 + if tick % 4 == 3 { await self?.refreshTON() }
319 + tick += 1
320 + try? await Task.sleep(for: Self.pollInterval)
321 + }
322 + }
323 + }
324 +
325 + private func restartPollingIfUnlocked() {
326 + guard phase == .unlocked else { return }
327 + balances = Balances()
328 + balancesLoaded = false
329 + startPolling()
330 + }
331 +
332 + // MARK: - History
333 +
334 + public func recordSend(_ record: TransactionRecord) {
335 + history.insert(record, at: 0)
336 + historyStore.save(history)
337 + }
338 +
339 + public func updateRecord(hash: String, status: TransactionRecord.Status) {
340 + guard let index = history.firstIndex(where: { $0.hash == hash }) else { return }
341 + history[index].status = status
342 + historyStore.save(history)
343 + }
344 +}
added Sources/OSVaultKit/App/OSVaultApp.swift +39 −0
@@ -0,0 +1,39 @@
1 +//
2 +// OSVaultApp.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +
11 +public struct OSVaultApp: App {
12 + @StateObject private var app = AppState()
13 +
14 + public init() {}
15 +
16 + public var body: some Scene {
17 + WindowGroup {
18 + ContentView()
19 + .environmentObject(app)
20 + .frame(minWidth: 520, minHeight: 640)
21 + }
22 + .windowResizability(.contentSize)
23 + }
24 +}
25 +
26 +struct ContentView: View {
27 + @EnvironmentObject var app: AppState
28 +
29 + var body: some View {
30 + switch app.phase {
31 + case .onboarding:
32 + OnboardingView()
33 + case .locked:
34 + UnlockView()
35 + case .unlocked:
36 + HomeView()
37 + }
38 + }
39 +}
added Sources/OSVaultKit/Models/Asset.swift +51 −0
@@ -0,0 +1,51 @@
1 +//
2 +// Asset.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +
11 +/// Anything the wallet can send on an EVM chain: the chain's native coin
12 +/// (ETH, POL, BNB, AVAX, xDAI… — also the gas currency) or a registered
13 +/// ERC-20 stablecoin. Native symbol/name depend on the chain, so they are
14 +/// resolved against a Network.
15 +public enum Asset: Identifiable, Hashable, Sendable {
16 + case native
17 + case token(Token)
18 +
19 + public var id: String {
20 + switch self {
21 + case .native: return "native"
22 + case .token(let token): return "token-\(token.symbol)"
23 + }
24 + }
25 +
26 + public func symbol(on network: Network) -> String {
27 + switch self {
28 + case .native: return network.config.nativeSymbol
29 + case .token(let token): return token.symbol
30 + }
31 + }
32 +
33 + public func name(on network: Network) -> String {
34 + switch self {
35 + case .native: return network.config.nativeName
36 + case .token(let token): return token.name
37 + }
38 + }
39 +
40 + /// All supported natives are 18 decimals (ETH, POL, BNB, AVAX, xDAI).
41 + public var decimals: Int {
42 + switch self {
43 + case .native: return 18
44 + case .token(let token): return token.decimals
45 + }
46 + }
47 +
48 + public static func available(on network: Network) -> [Asset] {
49 + Token.available(on: network).map(Asset.token) + [.native]
50 + }
51 +}
added Sources/OSVaultKit/Models/Network.swift +195 −0
@@ -0,0 +1,195 @@
1 +//
2 +// Network.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +
12 +/// The EVM chains OS Vault can talk to. Fully data-driven: adding a chain is
13 +/// a new case + ChainConfig entry. Every chain id and RPC below was verified
14 +/// live before being listed (see docs/RESEARCH-MULTICHAIN.md). Non-EVM chains
15 +/// (Bitcoin, Solana, Tron, TON, XRPL…) use their own adapters.
16 +public enum Network: String, CaseIterable, Codable, Identifiable, Sendable {
17 + case baseSepolia // testnet — safe default for development
18 + case baseMainnet
19 + case ethereum
20 + case arbitrum
21 + case optimism
22 + case polygon
23 + case bnb
24 + case avalanche
25 + case gnosis
26 + case linea
27 + case scroll
28 +
29 + public var id: String { rawValue }
30 +
31 + /// How transaction fees actually work on this chain — the research
32 + /// finding is that "EIP-1559" hides four distinct realities.
33 + public enum FeeModel: Sendable {
34 + /// Standard: maxFee = 2×baseFee + tip.
35 + case eip1559
36 + /// BNB Chain (BEP-226): baseFee is 0; price via eth_gasPrice.
37 + case zeroBaseFee
38 + /// OP-stack (Base, Optimism): L2 fee + L1 data fee from the
39 + /// GasPriceOracle predeploy at 0x42…0F, deducted silently.
40 + case opStackL1Fee
41 + /// Scroll: same idea, oracle at 0x5300…0002.
42 + case scrollL1Fee
43 + /// Arbitrum: estimateGas already folds the L1 buffer into gasLimit;
44 + /// suggested tip is 0.
45 + case arbitrumInclusive
46 + /// Linea: base fee pinned at 7 wei; real cost rides in the tip.
47 + case lineaPinnedBase
48 + }
49 +
50 + public struct ChainConfig: Sendable {
51 + public let chainID: BigUInt
52 + public let displayName: String
53 + public let nativeSymbol: String
54 + public let nativeName: String
55 + /// Ordered keyless endpoints: primary first, chain id verified live.
56 + public let rpcs: [URL]
57 + public let explorerBase: URL
58 + public let feeModel: FeeModel
59 + public let isTestnet: Bool
60 + }
61 +
62 + public var config: ChainConfig {
63 + switch self {
64 + case .baseSepolia:
65 + return ChainConfig(
66 + chainID: 84532, displayName: "Base Sepolia",
67 + nativeSymbol: "ETH", nativeName: "Ether",
68 + rpcs: [URL(string: "https://sepolia.base.org")!,
69 + URL(string: "https://base-sepolia-rpc.publicnode.com")!],
70 + explorerBase: URL(string: "https://sepolia.basescan.org")!,
71 + feeModel: .opStackL1Fee, isTestnet: true
72 + )
73 + case .baseMainnet:
74 + return ChainConfig(
75 + chainID: 8453, displayName: "Base",
76 + nativeSymbol: "ETH", nativeName: "Ether",
77 + rpcs: [URL(string: "https://base-rpc.publicnode.com")!,
78 + URL(string: "https://mainnet.base.org")!],
79 + explorerBase: URL(string: "https://basescan.org")!,
80 + feeModel: .opStackL1Fee, isTestnet: false
81 + )
82 + case .ethereum:
83 + return ChainConfig(
84 + chainID: 1, displayName: "Ethereum",
85 + nativeSymbol: "ETH", nativeName: "Ether",
86 + rpcs: [URL(string: "https://ethereum-rpc.publicnode.com")!,
87 + URL(string: "https://cloudflare-eth.com")!,
88 + URL(string: "https://eth.merkle.io")!],
89 + explorerBase: URL(string: "https://etherscan.io")!,
90 + feeModel: .eip1559, isTestnet: false
91 + )
92 + case .arbitrum:
93 + return ChainConfig(
94 + chainID: 42161, displayName: "Arbitrum One",
95 + nativeSymbol: "ETH", nativeName: "Ether",
96 + rpcs: [URL(string: "https://arbitrum-one-rpc.publicnode.com")!,
97 + URL(string: "https://arb1.arbitrum.io/rpc")!],
98 + explorerBase: URL(string: "https://arbiscan.io")!,
99 + feeModel: .arbitrumInclusive, isTestnet: false
100 + )
101 + case .optimism:
102 + return ChainConfig(
103 + chainID: 10, displayName: "OP Mainnet",
104 + nativeSymbol: "ETH", nativeName: "Ether",
105 + rpcs: [URL(string: "https://optimism-rpc.publicnode.com")!,
106 + URL(string: "https://mainnet.optimism.io")!],
107 + explorerBase: URL(string: "https://optimistic.etherscan.io")!,
108 + feeModel: .opStackL1Fee, isTestnet: false
109 + )
110 + case .polygon:
111 + return ChainConfig(
112 + chainID: 137, displayName: "Polygon",
113 + nativeSymbol: "POL", nativeName: "Polygon Ecosystem Token",
114 + rpcs: [URL(string: "https://polygon-bor-rpc.publicnode.com")!,
115 + URL(string: "https://polygon.drpc.org")!],
116 + explorerBase: URL(string: "https://polygonscan.com")!,
117 + feeModel: .eip1559, isTestnet: false
118 + )
119 + case .bnb:
120 + return ChainConfig(
121 + chainID: 56, displayName: "BNB Chain",
122 + nativeSymbol: "BNB", nativeName: "BNB",
123 + rpcs: [URL(string: "https://bsc-rpc.publicnode.com")!,
124 + URL(string: "https://bsc-dataseed.bnbchain.org")!],
125 + explorerBase: URL(string: "https://bscscan.com")!,
126 + feeModel: .zeroBaseFee, isTestnet: false
127 + )
128 + case .avalanche:
129 + return ChainConfig(
130 + chainID: 43114, displayName: "Avalanche C-Chain",
131 + nativeSymbol: "AVAX", nativeName: "Avalanche",
132 + rpcs: [URL(string: "https://avalanche-c-chain-rpc.publicnode.com")!,
133 + URL(string: "https://api.avax.network/ext/bc/C/rpc")!],
134 + explorerBase: URL(string: "https://snowtrace.io")!,
135 + feeModel: .eip1559, isTestnet: false
136 + )
137 + case .gnosis:
138 + return ChainConfig(
139 + chainID: 100, displayName: "Gnosis",
140 + nativeSymbol: "xDAI", nativeName: "xDAI (dollar-pegged)",
141 + rpcs: [URL(string: "https://gnosis-rpc.publicnode.com")!,
142 + URL(string: "https://rpc.gnosischain.com")!],
143 + explorerBase: URL(string: "https://gnosisscan.io")!,
144 + feeModel: .eip1559, isTestnet: false
145 + )
146 + case .linea:
147 + return ChainConfig(
148 + chainID: 59144, displayName: "Linea",
149 + nativeSymbol: "ETH", nativeName: "Ether",
150 + rpcs: [URL(string: "https://linea-rpc.publicnode.com")!,
151 + URL(string: "https://rpc.linea.build")!],
152 + explorerBase: URL(string: "https://lineascan.build")!,
153 + feeModel: .lineaPinnedBase, isTestnet: false
154 + )
155 + case .scroll:
156 + return ChainConfig(
157 + chainID: 534352, displayName: "Scroll",
158 + nativeSymbol: "ETH", nativeName: "Ether",
159 + rpcs: [URL(string: "https://scroll-rpc.publicnode.com")!,
160 + URL(string: "https://rpc.scroll.io")!],
161 + explorerBase: URL(string: "https://scrollscan.com")!,
162 + feeModel: .scrollL1Fee, isTestnet: false
163 + )
164 + }
165 + }
166 +
167 + /// L1 data-fee oracle for rollups that charge one (`getL1Fee(bytes)`).
168 + public var l1FeeOracle: String? {
169 + switch config.feeModel {
170 + case .opStackL1Fee: return "0x420000000000000000000000000000000000000F"
171 + case .scrollL1Fee: return "0x5300000000000000000000000000000000000002"
172 + default: return nil
173 + }
174 + }
175 +
176 + /// Active RPC endpoints, user override (Settings) first.
177 + public var rpcURLs: [URL] {
178 + var urls = config.rpcs
179 + if let raw = UserDefaults.standard.string(forKey: rpcOverrideKey),
180 + !raw.isEmpty, let url = URL(string: raw), url.scheme?.hasPrefix("http") == true {
181 + urls.insert(url, at: 0)
182 + }
183 + return urls
184 + }
185 +
186 + public var rpcOverrideKey: String { "osvault.rpcOverride.\(rawValue)" }
187 +
188 + public func explorerTxURL(_ hash: String) -> URL {
189 + config.explorerBase.appendingPathComponent("tx/\(hash)")
190 + }
191 +
192 + public func explorerAddressURL(_ address: String) -> URL {
193 + config.explorerBase.appendingPathComponent("address/\(address)")
194 + }
195 +}
added Sources/OSVaultKit/Models/Token.swift +128 −0
@@ -0,0 +1,128 @@
1 +//
2 +// Token.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +
11 +/// An ERC-20 stablecoin deployment set. Every address and decimal count below
12 +/// was verified live on-chain via `symbol()`/`decimals()` eth_calls
13 +/// (docs/STABLECOINS.md + docs/RESEARCH-MULTICHAIN.md, 2026-08-05).
14 +///
15 +/// Registry rules learned from that research:
16 +/// - decimals are per-DEPLOYMENT data: USDT/USDC are 18 on BNB Chain, 6
17 +/// everywhere else — hence the separate BNB-peg entries.
18 +/// - bridged USDC.e reports the same `symbol()` as native USDC on
19 +/// Arbitrum/Optimism/Polygon; the registry distinguishes them by address
20 +/// and shows "USDC.e" to the user.
21 +/// - Arbitrum/Polygon USDT was upgraded in place to USDT0 (same address,
22 +/// same 6 decimals) — never assert on-chain symbol strings.
23 +public struct Token: Identifiable, Hashable, Sendable {
24 + public let symbol: String
25 + public let name: String
26 + public let decimals: Int
27 + /// Checksummed contract address per network the token is deployed on.
28 + public let addresses: [Network: String]
29 +
30 + public var id: String { symbol }
31 +
32 + public func address(on network: Network) -> String? {
33 + addresses[network]
34 + }
35 +
36 + // MARK: - Registry
37 +
38 + public static let usdc = Token(
39 + symbol: "USDC", name: "USD Coin", decimals: 6,
40 + addresses: [
41 + .baseSepolia: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
42 + .baseMainnet: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
43 + .ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
44 + .arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
45 + .optimism: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
46 + .polygon: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
47 + .avalanche: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
48 + .linea: "0x176211869cA2b568f2A7D4EE941E073a821EE1ff"
49 + ]
50 + )
51 +
52 + /// Bridged USDC — same on-chain symbol as native USDC, different address.
53 + public static let usdce = Token(
54 + symbol: "USDC.e", name: "Bridged USDC", decimals: 6,
55 + addresses: [
56 + .arbitrum: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
57 + .optimism: "0x7F5c764cBc14f9669B88837ca1490cCa17c31607",
58 + .polygon: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
59 + .avalanche: "0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664",
60 + .gnosis: "0x2a22f9c3b484c3629090FeED35F17Ff8F88f76F0",
61 + .scroll: "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4"
62 + ]
63 + )
64 +
65 + public static let usdt = Token(
66 + symbol: "USDT", name: "Tether USD", decimals: 6,
67 + addresses: [
68 + .baseMainnet: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
69 + .ethereum: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
70 + .arbitrum: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", // USDT0 in-place upgrade
71 + .optimism: "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58",
72 + .polygon: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", // USDT0 in-place upgrade
73 + .avalanche: "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", // native USDt
74 + .gnosis: "0x4ECaBa5870353805a9F068101A40E0f32ed605C6",
75 + .linea: "0xA219439258ca9da29E9Cc4cE5596924745e12B93",
76 + .scroll: "0xf55BEC9cafDbE8730f096Aa55dad6D22d44099Df"
77 + ]
78 + )
79 +
80 + /// Binance-peg variants: 18 decimals, not issuer-native. Kept as separate
81 + /// registry entries because decimals differ from every other deployment.
82 + public static let usdtBNB = Token(
83 + symbol: "USDT", name: "Tether USD (BNB peg)", decimals: 18,
84 + addresses: [.bnb: "0x55d398326f99059fF775485246999027B3197955"]
85 + )
86 +
87 + public static let usdcBNB = Token(
88 + symbol: "USDC", name: "USD Coin (BNB peg)", decimals: 18,
89 + addresses: [.bnb: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"]
90 + )
91 +
92 + public static let dai = Token(
93 + symbol: "DAI", name: "Dai Stablecoin", decimals: 18,
94 + addresses: [
95 + .baseMainnet: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
96 + .ethereum: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
97 + .arbitrum: "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
98 + .optimism: "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
99 + .polygon: "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
100 + .bnb: "0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3",
101 + .avalanche: "0xd586E7F844cEa2F87f50152665BCbc2C279D8d70", // DAI.e
102 + .linea: "0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5",
103 + .scroll: "0xcA77eB3fEFe3725Dc33bccB54eDEFc3D9f764f97"
104 + ]
105 + )
106 +
107 + public static let usds = Token(
108 + symbol: "USDS", name: "Sky Dollar", decimals: 18,
109 + addresses: [
110 + .ethereum: "0xdC035D45d973E3EC169d2276DDab16f1e407384F",
111 + .baseMainnet: "0x820C137fa70C8691f0e44Dc420a5e53c168921Dc"
112 + ]
113 + )
114 +
115 + public static let eurc = Token(
116 + symbol: "EURC", name: "Euro Coin", decimals: 6,
117 + addresses: [
118 + .baseMainnet: "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
119 + ]
120 + )
121 +
122 + public static let all: [Token] = [usdc, usdcBNB, usdce, usdt, usdtBNB, dai, usds, eurc]
123 +
124 + /// Tokens usable on a given network, USDC-family first.
125 + public static func available(on network: Network) -> [Token] {
126 + all.filter { $0.addresses[network] != nil }
127 + }
128 +}
added Sources/OSVaultKit/Models/TokenAmount.swift +59 −0
@@ -0,0 +1,59 @@
1 +//
2 +// TokenAmount.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +
12 +/// Integer-only conversion between base units and display strings.
13 +/// `Double` is banned for money: 6- and 18-decimal tokens both exceed the
14 +/// 53-bit mantissa long before real-world balances do.
15 +public enum TokenAmount {
16 +
17 + /// "12.5" with decimals 6 → 12_500_000. Returns nil on malformed input or
18 + /// more fraction digits than the token supports. Accepts "," as separator.
19 + public static func parse(_ input: String, decimals: Int) -> BigUInt? {
20 + let normalized = input
21 + .trimmingCharacters(in: .whitespacesAndNewlines)
22 + .replacingOccurrences(of: ",", with: ".")
23 + guard !normalized.isEmpty, normalized != "." else { return nil }
24 +
25 + let parts = normalized.split(separator: ".", omittingEmptySubsequences: false)
26 + guard parts.count <= 2 else { return nil }
27 +
28 + let wholePart = String(parts[0])
29 + let fracPart = parts.count == 2 ? String(parts[1]) : ""
30 + guard wholePart.allSatisfy(\.isNumber), fracPart.allSatisfy(\.isNumber) else { return nil }
31 + guard !(wholePart.isEmpty && fracPart.isEmpty) else { return nil }
32 + guard fracPart.count <= decimals else { return nil }
33 +
34 + let whole = BigUInt(wholePart.isEmpty ? "0" : wholePart, radix: 10) ?? 0
35 + let paddedFrac = fracPart.padding(toLength: decimals, withPad: "0", startingAt: 0)
36 + let frac = paddedFrac.isEmpty ? BigUInt(0) : (BigUInt(paddedFrac, radix: 10) ?? 0)
37 + return whole * BigUInt(10).power(decimals) + frac
38 + }
39 +
40 + /// 12_500_000 with decimals 6 → "12.5". Trailing zeros trimmed,
41 + /// optionally capped to `maxFractionDigits` (truncated, never rounded up —
42 + /// a wallet must not display more than the user owns).
43 + public static func format(_ units: BigUInt, decimals: Int, maxFractionDigits: Int? = nil) -> String {
44 + let divisor = BigUInt(10).power(decimals)
45 + let whole = units / divisor
46 + var frac = String(units % divisor)
47 + frac = String(repeating: "0", count: max(0, decimals - frac.count)) + frac
48 + if let cap = maxFractionDigits, frac.count > cap {
49 + frac = String(frac.prefix(cap))
50 + }
51 + while frac.hasSuffix("0") { frac.removeLast() }
52 + return frac.isEmpty ? String(whole) : "\(whole).\(frac)"
53 + }
54 +
55 + /// Wei → ETH display string (18 decimals), for gas costs.
56 + public static func formatWei(_ wei: BigUInt, maxFractionDigits: Int = 8) -> String {
57 + format(wei, decimals: 18, maxFractionDigits: maxFractionDigits)
58 + }
59 +}
added Sources/OSVaultKit/Models/TransactionRecord.swift +85 −0
@@ -0,0 +1,85 @@
1 +//
2 +// TransactionRecord.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +
12 +/// A send initiated from this app, persisted locally (non-sensitive data
13 +/// only: it is all public on-chain anyway). Full history lives on the
14 +/// explorer; each record links there.
15 +public struct TransactionRecord: Identifiable, Codable, Equatable {
16 + public enum Status: String, Codable {
17 + case pending, confirmed, failed
18 + }
19 +
20 + public let id: UUID
21 + public let hash: String
22 + public let tokenSymbol: String
23 + public let tokenDecimals: Int
24 + public let amountUnits: String // BigUInt as decimal string (Codable-safe)
25 + public let recipient: String
26 + public let network: Network
27 + public var status: Status
28 + public let date: Date
29 +
30 + public init(hash: String, asset: Asset, amountUnits: BigUInt,
31 + recipient: String, network: Network, status: Status, date: Date = Date()) {
32 + self.id = UUID()
33 + self.hash = hash
34 + self.tokenSymbol = asset.symbol(on: network)
35 + self.tokenDecimals = asset.decimals
36 + self.amountUnits = String(amountUnits)
37 + self.recipient = recipient
38 + self.network = network
39 + self.status = status
40 + self.date = date
41 + }
42 +
43 + public var displayAmount: String {
44 + guard let units = BigUInt(amountUnits, radix: 10) else { return amountUnits }
45 + return TokenAmount.format(units, decimals: tokenDecimals)
46 + }
47 +
48 + public var explorerURL: URL { network.explorerTxURL(hash) }
49 +}
50 +
51 +/// JSON-file persistence for local send history.
52 +public final class HistoryStore {
53 + private let fileURL: URL
54 + private let maxEntries = 200
55 +
56 + public init(fileURL: URL? = nil) {
57 + if let fileURL {
58 + self.fileURL = fileURL
59 + } else {
60 + let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
61 + self.fileURL = support.appendingPathComponent("OSVault/history.json")
62 + }
63 + }
64 +
65 + public func load() -> [TransactionRecord] {
66 + guard let data = try? Data(contentsOf: fileURL),
67 + let records = try? JSONDecoder().decode([TransactionRecord].self, from: data) else {
68 + return []
69 + }
70 + return records
71 + }
72 +
73 + public func save(_ records: [TransactionRecord]) {
74 + let trimmed = Array(records.prefix(maxEntries))
75 + let dir = fileURL.deletingLastPathComponent()
76 + try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
77 + if let data = try? JSONEncoder().encode(trimmed) {
78 + try? data.write(to: fileURL, options: [.atomic])
79 + }
80 + }
81 +
82 + public func clear() {
83 + try? FileManager.default.removeItem(at: fileURL)
84 + }
85 +}
added Sources/OSVaultKit/Models/WalletError.swift +48 −0
@@ -0,0 +1,48 @@
1 +//
2 +// WalletError.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +
11 +/// Typed errors for every service call. Messages never contain key material.
12 +public enum WalletError: LocalizedError, Equatable {
13 + case noVault
14 + case vaultCorrupted
15 + case wrongPassword
16 + case invalidMnemonic
17 + case invalidAddress
18 + case insufficientETHForGas(needWei: String, haveWei: String)
19 + case insufficientTokenBalance
20 + case rpc(String)
21 + case signingFailed
22 + case internalError(String)
23 +
24 + public var errorDescription: String? {
25 + switch self {
26 + case .noVault:
27 + return "No wallet exists on this Mac yet."
28 + case .vaultCorrupted:
29 + return "The vault file is damaged and cannot be read."
30 + case .wrongPassword:
31 + return "Incorrect password."
32 + case .invalidMnemonic:
33 + return "This recovery phrase is not valid. Check the words and their order."
34 + case .invalidAddress:
35 + return "This is not a valid Ethereum address."
36 + case .insufficientETHForGas(let need, let have):
37 + return "Not enough of the chain's native coin to pay gas (need ~\(need), have \(have)). Gas is always paid in the native coin, never in stablecoins."
38 + case .insufficientTokenBalance:
39 + return "Amount exceeds your token balance."
40 + case .rpc(let message):
41 + return "Network error: \(message)"
42 + case .signingFailed:
43 + return "The transaction could not be signed."
44 + case .internalError(let message):
45 + return message
46 + }
47 + }
48 +}
added Sources/OSVaultKit/Services/BalanceService.swift +38 −0
@@ -0,0 +1,38 @@
1 +//
2 +// BalanceService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +
12 +/// Fetches the native ETH balance (gas money) plus every registered
13 +/// stablecoin's `balanceOf` for the current network.
14 +public struct Balances: Sendable {
15 + public var ethWei: BigUInt
16 + public var tokenUnits: [String: BigUInt] // keyed by token symbol
17 +
18 + public init(ethWei: BigUInt = 0, tokenUnits: [String: BigUInt] = [:]) {
19 + self.ethWei = ethWei
20 + self.tokenUnits = tokenUnits
21 + }
22 +}
23 +
24 +public enum BalanceService {
25 +
26 + public static func fetch(address: String, network: Network, rpc: RPCService) async throws -> Balances {
27 + var balances = Balances()
28 + balances.ethWei = try await rpc.balance(of: address)
29 +
30 + for token in Token.available(on: network) {
31 + guard let contract = token.address(on: network),
32 + let calldata = Hex.erc20BalanceOfData(owner: address) else { continue }
33 + let result = try await rpc.call(to: contract, data: calldata)
34 + balances.tokenUnits[token.symbol] = Hex.toBigUInt(result) ?? 0
35 + }
36 + return balances
37 + }
38 +}
added Sources/OSVaultKit/Services/BitcoinService.swift +310 −0
@@ -0,0 +1,310 @@
1 +//
2 +// BitcoinService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +import BitcoinDevKit
12 +
13 +/// Real Bitcoin support via the Bitcoin Dev Kit (bdk-swift, macOS-native).
14 +///
15 +/// Same one-mnemonic model as the EVM side: BIP-84 native-segwit descriptors
16 +/// (m/84'/…, bc1q addresses) are derived from the vault mnemonic. The service
17 +/// holds a **watch-only** wallet (public descriptors) for sync/balance/
18 +/// receive; sends re-derive the secret descriptors from the vault password,
19 +/// sign the PSBT with a throwaway in-memory signer wallet, and discard them.
20 +///
21 +/// Networking is keyless Esplora (mempool.space / blockstream.info) — sync,
22 +/// fee estimates and broadcast; endpoints follow the research in
23 +/// docs/RESEARCH-MULTICHAIN.md. Default network is signet (testnet-first
24 +/// rule); mainnet sits behind the same explicit switch pattern as EVM.
25 +public actor BitcoinService {
26 +
27 + public enum BTCNetwork: String, CaseIterable, Codable, Sendable {
28 + case mainnet
29 + case signet
30 +
31 + public var bdkNetwork: BitcoinDevKit.Network {
32 + switch self {
33 + case .mainnet: return .bitcoin
34 + case .signet: return .signet
35 + }
36 + }
37 +
38 + public var esploraURL: String {
39 + switch self {
40 + case .mainnet: return "https://mempool.space/api"
41 + case .signet: return "https://mempool.space/signet/api"
42 + }
43 + }
44 +
45 + public var fallbackEsploraURL: String? {
46 + switch self {
47 + case .mainnet: return "https://blockstream.info/api"
48 + case .signet: return nil
49 + }
50 + }
51 +
52 + public var feeAPI: String {
53 + switch self {
54 + case .mainnet: return "https://mempool.space/api/v1/fees/recommended"
55 + case .signet: return "https://mempool.space/signet/api/v1/fees/recommended"
56 + }
57 + }
58 +
59 + public func explorerTxURL(_ txid: String) -> URL {
60 + switch self {
61 + case .mainnet: return URL(string: "https://mempool.space/tx/\(txid)")!
62 + case .signet: return URL(string: "https://mempool.space/signet/tx/\(txid)")!
63 + }
64 + }
65 +
66 + public func explorerAddressURL(_ address: String) -> URL {
67 + switch self {
68 + case .mainnet: return URL(string: "https://mempool.space/address/\(address)")!
69 + case .signet: return URL(string: "https://mempool.space/signet/address/\(address)")!
70 + }
71 + }
72 +
73 + public var displayName: String {
74 + switch self {
75 + case .mainnet: return "Bitcoin"
76 + case .signet: return "Bitcoin Signet"
77 + }
78 + }
79 +
80 + public var isTestnet: Bool { self == .signet }
81 + }
82 +
83 + public static let networkKey = "osvault.bitcoin.network"
84 +
85 + public struct BTCBalance: Sendable {
86 + public var confirmedSats: UInt64 = 0
87 + public var pendingSats: UInt64 = 0
88 + public var totalSats: UInt64 { confirmedSats + pendingSats }
89 + }
90 +
91 + public struct FeeRates: Sendable {
92 + public let fastest: UInt64
93 + public let halfHour: UInt64
94 + public let hour: UInt64
95 + public let economy: UInt64
96 + }
97 +
98 + public struct PreparedBTCSend: Sendable {
99 + public let recipient: String
100 + public let amountSats: UInt64
101 + public let feeSats: UInt64
102 + public let feeRateSatVb: UInt64
103 + public let network: BTCNetwork
104 + }
105 +
106 + private var wallet: Wallet?
107 + private var persister: Persister?
108 + private var network: BTCNetwork = .signet
109 + private var pendingPsbt: Psbt?
110 + private var hasFullScanned = false
111 + private let dataDir: URL
112 +
113 + public init(dataDir: URL? = nil) {
114 + if let dataDir {
115 + self.dataDir = dataDir
116 + } else {
117 + let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
118 + self.dataDir = support.appendingPathComponent("OSVault")
119 + }
120 + }
121 +
122 + // MARK: - Setup (watch-only, from the vault mnemonic)
123 +
124 + /// Derives BIP-84 descriptors from the mnemonic, keeps only the public
125 + /// side, and opens (or creates) the persisted watch-only wallet.
126 + public func configure(mnemonic: String) throws {
127 + let stored = UserDefaults.standard.string(forKey: Self.networkKey)
128 + network = stored.flatMap(BTCNetwork.init(rawValue:)) ?? .signet
129 +
130 + let (external, internalD) = try Self.publicDescriptors(mnemonic: mnemonic, network: network)
131 + try FileManager.default.createDirectory(at: dataDir, withIntermediateDirectories: true)
132 + let dbPath = dataDir.appendingPathComponent("bdk-\(network.rawValue).sqlite").path
133 +
134 + let store = try Persister.newSqlite(path: dbPath)
135 + if let loaded = try? Wallet.load(descriptor: external, changeDescriptor: internalD, persister: store) {
136 + wallet = loaded
137 + } else {
138 + wallet = try Wallet(descriptor: external, changeDescriptor: internalD,
139 + network: network.bdkNetwork, persister: store)
140 + }
141 + persister = store
142 + hasFullScanned = UserDefaults.standard.bool(forKey: scanFlagKey)
143 + }
144 +
145 + private var scanFlagKey: String { "osvault.bitcoin.scanned.\(network.rawValue)" }
146 +
147 + static func secretDescriptors(mnemonic: String, network: BTCNetwork) throws -> (Descriptor, Descriptor) {
148 + let parsed = try Mnemonic.fromString(mnemonic: mnemonic)
149 + let kind: NetworkKind = network == .mainnet ? .main : .test
150 + let key = DescriptorSecretKey(networkKind: kind, mnemonic: parsed, password: nil)
151 + let external = Descriptor.newBip84(secretKey: key, keychainKind: .external, networkKind: kind)
152 + let internalD = Descriptor.newBip84(secretKey: key, keychainKind: .internal, networkKind: kind)
153 + return (external, internalD)
154 + }
155 +
156 + static func publicDescriptors(mnemonic: String, network: BTCNetwork) throws -> (Descriptor, Descriptor) {
157 + let (extSecret, intSecret) = try secretDescriptors(mnemonic: mnemonic, network: network)
158 + // description renders the PUBLIC form of the descriptor.
159 + let kind: NetworkKind = network == .mainnet ? .main : .test
160 + let external = try Descriptor(descriptor: extSecret.description, networkKind: kind)
161 + let internalD = try Descriptor(descriptor: intSecret.description, networkKind: kind)
162 + return (external, internalD)
163 + }
164 +
165 + public var isConfigured: Bool { wallet != nil }
166 + public var currentNetwork: BTCNetwork { network }
167 +
168 + /// Called when the user flips mainnet/signet in Settings.
169 + public func switchNetwork(to newNetwork: BTCNetwork, mnemonic: String) throws {
170 + UserDefaults.standard.set(newNetwork.rawValue, forKey: Self.networkKey)
171 + wallet = nil
172 + persister = nil
173 + try configure(mnemonic: mnemonic)
174 + }
175 +
176 + // MARK: - Sync / balance / receive
177 +
178 + /// First call does a full descriptor scan (slow, once); later calls only
179 + /// check revealed scripts (fast).
180 + public func sync() throws {
181 + guard let wallet, let persister else { throw WalletError.internalError("Bitcoin wallet not configured.") }
182 + let client = EsploraClient(url: network.esploraURL)
183 + let update: Update
184 + if !hasFullScanned {
185 + let request = try wallet.startFullScan().build()
186 + update = try client.fullScan(request: request, stopGap: 20, parallelRequests: 4)
187 + hasFullScanned = true
188 + UserDefaults.standard.set(true, forKey: scanFlagKey)
189 + } else {
190 + let request = try wallet.startSyncWithRevealedSpks().build()
191 + update = try client.sync(request: request, parallelRequests: 4)
192 + }
193 + try wallet.applyUpdate(update: update)
194 + _ = try wallet.persist(persister: persister)
195 + }
196 +
197 + public func balance() -> BTCBalance {
198 + guard let wallet else { return BTCBalance() }
199 + let b = wallet.balance()
200 + return BTCBalance(
201 + confirmedSats: b.confirmed.toSat(),
202 + pendingSats: b.trustedPending.toSat() + b.untrustedPending.toSat()
203 + )
204 + }
205 +
206 + /// Fresh address per call (privacy); the revealed index is persisted.
207 + public func receiveAddress() throws -> String {
208 + guard let wallet, let persister else { throw WalletError.internalError("Bitcoin wallet not configured.") }
209 + let info = wallet.revealNextAddress(keychain: .external)
210 + _ = try wallet.persist(persister: persister)
211 + return info.address.description
212 + }
213 +
214 + public static func validate(address: String, network: BTCNetwork) -> Bool {
215 + (try? Address(address: address, network: network.bdkNetwork)) != nil
216 + }
217 +
218 + // MARK: - Fees
219 +
220 + public func recommendedFees() async -> FeeRates {
221 + var request = URLRequest(url: URL(string: network.feeAPI)!)
222 + request.timeoutInterval = 10
223 + if let (data, _) = try? await URLSession.shared.data(for: request),
224 + let json = try? JSONSerialization.jsonObject(with: data) as? [String: Double] {
225 + return FeeRates(
226 + fastest: UInt64(json["fastestFee"] ?? 2),
227 + halfHour: UInt64(json["halfHourFee"] ?? 2),
228 + hour: UInt64(json["hourFee"] ?? 1),
229 + economy: UInt64(json["economyFee"] ?? 1)
230 + )
231 + }
232 + return FeeRates(fastest: 3, halfHour: 2, hour: 2, economy: 1)
233 + }
234 +
235 + // MARK: - Send
236 +
237 + /// Builds the PSBT on the watch-only wallet (coin selection, change, RBF)
238 + /// and reports the exact fee. The PSBT is held until sign-and-broadcast.
239 + public func prepareSend(to recipient: String, amountSats: UInt64,
240 + feeRateSatVb: UInt64, drainAll: Bool = false) throws -> PreparedBTCSend {
241 + guard let wallet else { throw WalletError.internalError("Bitcoin wallet not configured.") }
242 + guard let address = try? Address(address: recipient, network: network.bdkNetwork) else {
243 + throw WalletError.invalidAddress
244 + }
245 + let rate = try FeeRate.fromSatPerVb(satVb: feeRateSatVb)
246 + var builder = TxBuilder().feeRate(feeRate: rate)
247 + if drainAll {
248 + builder = builder.drainWallet().drainTo(script: address.scriptPubkey())
249 + } else {
250 + builder = builder.addRecipient(script: address.scriptPubkey(),
251 + amount: Amount.fromSat(satoshi: amountSats))
252 + }
253 + let psbt: Psbt
254 + do {
255 + psbt = try builder.finish(wallet: wallet)
256 + } catch {
257 + throw WalletError.internalError("Could not build the transaction: \(error.localizedDescription)")
258 + }
259 + pendingPsbt = psbt
260 + let fee = (try? psbt.fee()) ?? 0
261 + return PreparedBTCSend(
262 + recipient: recipient, amountSats: amountSats,
263 + feeSats: fee, feeRateSatVb: feeRateSatVb, network: network
264 + )
265 + }
266 +
267 + /// Signs the held PSBT with a throwaway in-memory signer wallet derived
268 + /// from the mnemonic, broadcasts, then discards everything secret.
269 + public func signAndBroadcast(mnemonic: String) throws -> String {
270 + guard let wallet, let persister, let psbt = pendingPsbt else {
271 + throw WalletError.internalError("Nothing to send.")
272 + }
273 + let (extSecret, intSecret) = try Self.secretDescriptors(mnemonic: mnemonic, network: network)
274 + let signer = try Wallet(descriptor: extSecret, changeDescriptor: intSecret,
275 + network: network.bdkNetwork, persister: Persister.newInMemory())
276 + let signed = try signer.sign(psbt: psbt)
277 + guard signed else { throw WalletError.signingFailed }
278 +
279 + let tx = try psbt.extractTx()
280 + let client = EsploraClient(url: network.esploraURL)
281 + do {
282 + try client.broadcast(transaction: tx)
283 + } catch {
284 + if let fallback = network.fallbackEsploraURL {
285 + try EsploraClient(url: fallback).broadcast(transaction: tx)
286 + } else {
287 + throw WalletError.rpc(error.localizedDescription)
288 + }
289 + }
290 + pendingPsbt = nil
291 + // Register our own tx immediately so the balance reflects the spend.
292 + _ = try? wallet.persist(persister: persister)
293 + return tx.computeTxid().description
294 + }
295 +
296 + public func cancelPending() {
297 + pendingPsbt = nil
298 + }
299 +
300 + // MARK: - Formatting
301 +
302 + public static func formatBTC(_ sats: UInt64) -> String {
303 + TokenAmount.format(BigUInt(sats), decimals: 8)
304 + }
305 +
306 + public static func parseBTC(_ input: String) -> UInt64? {
307 + guard let units = TokenAmount.parse(input, decimals: 8), units <= BigUInt(UInt64.max) else { return nil }
308 + return UInt64(units)
309 + }
310 +}
added Sources/OSVaultKit/Services/KeyManager.swift +136 −0
@@ -0,0 +1,136 @@
1 +//
2 +// KeyManager.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import Web3Core
11 +import BigInt
12 +
13 +/// Wallet lifecycle: BIP-39 mnemonic generation/import, HD derivation at
14 +/// m/44'/60'/0'/0/0, and persistence through the encrypted vault file
15 +/// (VaultCrypto — no Keychain, no iCloud, never leaves this Mac).
16 +///
17 +/// The private key is derived on demand (unlock / send / export) and returned
18 +/// to the caller; KeyManager itself never retains key material.
19 +public final class KeyManager {
20 +
21 + public static let derivationPath = "m/44'/60'/0'/0/0"
22 +
23 + public struct UnlockedWallet {
24 + public let address: String // EIP-55 checksummed
25 + public let privateKey: Data
26 + public let mnemonic: String
27 + }
28 +
29 + /// What the vault ciphertext protects.
30 + struct VaultPayload: Codable {
31 + let mnemonic: String
32 + let derivationPath: String
33 + }
34 +
35 + public let vaultURL: URL
36 +
37 + public init(vaultURL: URL? = nil) {
38 + if let vaultURL {
39 + self.vaultURL = vaultURL
40 + } else {
41 + let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
42 + self.vaultURL = support.appendingPathComponent("OSVault/vault.json")
43 + }
44 + }
45 +
46 + public var hasVault: Bool {
47 + FileManager.default.fileExists(atPath: vaultURL.path)
48 + }
49 +
50 + // MARK: - Create / import
51 +
52 + public func generateMnemonic() throws -> String {
53 + guard let mnemonic = try? BIP39.generateMnemonics(bitsOfEntropy: 128, language: .english),
54 + !mnemonic.isEmpty else {
55 + throw WalletError.internalError("Mnemonic generation failed.")
56 + }
57 + return mnemonic
58 + }
59 +
60 + public static func validate(mnemonic: String) -> Bool {
61 + let words = normalize(mnemonic: mnemonic).split(separator: " ")
62 + guard words.count == 12 || words.count == 24 else { return false }
63 + return BIP39.mnemonicsToEntropy(normalize(mnemonic: mnemonic), language: .english) != nil
64 + }
65 +
66 + /// Persists the mnemonic into a fresh encrypted vault. Same path for
67 + /// "create" (with a just-generated mnemonic) and "import".
68 + @discardableResult
69 + public func saveWallet(mnemonic: String, password: String) throws -> UnlockedWallet {
70 + let wallet = try Self.derive(mnemonic: mnemonic)
71 + let payload = VaultPayload(mnemonic: wallet.mnemonic, derivationPath: Self.derivationPath)
72 + let secret = try JSONEncoder().encode(payload)
73 + let vault = try VaultCrypto.seal(secret: secret, password: password)
74 +
75 + let dir = vaultURL.deletingLastPathComponent()
76 + try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
77 + let encoder = JSONEncoder()
78 + encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
79 + let data = try encoder.encode(vault)
80 + try data.write(to: vaultURL, options: [.atomic])
81 + try FileManager.default.setAttributes([.posixPermissions: 0o600], ofItemAtPath: vaultURL.path)
82 + return wallet
83 + }
84 +
85 + // MARK: - Unlock / export / delete
86 +
87 + public func unlock(password: String) throws -> UnlockedWallet {
88 + guard hasVault else { throw WalletError.noVault }
89 + let data: Data
90 + do { data = try Data(contentsOf: vaultURL) } catch { throw WalletError.vaultCorrupted }
91 + guard let vault = try? JSONDecoder().decode(VaultCrypto.VaultFile.self, from: data) else {
92 + throw WalletError.vaultCorrupted
93 + }
94 + let secret = try VaultCrypto.open(vault, password: password)
95 + guard let payload = try? JSONDecoder().decode(VaultPayload.self, from: secret) else {
96 + throw WalletError.vaultCorrupted
97 + }
98 + return try Self.derive(mnemonic: payload.mnemonic)
99 + }
100 +
101 + public func exportMnemonic(password: String) throws -> String {
102 + try unlock(password: password).mnemonic
103 + }
104 +
105 + public func deleteVault() throws {
106 + guard hasVault else { return }
107 + try FileManager.default.removeItem(at: vaultURL)
108 + }
109 +
110 + // MARK: - Derivation
111 +
112 + public static func derive(mnemonic: String) throws -> UnlockedWallet {
113 + let normalized = normalize(mnemonic: mnemonic)
114 + guard validate(mnemonic: normalized),
115 + let seed = BIP39.seedFromMmemonics(normalized, password: "", language: .english),
116 + let root = HDNode(seed: seed),
117 + let node = root.derive(path: derivationPath, derivePrivateKey: true),
118 + let privateKey = node.privateKey,
119 + let publicKey = Utilities.privateToPublic(privateKey, compressed: false),
120 + let address = Utilities.publicToAddress(publicKey) else {
121 + throw WalletError.invalidMnemonic
122 + }
123 + guard let checksummed = EthereumAddress.toChecksumAddress(address.address) else {
124 + throw WalletError.internalError("Address derivation failed.")
125 + }
126 + return UnlockedWallet(address: checksummed, privateKey: privateKey, mnemonic: normalized)
127 + }
128 +
129 + static func normalize(mnemonic: String) -> String {
130 + mnemonic
131 + .lowercased()
132 + .components(separatedBy: .whitespacesAndNewlines)
133 + .filter { !$0.isEmpty }
134 + .joined(separator: " ")
135 + }
136 +}
added Sources/OSVaultKit/Services/PriceService.swift +129 −0
@@ -0,0 +1,129 @@
1 +//
2 +// PriceService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +
12 +/// Fiat valuation, keyless and optional. One batched CoinGecko call covers
13 +/// every asset in USD/CAD/EUR (research: keyless budget 5–15 calls/min; we
14 +/// use ~1 per 2 min). Serve-stale-while-revalidate: the UI renders from the
15 +/// on-disk cache immediately and never blocks on the network. Prices are a
16 +/// display-layer estimate only — balances remain exact base units.
17 +public actor PriceService {
18 +
19 + public static let fiatOptions = ["USD", "CAD", "EUR"]
20 + public static let enabledKey = "osvault.prices.enabled"
21 + public static let fiatKey = "osvault.prices.fiat"
22 +
23 + /// Symbol → CoinGecko id. Bridged variants share the canonical id.
24 + static let coingeckoIDs: [String: String] = [
25 + "ETH": "ethereum",
26 + "POL": "polygon-ecosystem-token",
27 + "BNB": "binancecoin",
28 + "AVAX": "avalanche-2",
29 + "xDAI": "xdai",
30 + "BTC": "bitcoin",
31 + "SOL": "solana",
32 + "TRX": "tron",
33 + "XRP": "ripple",
34 + "TON": "the-open-network",
35 + "USDC": "usd-coin",
36 + "USDC.e": "usd-coin",
37 + "USDT": "tether",
38 + "DAI": "dai",
39 + "USDS": "usds",
40 + "EURC": "euro-coin"
41 + ]
42 +
43 + struct Cache: Codable {
44 + var fetchedAt: Date
45 + /// id → fiat code (lowercased) → price
46 + var prices: [String: [String: Double]]
47 + }
48 +
49 + private let cacheURL: URL
50 + private var cache: Cache?
51 + private let session: URLSession
52 + private let ttl: TimeInterval = 120
53 +
54 + public init(cacheURL: URL? = nil, session: URLSession = .shared) {
55 + if let cacheURL {
56 + self.cacheURL = cacheURL
57 + } else {
58 + let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
59 + self.cacheURL = support.appendingPathComponent("OSVault/prices.json")
60 + }
61 + self.session = session
62 + if let data = try? Data(contentsOf: self.cacheURL),
63 + let stored = try? JSONDecoder().decode(Cache.self, from: data) {
64 + self.cache = stored
65 + }
66 + }
67 +
68 + /// Latest known price per symbol in `fiat`, refreshing in the background
69 + /// when stale. Returns cached (possibly stale) values on network failure.
70 + public func prices(for symbols: [String], fiat: String) async -> [String: Decimal] {
71 + let ids = Set(symbols.compactMap { Self.coingeckoIDs[$0] })
72 + guard !ids.isEmpty else { return [:] }
73 +
74 + if cache == nil || Date().timeIntervalSince(cache!.fetchedAt) > ttl {
75 + await refresh(ids: Set(Self.coingeckoIDs.values))
76 + }
77 + guard let cache else { return [:] }
78 +
79 + var result: [String: Decimal] = [:]
80 + for symbol in symbols {
81 + if let id = Self.coingeckoIDs[symbol],
82 + let value = cache.prices[id]?[fiat.lowercased()] {
83 + result[symbol] = Decimal(value)
84 + }
85 + }
86 + return result
87 + }
88 +
89 + public var lastUpdated: Date? { cache?.fetchedAt }
90 +
91 + private func refresh(ids: Set<String>) async {
92 + var components = URLComponents(string: "https://api.coingecko.com/api/v3/simple/price")!
93 + components.queryItems = [
94 + URLQueryItem(name: "ids", value: ids.sorted().joined(separator: ",")),
95 + URLQueryItem(name: "vs_currencies", value: "usd,cad,eur")
96 + ]
97 + var request = URLRequest(url: components.url!)
98 + request.timeoutInterval = 15
99 + do {
100 + let (data, response) = try await session.data(for: request)
101 + guard let http = response as? HTTPURLResponse, http.statusCode == 200,
102 + let json = try JSONSerialization.jsonObject(with: data) as? [String: [String: Double]] else {
103 + return // keep stale cache
104 + }
105 + let fresh = Cache(fetchedAt: Date(), prices: json)
106 + cache = fresh
107 + let dir = cacheURL.deletingLastPathComponent()
108 + try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
109 + if let encoded = try? JSONEncoder().encode(fresh) {
110 + try? encoded.write(to: cacheURL, options: [.atomic])
111 + }
112 + } catch {
113 + // Offline or rate-limited: stale cache keeps serving.
114 + }
115 + }
116 +
117 + /// amount (base units) × price → fiat, for display only.
118 + public static func fiatValue(units: BigUInt, decimals: Int, price: Decimal) -> Decimal {
119 + (Decimal(string: String(units)) ?? 0) / pow(Decimal(10), decimals) * price
120 + }
121 +
122 + public static func formatFiat(_ value: Decimal, currency: String) -> String {
123 + let formatter = NumberFormatter()
124 + formatter.numberStyle = .currency
125 + formatter.currencyCode = currency
126 + formatter.maximumFractionDigits = 2
127 + return formatter.string(from: value as NSDecimalNumber) ?? "\(value) \(currency)"
128 + }
129 +}
added Sources/OSVaultKit/Services/RPCService.swift +186 −0
@@ -0,0 +1,186 @@
1 +//
2 +// RPCService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +
12 +/// Minimal JSON-RPC client over URLSession with endpoint failover: the
13 +/// network's keyless endpoints are tried in order (user override first), a
14 +/// failing endpoint is demoted for a cooldown, and node-side errors (reverts,
15 +/// underpriced…) are surfaced immediately — only transport problems rotate.
16 +/// Every method returns typed `WalletError`s; the app must never crash on RPC
17 +/// trouble.
18 +public actor RPCService {
19 +
20 + public let urls: [URL]
21 + private let session: URLSession
22 + private var nextID = 1
23 + /// Index of the endpoint that most recently worked (sticky primary).
24 + private var preferred = 0
25 + private var demotedUntil: [Int: Date] = [:]
26 +
27 + public init(urls: [URL], session: URLSession = .shared) {
28 + precondition(!urls.isEmpty)
29 + self.urls = urls
30 + self.session = session
31 + }
32 +
33 + public init(url: URL, session: URLSession = .shared) {
34 + self.init(urls: [url], session: session)
35 + }
36 +
37 + // MARK: - Core request with failover
38 +
39 + private func orderedEndpoints() -> [Int] {
40 + let now = Date()
41 + let healthy = urls.indices.filter { (demotedUntil[$0] ?? .distantPast) < now }
42 + let demoted = urls.indices.filter { !healthy.contains($0) }
43 + let sorted = healthy.sorted { a, b in
44 + (a == preferred ? 0 : 1, a) < (b == preferred ? 0 : 1, b)
45 + }
46 + return sorted + demoted // demoted endpoints remain the last resort
47 + }
48 +
49 + private func request(method: String, params: [Any]) async throws -> Any {
50 + let id = nextID
51 + nextID += 1
52 + let body: [String: Any] = ["jsonrpc": "2.0", "id": id, "method": method, "params": params]
53 + let payload = try JSONSerialization.data(withJSONObject: body)
54 +
55 + var lastError: Error = WalletError.rpc("Unreachable RPC endpoint.")
56 + for index in orderedEndpoints() {
57 + var req = URLRequest(url: urls[index])
58 + req.httpMethod = "POST"
59 + req.setValue("application/json", forHTTPHeaderField: "Content-Type")
60 + req.httpBody = payload
61 + req.timeoutInterval = 15
62 +
63 + for attempt in 0..<2 {
64 + if attempt > 0 {
65 + try? await Task.sleep(nanoseconds: 500_000_000)
66 + }
67 + do {
68 + let (data, response) = try await session.data(for: req)
69 + if let http = response as? HTTPURLResponse, !(200...299).contains(http.statusCode) {
70 + lastError = WalletError.rpc("HTTP \(http.statusCode) from RPC endpoint.")
71 + continue
72 + }
73 + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
74 + lastError = WalletError.rpc("Malformed RPC response.")
75 + continue
76 + }
77 + if let errorDict = json["error"] as? [String: Any] {
78 + let message = (errorDict["message"] as? String) ?? "RPC error"
79 + let code = errorDict["code"] as? Int ?? 0
80 + // Rate-limit style errors → try the next endpoint;
81 + // genuine node-side errors (revert, nonce, funds) are
82 + // not transient and must surface immediately.
83 + if code == -32005 || code == -32001 || message.lowercased().contains("rate") {
84 + lastError = WalletError.rpc(message)
85 + break
86 + }
87 + throw WalletError.rpc(message)
88 + }
89 + guard let result = json["result"] else {
90 + lastError = WalletError.rpc("RPC response missing result.")
91 + continue
92 + }
93 + preferred = index
94 + return result
95 + } catch let error as WalletError {
96 + throw error
97 + } catch {
98 + lastError = WalletError.rpc(error.localizedDescription)
99 + }
100 + }
101 + demotedUntil[index] = Date().addingTimeInterval(60)
102 + }
103 + throw lastError
104 + }
105 +
106 + private func quantity(method: String, params: [Any]) async throws -> BigUInt {
107 + guard let hex = try await request(method: method, params: params) as? String,
108 + let value = Hex.toBigUInt(hex) else {
109 + throw WalletError.rpc("Unexpected result for \(method).")
110 + }
111 + return value
112 + }
113 +
114 + // MARK: - Ethereum methods
115 +
116 + public func chainID() async throws -> BigUInt {
117 + try await quantity(method: "eth_chainId", params: [])
118 + }
119 +
120 + public func balance(of address: String) async throws -> BigUInt {
121 + try await quantity(method: "eth_getBalance", params: [address, "latest"])
122 + }
123 +
124 + public func call(to contract: String, data: Data) async throws -> String {
125 + guard let result = try await request(
126 + method: "eth_call",
127 + params: [["to": contract, "data": Hex.string(data)], "latest"]
128 + ) as? String else {
129 + throw WalletError.rpc("Unexpected result for eth_call.")
130 + }
131 + return result
132 + }
133 +
134 + public func transactionCount(of address: String) async throws -> BigUInt {
135 + try await quantity(method: "eth_getTransactionCount", params: [address, "pending"])
136 + }
137 +
138 + public func estimateGas(from: String, to destination: String, valueWei: BigUInt, data: Data) async throws -> BigUInt {
139 + var tx: [String: Any] = ["from": from, "to": destination]
140 + if valueWei > 0 { tx["value"] = Hex.quantity(valueWei) }
141 + if !data.isEmpty { tx["data"] = Hex.string(data) }
142 + return try await quantity(method: "eth_estimateGas", params: [tx])
143 + }
144 +
145 + public func gasPrice() async throws -> BigUInt {
146 + try await quantity(method: "eth_gasPrice", params: [])
147 + }
148 +
149 + public func maxPriorityFeePerGas() async throws -> BigUInt {
150 + try await quantity(method: "eth_maxPriorityFeePerGas", params: [])
151 + }
152 +
153 + public func latestBaseFee() async throws -> BigUInt {
154 + guard let block = try await request(method: "eth_getBlockByNumber", params: ["latest", false]) as? [String: Any],
155 + let hex = block["baseFeePerGas"] as? String,
156 + let fee = Hex.toBigUInt(hex) else {
157 + throw WalletError.rpc("Latest block has no base fee.")
158 + }
159 + return fee
160 + }
161 +
162 + public func sendRawTransaction(_ rawHex: String) async throws -> String {
163 + guard let hash = try await request(method: "eth_sendRawTransaction", params: [rawHex]) as? String else {
164 + throw WalletError.rpc("Broadcast returned no transaction hash.")
165 + }
166 + return hash
167 + }
168 +
169 + public struct Receipt {
170 + public let succeeded: Bool
171 + public let blockNumber: BigUInt?
172 + }
173 +
174 + /// nil while the transaction is still pending.
175 + public func transactionReceipt(_ hash: String) async throws -> Receipt? {
176 + let result = try await request(method: "eth_getTransactionReceipt", params: [hash])
177 + if result is NSNull { return nil }
178 + guard let dict = result as? [String: Any], let statusHex = dict["status"] as? String else {
179 + return nil
180 + }
181 + return Receipt(
182 + succeeded: Hex.toBigUInt(statusHex) == 1,
183 + blockNumber: (dict["blockNumber"] as? String).flatMap(Hex.toBigUInt)
184 + )
185 + }
186 +}
added Sources/OSVaultKit/Services/SolanaService.swift +263 −0
@@ -0,0 +1,263 @@
1 +//
2 +// SolanaService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import SolanaSwift
11 +
12 +/// Solana support via solana-swift (macOS-native, maintained — see
13 +/// docs/RESEARCH-MULTICHAIN.md): SOL + USDC (SPL) from the same vault
14 +/// mnemonic, ed25519 at m/44'/501'/0'/0' (Phantom-compatible bip44Change).
15 +///
16 +/// Security model matches the rest of the app: only the public address stays
17 +/// in memory; sends re-derive the keypair from the vault password, sign, and
18 +/// discard. RPC is keyless (PublicNode mainnet / official devnet). Default
19 +/// network is devnet (testnet-first rule).
20 +public actor SolanaService {
21 +
22 + public enum SOLNetwork: String, CaseIterable, Codable, Sendable {
23 + case mainnet
24 + case devnet
25 +
26 + var solanaNetwork: SolanaSwift.Network {
27 + switch self {
28 + case .mainnet: return .mainnetBeta
29 + case .devnet: return .devnet
30 + }
31 + }
32 +
33 + public var rpcURL: String {
34 + switch self {
35 + // PublicNode: keyless, MEV-protected; official endpoint fallback.
36 + case .mainnet: return "https://solana-rpc.publicnode.com"
37 + case .devnet: return "https://api.devnet.solana.com"
38 + }
39 + }
40 +
41 + var fallbackRPCURL: String? {
42 + switch self {
43 + case .mainnet: return "https://api.mainnet-beta.solana.com"
44 + case .devnet: return nil
45 + }
46 + }
47 +
48 + /// Circle-issued USDC mint (devnet mint is the Circle faucet's).
49 + public var usdcMint: String {
50 + switch self {
51 + case .mainnet: return "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
52 + case .devnet: return "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
53 + }
54 + }
55 +
56 + public func explorerTxURL(_ signature: String) -> URL {
57 + switch self {
58 + case .mainnet: return URL(string: "https://explorer.solana.com/tx/\(signature)")!
59 + case .devnet: return URL(string: "https://explorer.solana.com/tx/\(signature)?cluster=devnet")!
60 + }
61 + }
62 +
63 + public func explorerAddressURL(_ address: String) -> URL {
64 + switch self {
65 + case .mainnet: return URL(string: "https://explorer.solana.com/address/\(address)")!
66 + case .devnet: return URL(string: "https://explorer.solana.com/address/\(address)?cluster=devnet")!
67 + }
68 + }
69 +
70 + public var displayName: String {
71 + switch self {
72 + case .mainnet: return "Solana"
73 + case .devnet: return "Solana Devnet"
74 + }
75 + }
76 +
77 + public var isTestnet: Bool { self == .devnet }
78 + }
79 +
80 + public static let networkKey = "osvault.solana.network"
81 + public static let usdcDecimals = 6
82 + static let derivablePath = DerivablePath(type: .bip44Change, walletIndex: 0, accountIndex: 0)
83 +
84 + public struct SOLBalances: Sendable {
85 + public var lamports: UInt64 = 0 // SOL, 9 decimals
86 + public var usdcUnits: UInt64 = 0 // USDC, 6 decimals
87 + }
88 +
89 + public struct PreparedSOLSend: Sendable {
90 + public let recipient: String
91 + public let amountUnits: UInt64
92 + public let isUSDC: Bool
93 + /// Signature fee + ATA rent if the recipient needs a token account.
94 + public let estimatedFeeLamports: UInt64
95 + public let createsTokenAccount: Bool
96 + public let network: SOLNetwork
97 + }
98 +
99 + private var address: String?
100 + private var network: SOLNetwork = .devnet
101 +
102 + // MARK: - Setup
103 +
104 + public func configure(mnemonic: String) async throws {
105 + let stored = UserDefaults.standard.string(forKey: Self.networkKey)
106 + network = stored.flatMap(SOLNetwork.init(rawValue:)) ?? .devnet
107 + let keyPair = try await Self.deriveKeyPair(mnemonic: mnemonic, network: network)
108 + address = keyPair.publicKey.base58EncodedString
109 + }
110 +
111 + static func deriveKeyPair(mnemonic: String, network: SOLNetwork) async throws -> KeyPair {
112 + try await KeyPair(
113 + phrase: mnemonic.split(separator: " ").map(String.init),
114 + network: network.solanaNetwork,
115 + derivablePath: derivablePath
116 + )
117 + }
118 +
119 + public var isConfigured: Bool { address != nil }
120 + public var currentNetwork: SOLNetwork { network }
121 + public var publicAddress: String? { address }
122 +
123 + /// The address is derivation-only, so switching clusters needs no password.
124 + public func switchNetwork(to newNetwork: SOLNetwork) {
125 + UserDefaults.standard.set(newNetwork.rawValue, forKey: Self.networkKey)
126 + network = newNetwork
127 + }
128 +
129 + public static func validate(address: String) -> Bool {
130 + // solana-swift's PublicKey(string:) is lax; enforce strict base58
131 + // alphabet and an exact 32-byte decode.
132 + guard address.count >= 32, address.count <= 44,
133 + address.allSatisfy({ "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".contains($0) }),
134 + Base58.decode(address).count == 32 else {
135 + return false
136 + }
137 + return true
138 + }
139 +
140 + // MARK: - RPC
141 +
142 + private func apiClient() -> JSONRPCAPIClient {
143 + JSONRPCAPIClient(endpoint: APIEndPoint(address: network.rpcURL, network: network.solanaNetwork))
144 + }
145 +
146 + private func fallbackClient() -> JSONRPCAPIClient? {
147 + network.fallbackRPCURL.map {
148 + JSONRPCAPIClient(endpoint: APIEndPoint(address: $0, network: network.solanaNetwork))
149 + }
150 + }
151 +
152 + private func usdcATA() throws -> PublicKey {
153 + guard let address else { throw WalletError.internalError("Solana not configured.") }
154 + return try PublicKey.associatedTokenAddress(
155 + walletAddress: PublicKey(string: address),
156 + tokenMintAddress: PublicKey(string: network.usdcMint),
157 + tokenProgramId: TokenProgram.id
158 + )
159 + }
160 +
161 + // MARK: - Balances
162 +
163 + public func fetchBalances() async throws -> SOLBalances {
164 + guard let address else { throw WalletError.internalError("Solana not configured.") }
165 + let client = apiClient()
166 + var balances = SOLBalances()
167 + do {
168 + balances.lamports = try await client.getBalance(account: address, commitment: "confirmed")
169 + } catch {
170 + guard let fallback = fallbackClient() else { throw WalletError.rpc(error.localizedDescription) }
171 + balances.lamports = try await fallback.getBalance(account: address, commitment: "confirmed")
172 + }
173 + if let ata = try? usdcATA(),
174 + let tokenBalance = try? await client.getTokenAccountBalance(
175 + pubkey: ata.base58EncodedString, commitment: "confirmed"),
176 + let units = UInt64(tokenBalance.amount) {
177 + balances.usdcUnits = units
178 + }
179 + return balances
180 + }
181 +
182 + // MARK: - Send
183 +
184 + /// Fee estimate without touching key material: signature fee + ATA rent
185 + /// when sending USDC to a wallet that has no token account yet (the
186 + /// sender funds ~0.002 SOL of rent — a Solana-specific gotcha).
187 + public func estimateSend(to recipient: String, amountUnits: UInt64, isUSDC: Bool) async throws -> PreparedSOLSend {
188 + guard Self.validate(address: recipient) else { throw WalletError.invalidAddress }
189 + let client = apiClient()
190 + let lamportsPerSignature: UInt64 = 5_000
191 + var createsATA = false
192 + var fee = lamportsPerSignature
193 + if isUSDC {
194 + let recipientATA = try PublicKey.associatedTokenAddress(
195 + walletAddress: PublicKey(string: recipient),
196 + tokenMintAddress: PublicKey(string: network.usdcMint),
197 + tokenProgramId: TokenProgram.id
198 + )
199 + let info: BufferInfo<TokenAccountState>? = try? await client.getAccountInfo(
200 + account: recipientATA.base58EncodedString)
201 + if info == nil {
202 + createsATA = true
203 + let rent = (try? await client.getMinimumBalanceForRentExemption(
204 + dataLength: 165, commitment: "confirmed")) ?? 2_039_280
205 + fee += rent
206 + }
207 + }
208 + return PreparedSOLSend(
209 + recipient: recipient, amountUnits: amountUnits, isUSDC: isUSDC,
210 + estimatedFeeLamports: fee, createsTokenAccount: createsATA, network: network
211 + )
212 + }
213 +
214 + /// Derives the keypair from the mnemonic, builds + signs + broadcasts,
215 + /// returns the transaction signature. Key material is never retained.
216 + public func send(_ prepared: PreparedSOLSend, mnemonic: String) async throws -> String {
217 + let account = try await Self.deriveKeyPair(mnemonic: mnemonic, network: network)
218 + let client = apiClient()
219 + let blockchain = BlockchainClient(apiClient: client)
220 +
221 + if prepared.isUSDC {
222 + let sourceATA = try usdcATA()
223 + let lamportsPerSignature: UInt64 = 5_000
224 + let minRent = (try? await client.getMinimumBalanceForRentExemption(
225 + dataLength: 165, commitment: "confirmed")) ?? 2_039_280
226 + let (tx, _) = try await blockchain.prepareSendingSPLTokens(
227 + account: account,
228 + mintAddress: network.usdcMint,
229 + tokenProgramId: TokenProgram.id,
230 + decimals: UInt8(Self.usdcDecimals),
231 + from: sourceATA.base58EncodedString,
232 + to: prepared.recipient,
233 + amount: prepared.amountUnits,
234 + lamportsPerSignature: lamportsPerSignature,
235 + minRentExemption: minRent
236 + )
237 + return try await blockchain.sendTransaction(preparedTransaction: tx)
238 + } else {
239 + let tx = try await blockchain.prepareSendingNativeSOL(
240 + from: account,
241 + to: prepared.recipient,
242 + amount: prepared.amountUnits
243 + )
244 + return try await blockchain.sendTransaction(preparedTransaction: tx)
245 + }
246 + }
247 +
248 + // MARK: - Formatting
249 +
250 + public static func formatSOL(_ lamports: UInt64) -> String {
251 + TokenAmount.format(.init(lamports), decimals: 9, maxFractionDigits: 6)
252 + }
253 +
254 + public static func parseSOL(_ input: String) -> UInt64? {
255 + guard let units = TokenAmount.parse(input, decimals: 9), units <= .init(UInt64.max) else { return nil }
256 + return UInt64(units)
257 + }
258 +
259 + public static func parseUSDC(_ input: String) -> UInt64? {
260 + guard let units = TokenAmount.parse(input, decimals: usdcDecimals), units <= .init(UInt64.max) else { return nil }
261 + return UInt64(units)
262 + }
263 +}
added Sources/OSVaultKit/Services/TONService.swift +297 −0
@@ -0,0 +1,297 @@
1 +//
2 +// TONService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +import WalletCore
12 +
13 +/// TON support: native TON + USDT (jetton, TEP-74). Signing via wallet-core
14 +/// (`Transfer` / `JettonTransfer`, wallet v4R2 — the address format
15 +/// wallet-core derives). Networking via keyless toncenter (v2 for wallet
16 +/// state and broadcast, v3 for jetton wallets), throttled to its documented
17 +/// 1 req/s anonymous budget.
18 +///
19 +/// TON specifics: jetton balances live in a separate jetton-wallet contract;
20 +/// a jetton transfer is a TON message to YOUR jetton wallet carrying
21 +/// ~0.07 TON for fees (excess refunded). The wallet contract itself deploys
22 +/// with the first outgoing transfer (seqno 0 → wallet-core adds stateInit).
23 +public actor TONService {
24 +
25 + public enum TONNetwork: String, CaseIterable, Codable, Sendable {
26 + case mainnet
27 + case testnet
28 +
29 + public var v2Base: String {
30 + switch self {
31 + case .mainnet: return "https://toncenter.com/api/v2"
32 + case .testnet: return "https://testnet.toncenter.com/api/v2"
33 + }
34 + }
35 +
36 + public var v3Base: String {
37 + switch self {
38 + case .mainnet: return "https://toncenter.com/api/v3"
39 + case .testnet: return "https://testnet.toncenter.com/api/v3"
40 + }
41 + }
42 +
43 + /// Tether-issued USDT jetton master (mainnet only; no official
44 + /// testnet USDT).
45 + public var usdtMaster: String? {
46 + switch self {
47 + case .mainnet: return "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"
48 + case .testnet: return nil
49 + }
50 + }
51 +
52 + public func explorerTxURL(_ hash: String) -> URL {
53 + switch self {
54 + case .mainnet: return URL(string: "https://tonviewer.com/transaction/\(hash)")!
55 + case .testnet: return URL(string: "https://testnet.tonviewer.com/transaction/\(hash)")!
56 + }
57 + }
58 +
59 + public func explorerAddressURL(_ address: String) -> URL {
60 + switch self {
61 + case .mainnet: return URL(string: "https://tonviewer.com/\(address)")!
62 + case .testnet: return URL(string: "https://testnet.tonviewer.com/\(address)")!
63 + }
64 + }
65 +
66 + public var displayName: String {
67 + switch self {
68 + case .mainnet: return "TON"
69 + case .testnet: return "TON Testnet"
70 + }
71 + }
72 +
73 + public var isTestnet: Bool { self == .testnet }
74 + }
75 +
76 + public static let networkKey = "osvault.ton.network"
77 + public static let tonDecimals = 9
78 + public static let usdtDecimals = 6
79 + /// TON attached to a jetton transfer for fees (excess refunded).
80 + static let jettonAttachNanotons: UInt64 = 70_000_000 // 0.07 TON
81 + static let sendMode: UInt32 = 3 // pay fees separately + ignore errors
82 +
83 + public struct TONBalances: Sendable {
84 + public var nanotons: UInt64 = 0
85 + public var usdtUnits: UInt64 = 0
86 + public var deployed = false
87 + }
88 +
89 + public struct PreparedTONSend: Sendable {
90 + public let recipient: String
91 + public let amountUnits: UInt64
92 + public let isUSDT: Bool
93 + public let estimatedFeeNanotons: UInt64
94 + public let network: TONNetwork
95 + }
96 +
97 + private var address: String?
98 + private var network: TONNetwork = .testnet
99 + private var lastRequest = Date.distantPast
100 +
101 + // MARK: - Setup
102 +
103 + public func configure(mnemonic: String) throws {
104 + let stored = UserDefaults.standard.string(forKey: Self.networkKey)
105 + network = stored.flatMap(TONNetwork.init(rawValue:)) ?? .testnet
106 + guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: "") else {
107 + throw WalletError.invalidMnemonic
108 + }
109 + address = wallet.getAddressForCoin(coin: .ton)
110 + }
111 +
112 + public var isConfigured: Bool { address != nil }
113 + public var currentNetwork: TONNetwork { network }
114 + public var publicAddress: String? { address }
115 +
116 + public func switchNetwork(to newNetwork: TONNetwork) {
117 + UserDefaults.standard.set(newNetwork.rawValue, forKey: Self.networkKey)
118 + network = newNetwork
119 + }
120 +
121 + public static func validate(address: String) -> Bool {
122 + AnyAddress.isValid(string: address, coin: .ton)
123 + }
124 +
125 + // MARK: - HTTP (1 req/s budget)
126 +
127 + private func throttle() async {
128 + let elapsed = Date().timeIntervalSince(lastRequest)
129 + if elapsed < 1.1 {
130 + try? await Task.sleep(nanoseconds: UInt64((1.1 - elapsed) * 1_000_000_000))
131 + }
132 + lastRequest = Date()
133 + }
134 +
135 + private func getJSON(_ url: URL) async throws -> [String: Any] {
136 + await throttle()
137 + var request = URLRequest(url: url)
138 + request.timeoutInterval = 20
139 + let (data, _) = try await URLSession.shared.data(for: request)
140 + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
141 + throw WalletError.rpc("Malformed toncenter response.")
142 + }
143 + return json
144 + }
145 +
146 + // MARK: - Balances
147 +
148 + public func fetchBalances() async throws -> TONBalances {
149 + guard let address else { throw WalletError.internalError("TON not configured.") }
150 + var balances = TONBalances()
151 +
152 + var components = URLComponents(string: network.v2Base + "/getWalletInformation")!
153 + components.queryItems = [URLQueryItem(name: "address", value: address)]
154 + let info = try await getJSON(components.url!)
155 + guard info["ok"] as? Bool == true, let result = info["result"] as? [String: Any] else {
156 + throw WalletError.rpc((info["error"] as? String) ?? "toncenter query failed.")
157 + }
158 + balances.nanotons = (result["balance"] as? String).flatMap(UInt64.init)
159 + ?? (result["balance"] as? NSNumber)?.uint64Value ?? 0
160 + balances.deployed = (result["account_state"] as? String) == "active"
161 +
162 + if let master = network.usdtMaster {
163 + var jettonComponents = URLComponents(string: network.v3Base + "/jetton/wallets")!
164 + jettonComponents.queryItems = [
165 + URLQueryItem(name: "owner_address", value: address),
166 + URLQueryItem(name: "jetton_address", value: master),
167 + URLQueryItem(name: "limit", value: "1")
168 + ]
169 + if let json = try? await getJSON(jettonComponents.url!),
170 + let wallets = json["jetton_wallets"] as? [[String: Any]],
171 + let first = wallets.first,
172 + let balance = first["balance"] as? String, let units = UInt64(balance) {
173 + balances.usdtUnits = units
174 + }
175 + }
176 + return balances
177 + }
178 +
179 + /// Raw-format jetton wallet address (0:hex) for this owner, if any.
180 + private func myJettonWallet() async throws -> String? {
181 + guard let address, let master = network.usdtMaster else { return nil }
182 + var components = URLComponents(string: network.v3Base + "/jetton/wallets")!
183 + components.queryItems = [
184 + URLQueryItem(name: "owner_address", value: address),
185 + URLQueryItem(name: "jetton_address", value: master),
186 + URLQueryItem(name: "limit", value: "1")
187 + ]
188 + let json = try await getJSON(components.url!)
189 + guard let wallets = json["jetton_wallets"] as? [[String: Any]],
190 + let raw = wallets.first?["address"] as? String else { return nil }
191 + // Convert raw 0:hex to the user-friendly bounceable form for the tx.
192 + return TONAddressConverter.toUserFriendly(address: raw, bounceable: true, testnet: network.isTestnet)
193 + }
194 +
195 + // MARK: - Estimate
196 +
197 + public func estimateSend(to recipient: String, amountUnits: UInt64, isUSDT: Bool) async throws -> PreparedTONSend {
198 + guard Self.validate(address: recipient) else { throw WalletError.invalidAddress }
199 + if isUSDT {
200 + guard network.usdtMaster != nil else {
201 + throw WalletError.internalError("USDT is not available on TON testnet.")
202 + }
203 + guard try await myJettonWallet() != nil else {
204 + throw WalletError.internalError("No USDT jetton wallet found for this account (balance is 0).")
205 + }
206 + }
207 + // Typical costs: plain transfer ~0.004 TON; jetton carries the
208 + // attached 0.07 TON of which the unused part is refunded.
209 + let fee: UInt64 = isUSDT ? Self.jettonAttachNanotons : 5_000_000
210 + return PreparedTONSend(
211 + recipient: recipient, amountUnits: amountUnits,
212 + isUSDT: isUSDT, estimatedFeeNanotons: fee, network: network
213 + )
214 + }
215 +
216 + // MARK: - Sign + broadcast
217 +
218 + public func send(_ prepared: PreparedTONSend, mnemonic: String) async throws -> String {
219 + guard let address else { throw WalletError.internalError("TON not configured.") }
220 + guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: "") else {
221 + throw WalletError.invalidMnemonic
222 + }
223 +
224 + // seqno (0 for an undeployed wallet → wallet-core adds stateInit).
225 + var components = URLComponents(string: network.v2Base + "/getWalletInformation")!
226 + components.queryItems = [URLQueryItem(name: "address", value: address)]
227 + let info = try await getJSON(components.url!)
228 + let result = info["result"] as? [String: Any] ?? [:]
229 + let seqno = (result["seqno"] as? NSNumber)?.uint32Value ?? 0
230 +
231 + var transfer = TheOpenNetworkTransfer()
232 + transfer.mode = Self.sendMode
233 + if prepared.isUSDT {
234 + guard let jettonWallet = try await myJettonWallet() else {
235 + throw WalletError.internalError("USDT jetton wallet not found.")
236 + }
237 + transfer.dest = jettonWallet
238 + transfer.amount = BigUInt(Self.jettonAttachNanotons).serialize()
239 + transfer.bounceable = true
240 + var jetton = TheOpenNetworkJettonTransfer()
241 + jetton.jettonAmount = BigUInt(prepared.amountUnits).serialize()
242 + jetton.toOwner = prepared.recipient
243 + jetton.responseAddress = address
244 + jetton.forwardAmount = BigUInt(1).serialize()
245 + transfer.payload = .jettonTransfer(jetton)
246 + } else {
247 + transfer.dest = prepared.recipient
248 + transfer.amount = BigUInt(prepared.amountUnits).serialize()
249 + transfer.bounceable = false // wallets use non-bounceable
250 + }
251 +
252 + let key = wallet.getKeyForCoin(coin: .ton)
253 + var input = TheOpenNetworkSigningInput()
254 + input.privateKey = key.data
255 + input.walletVersion = .walletV4R2
256 + input.sequenceNumber = seqno
257 + input.expireAt = UInt32(Date().timeIntervalSince1970) + 300
258 + input.messages = [transfer]
259 +
260 + let output: TheOpenNetworkSigningOutput = AnySigner.sign(input: input, coin: .ton)
261 + guard output.error == .ok, !output.encoded.isEmpty else {
262 + throw WalletError.signingFailed
263 + }
264 +
265 + await throttle()
266 + var request = URLRequest(url: URL(string: network.v2Base + "/sendBoc")!)
267 + request.httpMethod = "POST"
268 + request.setValue("application/json", forHTTPHeaderField: "Content-Type")
269 + request.httpBody = try JSONSerialization.data(withJSONObject: ["boc": output.encoded])
270 + request.timeoutInterval = 20
271 + let (data, _) = try await URLSession.shared.data(for: request)
272 + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
273 + json["ok"] as? Bool == true else {
274 + let message = (try? JSONSerialization.jsonObject(with: data) as? [String: Any])?["error"] as? String
275 + throw WalletError.rpc(message ?? "Broadcast failed.")
276 + }
277 + // toncenter returns the message hash; link the account view instead.
278 + let hash = ((json["result"] as? [String: Any])?["hash"] as? String) ?? ""
279 + return hash.isEmpty ? address : hash
280 + }
281 +
282 + // MARK: - Formatting
283 +
284 + public static func formatTON(_ nanotons: UInt64) -> String {
285 + TokenAmount.format(BigUInt(nanotons), decimals: tonDecimals, maxFractionDigits: 6)
286 + }
287 +
288 + public static func parseTON(_ input: String) -> UInt64? {
289 + guard let units = TokenAmount.parse(input, decimals: tonDecimals), units <= BigUInt(UInt64.max) else { return nil }
290 + return UInt64(units)
291 + }
292 +
293 + public static func parseUSDT(_ input: String) -> UInt64? {
294 + guard let units = TokenAmount.parse(input, decimals: usdtDecimals), units <= BigUInt(UInt64.max) else { return nil }
295 + return UInt64(units)
296 + }
297 +}
added Sources/OSVaultKit/Services/TransactionService.swift +221 −0
@@ -0,0 +1,221 @@
1 +//
2 +// TransactionService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +import Web3Core
12 +
13 +/// Builds, signs and broadcasts transfers, then tracks the receipt.
14 +/// Two shapes: native coin (value transfer) and ERC-20 `transfer` (calldata
15 +/// to the token contract). Fee logic follows the chain's FeeModel — the
16 +/// research finding is that "EIP-1559" hides four realities (BSC's zero base
17 +/// fee, OP-stack/Scroll L1 data fees, Arbitrum's inclusive estimates, Linea's
18 +/// pinned base). Gas is ALWAYS estimated, never hardcoded — even for native
19 +/// sends (Arbitrum folds L1 costs into the gas limit).
20 +public enum TransactionService {
21 +
22 + public struct PreparedTransfer {
23 + public let asset: Asset
24 + public let network: Network
25 + public let from: String
26 + public let recipient: String // checksummed
27 + public let amountUnits: BigUInt
28 + /// Transaction `to`: the recipient (native) or the token contract (ERC-20).
29 + public let txDestination: String
30 + public let txValue: BigUInt // amount (native) or 0 (ERC-20)
31 + public let calldata: Data
32 + public let nonce: BigUInt
33 + public let gasLimit: BigUInt
34 + public let maxFeePerGas: BigUInt
35 + public let maxPriorityFeePerGas: BigUInt
36 + /// Rollup L1 data fee (OP-stack/Scroll), deducted silently on-chain —
37 + /// shown to the user and included in the balance check.
38 + public let l1DataFee: BigUInt
39 +
40 + /// Worst-case cost in native wei on top of any native amount sent.
41 + public var maxGasCostWei: BigUInt { gasLimit * maxFeePerGas + l1DataFee }
42 + }
43 +
44 + // MARK: - Prepare (estimate everything, verify funds)
45 +
46 + public static func prepare(asset: Asset,
47 + network: Network,
48 + from: String,
49 + recipient: String,
50 + amountUnits: BigUInt,
51 + rpc: RPCService,
52 + balances: Balances) async throws -> PreparedTransfer {
53 + guard AddressValidator.validate(recipient) != .invalid else {
54 + throw WalletError.invalidAddress
55 + }
56 +
57 + let txDestination: String
58 + let txValue: BigUInt
59 + let calldata: Data
60 + switch asset {
61 + case .native:
62 + txDestination = recipient
63 + txValue = amountUnits
64 + calldata = Data()
65 + if amountUnits > balances.ethWei {
66 + throw WalletError.insufficientTokenBalance
67 + }
68 + case .token(let token):
69 + guard let contract = token.address(on: network) else {
70 + throw WalletError.internalError("\(token.symbol) is not deployed on \(network.config.displayName).")
71 + }
72 + guard let data = Hex.erc20TransferData(to: recipient, amount: amountUnits) else {
73 + throw WalletError.invalidAddress
74 + }
75 + txDestination = contract
76 + txValue = 0
77 + calldata = data
78 + if let held = balances.tokenUnits[token.symbol], amountUnits > held {
79 + throw WalletError.insufficientTokenBalance
80 + }
81 + }
82 +
83 + let nonce = try await rpc.transactionCount(of: from)
84 + let fees = try await feeParameters(for: network, rpc: rpc)
85 +
86 + let estimated = try await rpc.estimateGas(
87 + from: from, to: txDestination, valueWei: txValue, data: calldata
88 + )
89 + // Headroom on the estimate — except Arbitrum, whose estimate already
90 + // embeds the L1 buffer and is meant to be used verbatim.
91 + let gasLimit = network.config.feeModel == .arbitrumInclusive
92 + ? estimated
93 + : estimated * 12 / 10
94 +
95 + // L1 data fee via the rollup's oracle, on an unsigned serialization
96 + // of the tx. Best effort: a failing oracle call must not block sends.
97 + var l1Fee: BigUInt = 0
98 + if let oracle = network.l1FeeOracle,
99 + let destination = EthereumAddress(txDestination, ignoreChecksum: true) {
100 + var draft = CodableTransaction(
101 + type: .eip1559, to: destination, nonce: nonce,
102 + chainID: network.config.chainID, value: txValue, data: calldata,
103 + gasLimit: gasLimit, maxFeePerGas: fees.maxFee, maxPriorityFeePerGas: fees.tip
104 + )
105 + if let serialized = draft.encode(for: .signature) {
106 + var call = Data([0x49, 0x94, 0x8e, 0x0e]) // getL1Fee(bytes)
107 + call.append(Hex.abiWord(BigUInt(32))) // offset
108 + call.append(Hex.abiWord(BigUInt(serialized.count))) // length
109 + var padded = serialized
110 + if padded.count % 32 != 0 {
111 + padded.append(Data(repeating: 0, count: 32 - padded.count % 32))
112 + }
113 + call.append(padded)
114 + if let result = try? await rpc.call(to: oracle, data: call),
115 + let fee = Hex.toBigUInt(result) {
116 + l1Fee = fee
117 + }
118 + }
119 + }
120 +
121 + let prepared = PreparedTransfer(
122 + asset: asset, network: network, from: from, recipient: recipient,
123 + amountUnits: amountUnits, txDestination: txDestination,
124 + txValue: txValue, calldata: calldata,
125 + nonce: nonce, gasLimit: gasLimit,
126 + maxFeePerGas: fees.maxFee, maxPriorityFeePerGas: fees.tip,
127 + l1DataFee: l1Fee
128 + )
129 +
130 + // Native sends must cover amount + gas; token sends just the gas.
131 + let required = txValue + prepared.maxGasCostWei
132 + if balances.ethWei < required {
133 + throw WalletError.insufficientETHForGas(
134 + needWei: TokenAmount.formatWei(required),
135 + haveWei: TokenAmount.formatWei(balances.ethWei)
136 + )
137 + }
138 + return prepared
139 + }
140 +
141 + /// Per-FeeModel (maxFeePerGas, maxPriorityFeePerGas).
142 + static func feeParameters(for network: Network,
143 + rpc: RPCService) async throws -> (maxFee: BigUInt, tip: BigUInt) {
144 + switch network.config.feeModel {
145 + case .zeroBaseFee:
146 + // BSC: baseFee is 0 (BEP-226); price entirely via gasPrice.
147 + let gasPrice = try await rpc.gasPrice()
148 + return (max(gasPrice, 1), max(gasPrice, 1))
149 + case .lineaPinnedBase:
150 + // Base fee pinned at 7 wei; the tip is the real price.
151 + let gasPrice = try await rpc.gasPrice()
152 + let tip = (try? await rpc.maxPriorityFeePerGas()) ?? gasPrice
153 + return (max(gasPrice * 12 / 10, tip + 7), max(tip, 1))
154 + case .arbitrumInclusive:
155 + // Suggested tip is 0; cost = gasLimit × (2×base).
156 + let baseFee = try await rpc.latestBaseFee()
157 + let tip = (try? await rpc.maxPriorityFeePerGas()) ?? 0
158 + return (baseFee * 2 + tip, tip)
159 + case .eip1559, .opStackL1Fee, .scrollL1Fee:
160 + let baseFee = try await rpc.latestBaseFee()
161 + let tip: BigUInt
162 + if let suggested = try? await rpc.maxPriorityFeePerGas() {
163 + tip = max(suggested, 1)
164 + } else {
165 + tip = 1_000_000 // 0.001 gwei — plenty on modern L2s
166 + }
167 + return (baseFee * 2 + tip, tip)
168 + }
169 + }
170 +
171 + // MARK: - Sign + broadcast
172 +
173 + public static func send(_ prepared: PreparedTransfer, privateKey: Data, rpc: RPCService) async throws -> String {
174 + guard let destination = EthereumAddress(prepared.txDestination, ignoreChecksum: true) else {
175 + throw WalletError.internalError("Bad destination address.")
176 + }
177 + var tx = CodableTransaction(
178 + type: .eip1559,
179 + to: destination,
180 + nonce: prepared.nonce,
181 + chainID: prepared.network.config.chainID,
182 + value: prepared.txValue,
183 + data: prepared.calldata,
184 + gasLimit: prepared.gasLimit,
185 + maxFeePerGas: prepared.maxFeePerGas,
186 + maxPriorityFeePerGas: prepared.maxPriorityFeePerGas
187 + )
188 + do {
189 + try tx.sign(privateKey: privateKey)
190 + } catch {
191 + throw WalletError.signingFailed
192 + }
193 + guard let raw = tx.encode(for: .transaction) else {
194 + throw WalletError.signingFailed
195 + }
196 + return try await rpc.sendRawTransaction(Hex.string(raw))
197 + }
198 +
199 + // MARK: - Receipt tracking
200 +
201 + public enum Confirmation {
202 + case confirmed
203 + case failed
204 + case timedOut
205 + }
206 +
207 + public static func waitForReceipt(hash: String,
208 + rpc: RPCService,
209 + pollEvery seconds: Double = 3,
210 + timeout: Double = 300) async -> Confirmation {
211 + let deadline = Date().addingTimeInterval(timeout)
212 + while Date() < deadline {
213 + if let receipt = try? await rpc.transactionReceipt(hash) {
214 + return receipt.succeeded ? .confirmed : .failed
215 + }
216 + try? await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
217 + if Task.isCancelled { return .timedOut }
218 + }
219 + return .timedOut
220 + }
221 +}
added Sources/OSVaultKit/Services/TronService.swift +323 −0
@@ -0,0 +1,323 @@
1 +//
2 +// TronService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +import WalletCore
12 +import Web3Core
13 +
14 +/// Tron support — the largest USDT corridor. Signing via the vendored Trust
15 +/// wallet-core (`TransferContract` / `TransferTRC20Contract`), networking via
16 +/// keyless TronGrid REST with polite backoff (research: anonymous rate is
17 +/// throttled but ample for one wallet).
18 +///
19 +/// The Tron trap is the fee model: TRC-20 transfers consume ~65k energy
20 +/// (~130k to a fresh recipient); without staked energy the network burns
21 +/// ~13–27 TRX. The estimate is computed pre-send via
22 +/// `triggerconstantcontract` and shown to the user; `fee_limit` caps the burn.
23 +///
24 +/// Same security model: only the base58 address stays in memory; sends
25 +/// re-derive the key from the vault password and discard it.
26 +public actor TronService {
27 +
28 + public enum TronNetwork: String, CaseIterable, Codable, Sendable {
29 + case mainnet
30 + case nile // testnet, faucet at nileex.io
31 +
32 + public var apiBase: String {
33 + switch self {
34 + case .mainnet: return "https://api.trongrid.io"
35 + case .nile: return "https://nile.trongrid.io"
36 + }
37 + }
38 +
39 + /// USDT TRC-20 (verified live via symbol()/decimals(), 6 decimals).
40 + public var usdtContract: String {
41 + switch self {
42 + case .mainnet: return "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
43 + case .nile: return "TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf"
44 + }
45 + }
46 +
47 + public func explorerTxURL(_ txid: String) -> URL {
48 + switch self {
49 + case .mainnet: return URL(string: "https://tronscan.org/#/transaction/\(txid)")!
50 + case .nile: return URL(string: "https://nile.tronscan.org/#/transaction/\(txid)")!
51 + }
52 + }
53 +
54 + public func explorerAddressURL(_ address: String) -> URL {
55 + switch self {
56 + case .mainnet: return URL(string: "https://tronscan.org/#/address/\(address)")!
57 + case .nile: return URL(string: "https://nile.tronscan.org/#/address/\(address)")!
58 + }
59 + }
60 +
61 + public var displayName: String {
62 + switch self {
63 + case .mainnet: return "Tron"
64 + case .nile: return "Tron Nile"
65 + }
66 + }
67 +
68 + public var isTestnet: Bool { self == .nile }
69 + }
70 +
71 + public static let networkKey = "osvault.tron.network"
72 + public static let usdtDecimals = 6
73 + public static let trxDecimals = 6 // 1 TRX = 1_000_000 sun
74 + static let energyPriceSun: UInt64 = 420 // current chain parameter
75 + static let feeLimitSun: Int64 = 100_000_000 // 100 TRX ceiling
76 +
77 + public struct TronBalances: Sendable {
78 + public var trxSun: UInt64 = 0
79 + public var usdtUnits: UInt64 = 0
80 + }
81 +
82 + public struct PreparedTronSend: Sendable {
83 + public let recipient: String
84 + public let amountUnits: UInt64
85 + public let isUSDT: Bool
86 + /// Estimated burn in sun if no staked energy/bandwidth covers it.
87 + public let estimatedFeeSun: UInt64
88 + public let network: TronNetwork
89 + }
90 +
91 + private var address: String?
92 + private var network: TronNetwork = .nile
93 +
94 + // MARK: - Setup
95 +
96 + public func configure(mnemonic: String) throws {
97 + let stored = UserDefaults.standard.string(forKey: Self.networkKey)
98 + network = stored.flatMap(TronNetwork.init(rawValue:)) ?? .nile
99 + guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: "") else {
100 + throw WalletError.invalidMnemonic
101 + }
102 + address = wallet.getAddressForCoin(coin: .tron)
103 + }
104 +
105 + public var isConfigured: Bool { address != nil }
106 + public var currentNetwork: TronNetwork { network }
107 + public var publicAddress: String? { address }
108 +
109 + /// Address is network-independent; no password needed.
110 + public func switchNetwork(to newNetwork: TronNetwork) {
111 + UserDefaults.standard.set(newNetwork.rawValue, forKey: Self.networkKey)
112 + network = newNetwork
113 + }
114 +
115 + public static func validate(address: String) -> Bool {
116 + AnyAddress.isValid(string: address, coin: .tron)
117 + }
118 +
119 + // MARK: - HTTP
120 +
121 + private func post(_ path: String, body: [String: Any]) async throws -> [String: Any] {
122 + var request = URLRequest(url: URL(string: network.apiBase + path)!)
123 + request.httpMethod = "POST"
124 + request.setValue("application/json", forHTTPHeaderField: "Content-Type")
125 + request.httpBody = try JSONSerialization.data(withJSONObject: body)
126 + request.timeoutInterval = 20
127 + var lastError: Error = WalletError.rpc("TronGrid unreachable.")
128 + for attempt in 0..<3 {
129 + if attempt > 0 {
130 + try? await Task.sleep(nanoseconds: UInt64(attempt) * 1_200_000_000)
131 + }
132 + do {
133 + let (data, response) = try await URLSession.shared.data(for: request)
134 + if let http = response as? HTTPURLResponse, http.statusCode == 403 {
135 + lastError = WalletError.rpc("TronGrid rate limit — retrying.")
136 + continue
137 + }
138 + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
139 + lastError = WalletError.rpc("Malformed TronGrid response.")
140 + continue
141 + }
142 + return json
143 + } catch {
144 + lastError = WalletError.rpc(error.localizedDescription)
145 + }
146 + }
147 + throw lastError
148 + }
149 +
150 + private func get(_ path: String) async throws -> [String: Any] {
151 + var request = URLRequest(url: URL(string: network.apiBase + path)!)
152 + request.timeoutInterval = 20
153 + let (data, _) = try await URLSession.shared.data(for: request)
154 + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
155 + throw WalletError.rpc("Malformed TronGrid response.")
156 + }
157 + return json
158 + }
159 +
160 + // MARK: - Balances
161 +
162 + public func fetchBalances() async throws -> TronBalances {
163 + guard let address else { throw WalletError.internalError("Tron not configured.") }
164 + var balances = TronBalances()
165 + let json = try await get("/v1/accounts/\(address)")
166 + guard let accounts = json["data"] as? [[String: Any]] else {
167 + throw WalletError.rpc("TronGrid account query failed.")
168 + }
169 + guard let account = accounts.first else {
170 + return balances // unactivated account: all zero
171 + }
172 + if let sun = account["balance"] as? NSNumber {
173 + balances.trxSun = sun.uint64Value
174 + }
175 + if let trc20 = account["trc20"] as? [[String: String]] {
176 + for entry in trc20 {
177 + if let value = entry[network.usdtContract], let units = UInt64(value) {
178 + balances.usdtUnits = units
179 + }
180 + }
181 + }
182 + return balances
183 + }
184 +
185 + // MARK: - Estimate
186 +
187 + public func estimateSend(to recipient: String, amountUnits: UInt64, isUSDT: Bool) async throws -> PreparedTronSend {
188 + guard let address else { throw WalletError.internalError("Tron not configured.") }
189 + guard Self.validate(address: recipient) else { throw WalletError.invalidAddress }
190 +
191 + var feeSun: UInt64 = 0
192 + if isUSDT {
193 + // ABI-encode transfer(address,uint256): hex address (21 bytes,
194 + // 0x41-prefixed) left-padded + amount.
195 + guard let recipientHex = TronService.base58ToHex(recipient) else {
196 + throw WalletError.invalidAddress
197 + }
198 + let param = String(repeating: "0", count: 24) + recipientHex.dropFirst(2) // strip 0x41 prefix byte
199 + + String(String(repeating: "0", count: 64 - String(amountUnits, radix: 16).count)
200 + + String(amountUnits, radix: 16))
201 + let json = try await post("/wallet/triggerconstantcontract", body: [
202 + "owner_address": address,
203 + "contract_address": network.usdtContract,
204 + "function_selector": "transfer(address,uint256)",
205 + "parameter": param,
206 + "visible": true
207 + ])
208 + let energy = (json["energy_used"] as? NSNumber)?.uint64Value ?? 130_000
209 + feeSun = energy * Self.energyPriceSun + 350_000 // + bandwidth burn margin
210 + } else {
211 + // Plain TRX transfer: bandwidth only (~270 bytes), plus 1 TRX
212 + // account-creation fee if the recipient is fresh.
213 + let account = try await post("/wallet/getaccount", body: ["address": recipient, "visible": true])
214 + let isFresh = account.isEmpty || account["address"] == nil
215 + feeSun = (isFresh ? 1_100_000 : 300_000)
216 + }
217 +
218 + return PreparedTronSend(
219 + recipient: recipient, amountUnits: amountUnits,
220 + isUSDT: isUSDT, estimatedFeeSun: feeSun, network: network
221 + )
222 + }
223 +
224 + // MARK: - Sign + broadcast (wallet-core)
225 +
226 + public func send(_ prepared: PreparedTronSend, mnemonic: String) async throws -> String {
227 + guard let address else { throw WalletError.internalError("Tron not configured.") }
228 + guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: "") else {
229 + throw WalletError.invalidMnemonic
230 + }
231 + let key = wallet.getKeyForCoin(coin: .tron)
232 +
233 + // Reference block for the tx header.
234 + let now = try await post("/wallet/getnowblock", body: [:])
235 + guard let header = (now["block_header"] as? [String: Any])?["raw_data"] as? [String: Any],
236 + let number = (header["number"] as? NSNumber)?.int64Value,
237 + let version = (header["version"] as? NSNumber)?.int32Value,
238 + let timestamp = (header["timestamp"] as? NSNumber)?.int64Value,
239 + let txTrieRoot = header["txTrieRoot"] as? String,
240 + let parentHash = header["parentHash"] as? String,
241 + let witness = header["witness_address"] as? String,
242 + let blockID = now["blockID"] as? String else {
243 + throw WalletError.rpc("Could not fetch the reference block.")
244 + }
245 + _ = blockID
246 +
247 + var block = TronBlockHeader()
248 + block.number = number
249 + block.version = version
250 + block.timestamp = timestamp
251 + block.txTrieRoot = Hex.data(txTrieRoot) ?? Data()
252 + block.parentHash = Hex.data(parentHash) ?? Data()
253 + block.witnessAddress = Hex.data(witness) ?? Data()
254 +
255 + var tx = TronTransaction()
256 + tx.timestamp = timestamp
257 + tx.expiration = timestamp + 10 * 60 * 1000 // 10 minutes
258 + tx.blockHeader = block
259 + if prepared.isUSDT {
260 + tx.feeLimit = Self.feeLimitSun
261 + var contract = TronTransferTRC20Contract()
262 + contract.ownerAddress = address
263 + contract.contractAddress = prepared.network.usdtContract
264 + contract.toAddress = prepared.recipient
265 + contract.amount = Hex.abiWord(BigUInt(prepared.amountUnits))
266 + tx.contractOneof = .transferTrc20Contract(contract)
267 + } else {
268 + var contract = TronTransferContract()
269 + contract.ownerAddress = address
270 + contract.toAddress = prepared.recipient
271 + contract.amount = Int64(prepared.amountUnits)
272 + tx.contractOneof = .transfer(contract)
273 + }
274 +
275 + var input = TronSigningInput()
276 + input.transaction = tx
277 + input.privateKey = key.data
278 + let output: TronSigningOutput = AnySigner.sign(input: input, coin: .tron)
279 + guard output.error == .ok, !output.json.isEmpty else {
280 + throw WalletError.signingFailed
281 + }
282 +
283 + // Broadcast the signed JSON exactly as wallet-core produced it.
284 + var request = URLRequest(url: URL(string: network.apiBase + "/wallet/broadcasttransaction")!)
285 + request.httpMethod = "POST"
286 + request.setValue("application/json", forHTTPHeaderField: "Content-Type")
287 + request.httpBody = output.json.data(using: .utf8)
288 + request.timeoutInterval = 20
289 + let (data, _) = try await URLSession.shared.data(for: request)
290 + guard let result = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
291 + throw WalletError.rpc("Broadcast failed.")
292 + }
293 + if let ok = result["result"] as? Bool, ok {
294 + return output.id.map { String(format: "%02x", $0) }.joined()
295 + }
296 + let message = (result["message"] as? String).flatMap {
297 + Data(base64Encoded: $0).flatMap { String(data: $0, encoding: .utf8) }
298 + } ?? (result["code"] as? String ?? "Broadcast rejected.")
299 + throw WalletError.rpc(message)
300 + }
301 +
302 + // MARK: - Helpers
303 +
304 + /// Base58check T-address → 0x41-prefixed hex (21 bytes, lowercase, no 0x).
305 + static func base58ToHex(_ address: String) -> String? {
306 + guard let decoded = Base58.decode(string: address), decoded.count == 21 else { return nil }
307 + return decoded.map { String(format: "%02x", $0) }.joined()
308 + }
309 +
310 + public static func formatTRX(_ sun: UInt64) -> String {
311 + TokenAmount.format(BigUInt(sun), decimals: trxDecimals)
312 + }
313 +
314 + public static func parseTRX(_ input: String) -> UInt64? {
315 + guard let units = TokenAmount.parse(input, decimals: trxDecimals), units <= BigUInt(UInt64.max) else { return nil }
316 + return UInt64(units)
317 + }
318 +
319 + public static func parseUSDT(_ input: String) -> UInt64? {
320 + guard let units = TokenAmount.parse(input, decimals: usdtDecimals), units <= BigUInt(UInt64.max) else { return nil }
321 + return UInt64(units)
322 + }
323 +}
added Sources/OSVaultKit/Services/VaultCrypto.swift +96 −0
@@ -0,0 +1,96 @@
1 +//
2 +// VaultCrypto.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import CryptoKit
11 +import CommonCrypto
12 +
13 +/// OS Vault's own encryption mechanism — deliberately independent of the
14 +/// macOS Keychain. The secret (mnemonic) is sealed into a portable JSON file:
15 +///
16 +/// password ── PBKDF2-HMAC-SHA512 (600k rounds, random 32-byte salt) ──▶ 256-bit key
17 +/// secret ──── AES-256-GCM (random nonce, tag authenticates the file) ──▶ ciphertext
18 +///
19 +/// A wrong password or a tampered file both fail GCM authentication; the two
20 +/// cases are indistinguishable by design.
21 +public enum VaultCrypto {
22 +
23 + public static let currentVersion = 1
24 + public static let defaultIterations = 600_000
25 +
26 + public struct VaultFile: Codable, Equatable {
27 + public struct KDF: Codable, Equatable {
28 + public let algorithm: String // "pbkdf2-hmac-sha512"
29 + public let iterations: Int
30 + public let salt: String // base64
31 + }
32 + public let version: Int
33 + public let kdf: KDF
34 + public let cipher: String // "aes-256-gcm"
35 + public let ciphertext: String // base64, GCM combined (nonce ‖ ct ‖ tag)
36 + }
37 +
38 + public static func seal(secret: Data, password: String,
39 + iterations: Int = defaultIterations) throws -> VaultFile {
40 + var salt = Data(count: 32)
41 + let saltStatus = salt.withUnsafeMutableBytes { ptr in
42 + SecRandomCopyBytes(kSecRandomDefault, 32, ptr.baseAddress!)
43 + }
44 + guard saltStatus == errSecSuccess else { throw WalletError.internalError("Entropy source unavailable.") }
45 +
46 + let key = try deriveKey(password: password, salt: salt, iterations: iterations)
47 + let sealed = try AES.GCM.seal(secret, using: key)
48 + guard let combined = sealed.combined else { throw WalletError.internalError("Encryption failed.") }
49 +
50 + return VaultFile(
51 + version: currentVersion,
52 + kdf: .init(algorithm: "pbkdf2-hmac-sha512", iterations: iterations, salt: salt.base64EncodedString()),
53 + cipher: "aes-256-gcm",
54 + ciphertext: combined.base64EncodedString()
55 + )
56 + }
57 +
58 + public static func open(_ vault: VaultFile, password: String) throws -> Data {
59 + guard vault.version == currentVersion,
60 + vault.kdf.algorithm == "pbkdf2-hmac-sha512",
61 + vault.cipher == "aes-256-gcm",
62 + let salt = Data(base64Encoded: vault.kdf.salt),
63 + let combined = Data(base64Encoded: vault.ciphertext),
64 + vault.kdf.iterations >= 10_000 else {
65 + throw WalletError.vaultCorrupted
66 + }
67 + let key = try deriveKey(password: password, salt: salt, iterations: vault.kdf.iterations)
68 + do {
69 + let box = try AES.GCM.SealedBox(combined: combined)
70 + return try AES.GCM.open(box, using: key)
71 + } catch {
72 + throw WalletError.wrongPassword
73 + }
74 + }
75 +
76 + static func deriveKey(password: String, salt: Data, iterations: Int) throws -> SymmetricKey {
77 + let passwordData = Data(password.utf8)
78 + var derived = Data(count: 32)
79 + let status = derived.withUnsafeMutableBytes { derivedPtr in
80 + salt.withUnsafeBytes { saltPtr in
81 + passwordData.withUnsafeBytes { passPtr in
82 + CCKeyDerivationPBKDF(
83 + CCPBKDFAlgorithm(kCCPBKDF2),
84 + passPtr.bindMemory(to: Int8.self).baseAddress, passwordData.count,
85 + saltPtr.bindMemory(to: UInt8.self).baseAddress, salt.count,
86 + CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA512),
87 + UInt32(iterations),
88 + derivedPtr.bindMemory(to: UInt8.self).baseAddress, 32
89 + )
90 + }
91 + }
92 + }
93 + guard status == kCCSuccess else { throw WalletError.internalError("Key derivation failed.") }
94 + return SymmetricKey(data: derived)
95 + }
96 +}
added Sources/OSVaultKit/Services/XRPLService.swift +326 −0
@@ -0,0 +1,326 @@
1 +//
2 +// XRPLService.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +import WalletCore
12 +
13 +/// XRP Ledger support: XRP + RLUSD (Ripple's stablecoin, an issued currency).
14 +/// Signing via wallet-core (`OperationPayment` / `OperationTrustSet`),
15 +/// networking via the genuinely free public JSON-RPC servers (xrplcluster.com
16 +/// community full-history cluster; s.altnet.rippletest.net for testnet).
17 +///
18 +/// XRPL specifics surfaced to the user: the 1 XRP base reserve (+0.2 XRP per
19 +/// trustline) is locked, not spendable; RLUSD requires a trustline — the app
20 +/// offers one-tap creation and blocks sends to recipients without one.
21 +public actor XRPLService {
22 +
23 + public enum XRPLNetwork: String, CaseIterable, Codable, Sendable {
24 + case mainnet
25 + case testnet
26 +
27 + public var apiURL: String {
28 + switch self {
29 + case .mainnet: return "https://xrplcluster.com"
30 + case .testnet: return "https://s.altnet.rippletest.net:51234"
31 + }
32 + }
33 +
34 + var fallbackURL: String? {
35 + switch self {
36 + case .mainnet: return "https://s1.ripple.com:51234"
37 + case .testnet: return nil
38 + }
39 + }
40 +
41 + /// RLUSD issuer (mainnet from Ripple docs; testnet issuer verified
42 + /// live via account_info — tryrlusd.com faucet).
43 + public var rlusdIssuer: String {
44 + switch self {
45 + case .mainnet: return "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De"
46 + case .testnet: return "rQhWct2fv4Vc4KRjRgMrxa8xPN9Zx9iLKV"
47 + }
48 + }
49 +
50 + public func explorerTxURL(_ hash: String) -> URL {
51 + switch self {
52 + case .mainnet: return URL(string: "https://livenet.xrpl.org/transactions/\(hash)")!
53 + case .testnet: return URL(string: "https://testnet.xrpl.org/transactions/\(hash)")!
54 + }
55 + }
56 +
57 + public func explorerAddressURL(_ address: String) -> URL {
58 + switch self {
59 + case .mainnet: return URL(string: "https://livenet.xrpl.org/accounts/\(address)")!
60 + case .testnet: return URL(string: "https://testnet.xrpl.org/accounts/\(address)")!
61 + }
62 + }
63 +
64 + public var displayName: String {
65 + switch self {
66 + case .mainnet: return "XRP Ledger"
67 + case .testnet: return "XRPL Testnet"
68 + }
69 + }
70 +
71 + public var isTestnet: Bool { self == .testnet }
72 + }
73 +
74 + public static let networkKey = "osvault.xrpl.network"
75 + /// 160-bit hex currency code for "RLUSD" (non-standard >3-char code).
76 + public static let rlusdCurrencyHex = "524C555344000000000000000000000000000000"
77 + public static let xrpDecimals = 6 // 1 XRP = 1_000_000 drops
78 + static let baseReserveDrops: UInt64 = 1_000_000
79 + static let ownerReserveDrops: UInt64 = 200_000
80 +
81 + public struct XRPLBalances: Sendable {
82 + public var drops: UInt64 = 0
83 + public var reserveDrops: UInt64 = 0
84 + public var rlusdValue: String = "0" // issued-currency decimal string
85 + public var hasRLUSDTrustline = false
86 + public var accountExists = false
87 + public var spendableDrops: UInt64 {
88 + drops > reserveDrops ? drops - reserveDrops : 0
89 + }
90 + }
91 +
92 + public struct PreparedXRPLSend: Sendable {
93 + public let recipient: String
94 + /// Drops for XRP; decimal string for RLUSD.
95 + public let amountDrops: UInt64
96 + public let amountValue: String
97 + public let isRLUSD: Bool
98 + public let feeDrops: UInt64
99 + public let activatesRecipient: Bool
100 + public let network: XRPLNetwork
101 + }
102 +
103 + private var address: String?
104 + private var network: XRPLNetwork = .testnet
105 +
106 + // MARK: - Setup
107 +
108 + public func configure(mnemonic: String) throws {
109 + let stored = UserDefaults.standard.string(forKey: Self.networkKey)
110 + network = stored.flatMap(XRPLNetwork.init(rawValue:)) ?? .testnet
111 + guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: "") else {
112 + throw WalletError.invalidMnemonic
113 + }
114 + address = wallet.getAddressForCoin(coin: .xrp)
115 + }
116 +
117 + public var isConfigured: Bool { address != nil }
118 + public var currentNetwork: XRPLNetwork { network }
119 + public var publicAddress: String? { address }
120 +
121 + public func switchNetwork(to newNetwork: XRPLNetwork) {
122 + UserDefaults.standard.set(newNetwork.rawValue, forKey: Self.networkKey)
123 + network = newNetwork
124 + }
125 +
126 + public static func validate(address: String) -> Bool {
127 + AnyAddress.isValid(string: address, coin: .xrp)
128 + }
129 +
130 + // MARK: - JSON-RPC
131 +
132 + private func rpc(_ method: String, _ params: [String: Any]) async throws -> [String: Any] {
133 + let body: [String: Any] = ["method": method, "params": [params]]
134 + var lastError: Error = WalletError.rpc("XRPL endpoint unreachable.")
135 + for url in [network.apiURL, network.fallbackURL].compactMap({ $0 }) {
136 + var request = URLRequest(url: URL(string: url)!)
137 + request.httpMethod = "POST"
138 + request.setValue("application/json", forHTTPHeaderField: "Content-Type")
139 + request.httpBody = try JSONSerialization.data(withJSONObject: body)
140 + request.timeoutInterval = 20
141 + do {
142 + let (data, _) = try await URLSession.shared.data(for: request)
143 + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
144 + let result = json["result"] as? [String: Any] else {
145 + lastError = WalletError.rpc("Malformed XRPL response.")
146 + continue
147 + }
148 + return result
149 + } catch {
150 + lastError = WalletError.rpc(error.localizedDescription)
151 + }
152 + }
153 + throw lastError
154 + }
155 +
156 + // MARK: - Balances
157 +
158 + public func fetchBalances() async throws -> XRPLBalances {
159 + guard let address else { throw WalletError.internalError("XRPL not configured.") }
160 + var balances = XRPLBalances()
161 + let info = try await rpc("account_info", ["account": address, "ledger_index": "validated"])
162 + if info["error"] as? String == "actNotFound" {
163 + return balances // unfunded: first deposit must be ≥ 1 XRP
164 + }
165 + guard let accountData = info["account_data"] as? [String: Any] else {
166 + throw WalletError.rpc((info["error_message"] as? String) ?? "account_info failed.")
167 + }
168 + balances.accountExists = true
169 + balances.drops = (accountData["Balance"] as? String).flatMap(UInt64.init) ?? 0
170 + let ownerCount = (accountData["OwnerCount"] as? NSNumber)?.uint64Value ?? 0
171 + balances.reserveDrops = Self.baseReserveDrops + ownerCount * Self.ownerReserveDrops
172 +
173 + let lines = try await rpc("account_lines", ["account": address, "ledger_index": "validated"])
174 + for line in (lines["lines"] as? [[String: Any]]) ?? [] {
175 + if line["currency"] as? String == Self.rlusdCurrencyHex,
176 + line["account"] as? String == network.rlusdIssuer {
177 + balances.hasRLUSDTrustline = true
178 + balances.rlusdValue = (line["balance"] as? String) ?? "0"
179 + }
180 + }
181 + return balances
182 + }
183 +
184 + private func recipientHasRLUSDTrustline(_ recipient: String) async throws -> Bool {
185 + if recipient == network.rlusdIssuer { return true }
186 + let lines = try await rpc("account_lines", ["account": recipient, "ledger_index": "validated"])
187 + if lines["error"] as? String == "actNotFound" { return false }
188 + for line in (lines["lines"] as? [[String: Any]]) ?? [] {
189 + if line["currency"] as? String == Self.rlusdCurrencyHex,
190 + line["account"] as? String == network.rlusdIssuer {
191 + return true
192 + }
193 + }
194 + return false
195 + }
196 +
197 + // MARK: - Estimate
198 +
199 + public func estimateSend(to recipient: String, amountDrops: UInt64,
200 + amountValue: String, isRLUSD: Bool) async throws -> PreparedXRPLSend {
201 + guard Self.validate(address: recipient) else { throw WalletError.invalidAddress }
202 + let feeResult = try await rpc("fee", [:])
203 + let openFee = ((feeResult["drops"] as? [String: Any])?["open_ledger_fee"] as? String)
204 + .flatMap(UInt64.init) ?? 10
205 + let fee = max(10, min(openFee, 10_000)) // sane bounds
206 +
207 + var activates = false
208 + if isRLUSD {
209 + guard try await recipientHasRLUSDTrustline(recipient) else {
210 + throw WalletError.internalError("The recipient has no RLUSD trustline — they must add one before they can receive RLUSD.")
211 + }
212 + } else {
213 + let info = try await rpc("account_info", ["account": recipient, "ledger_index": "validated"])
214 + if info["error"] as? String == "actNotFound" {
215 + activates = true
216 + guard amountDrops >= Self.baseReserveDrops else {
217 + throw WalletError.internalError("This account doesn't exist yet — the first payment must be at least 1 XRP (base reserve).")
218 + }
219 + }
220 + }
221 + return PreparedXRPLSend(
222 + recipient: recipient, amountDrops: amountDrops, amountValue: amountValue,
223 + isRLUSD: isRLUSD, feeDrops: fee, activatesRecipient: activates, network: network
224 + )
225 + }
226 +
227 + // MARK: - Sign + submit
228 +
229 + private func signingContext() async throws -> (sequence: UInt32, lastLedger: UInt32) {
230 + guard let address else { throw WalletError.internalError("XRPL not configured.") }
231 + let info = try await rpc("account_info", ["account": address, "ledger_index": "validated"])
232 + guard let accountData = info["account_data"] as? [String: Any],
233 + let sequence = (accountData["Sequence"] as? NSNumber)?.uint32Value,
234 + let ledgerIndex = (info["ledger_index"] as? NSNumber)?.uint32Value else {
235 + throw WalletError.rpc("Could not read the account sequence.")
236 + }
237 + return (sequence, ledgerIndex + 30)
238 + }
239 +
240 + private func submit(_ input: RippleSigningInput) async throws -> String {
241 + let output: RippleSigningOutput = AnySigner.sign(input: input, coin: .xrp)
242 + guard output.error == .ok, !output.encoded.isEmpty else {
243 + throw WalletError.signingFailed
244 + }
245 + let blob = output.encoded.map { String(format: "%02X", $0) }.joined()
246 + let result = try await rpc("submit", ["tx_blob": blob])
247 + let engine = (result["engine_result"] as? String) ?? "unknown"
248 + guard engine == "tesSUCCESS" || engine.hasPrefix("terQUEUED") else {
249 + throw WalletError.rpc((result["engine_result_message"] as? String) ?? engine)
250 + }
251 + return ((result["tx_json"] as? [String: Any])?["hash"] as? String) ?? blob.prefix(64).lowercased()
252 + }
253 +
254 + public func send(_ prepared: PreparedXRPLSend, mnemonic: String) async throws -> String {
255 + guard let address else { throw WalletError.internalError("XRPL not configured.") }
256 + guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: "") else {
257 + throw WalletError.invalidMnemonic
258 + }
259 + let context = try await signingContext()
260 +
261 + var payment = RippleOperationPayment()
262 + payment.destination = prepared.recipient
263 + if prepared.isRLUSD {
264 + var currency = RippleCurrencyAmount()
265 + currency.currency = Self.rlusdCurrencyHex
266 + currency.value = prepared.amountValue
267 + currency.issuer = prepared.network.rlusdIssuer
268 + payment.currencyAmount = currency
269 + } else {
270 + payment.amount = Int64(prepared.amountDrops)
271 + }
272 +
273 + var input = RippleSigningInput()
274 + input.account = address
275 + input.fee = Int64(prepared.feeDrops)
276 + input.sequence = context.sequence
277 + input.lastLedgerSequence = context.lastLedger
278 + input.privateKey = wallet.getKeyForCoin(coin: .xrp).data
279 + input.operationOneof = .opPayment(payment)
280 + return try await submit(input)
281 + }
282 +
283 + /// One-tap RLUSD trustline (costs the 12-drop fee + locks 0.2 XRP reserve).
284 + public func createRLUSDTrustline(mnemonic: String) async throws -> String {
285 + guard let address else { throw WalletError.internalError("XRPL not configured.") }
286 + guard let wallet = HDWallet(mnemonic: mnemonic, passphrase: "") else {
287 + throw WalletError.invalidMnemonic
288 + }
289 + let context = try await signingContext()
290 +
291 + var limit = RippleCurrencyAmount()
292 + limit.currency = Self.rlusdCurrencyHex
293 + limit.value = "1000000000"
294 + limit.issuer = network.rlusdIssuer
295 + var trustSet = RippleOperationTrustSet()
296 + trustSet.limitAmount = limit
297 +
298 + var input = RippleSigningInput()
299 + input.account = address
300 + input.fee = 12
301 + input.sequence = context.sequence
302 + input.lastLedgerSequence = context.lastLedger
303 + input.flags = 131_072 // tfSetNoRipple
304 + input.privateKey = wallet.getKeyForCoin(coin: .xrp).data
305 + input.operationOneof = .opTrustSet(trustSet)
306 + return try await submit(input)
307 + }
308 +
309 + // MARK: - Formatting
310 +
311 + public static func formatXRP(_ drops: UInt64) -> String {
312 + TokenAmount.format(BigUInt(drops), decimals: xrpDecimals)
313 + }
314 +
315 + public static func parseXRP(_ input: String) -> UInt64? {
316 + guard let units = TokenAmount.parse(input, decimals: xrpDecimals), units <= BigUInt(UInt64.max) else { return nil }
317 + return UInt64(units)
318 + }
319 +
320 + /// RLUSD values travel as decimal strings on-ledger; validate shape only.
321 + public static func validRLUSDAmount(_ input: String) -> String? {
322 + let normalized = input.trimmingCharacters(in: .whitespaces).replacingOccurrences(of: ",", with: ".")
323 + guard TokenAmount.parse(normalized, decimals: 15) ?? 0 > 0 else { return nil }
324 + return normalized
325 + }
326 +}
added Sources/OSVaultKit/Utils/AddressValidator.swift +43 −0
@@ -0,0 +1,43 @@
1 +//
2 +// AddressValidator.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import Web3Core
11 +
12 +/// Recipient address validation: hex shape + EIP-55 checksum.
13 +/// All-lowercase (or all-uppercase) addresses carry no checksum information —
14 +/// they are accepted with a warning, per the project security rules.
15 +public enum AddressValidator {
16 +
17 + public enum Verdict: Equatable {
18 + /// Mixed-case address whose EIP-55 checksum matches.
19 + case valid(checksummed: String)
20 + /// Well-formed but caseless — no checksum to verify. Warn, don't block.
21 + case validNoChecksum(checksummed: String)
22 + case invalid
23 + }
24 +
25 + public static func validate(_ input: String) -> Verdict {
26 + let candidate = input.trimmingCharacters(in: .whitespacesAndNewlines)
27 + guard candidate.count == 42, candidate.hasPrefix("0x") else { return .invalid }
28 + let body = String(candidate.dropFirst(2))
29 + guard body.allSatisfy({ $0.isHexDigit }) else { return .invalid }
30 + guard let checksummed = EthereumAddress.toChecksumAddress(candidate) else { return .invalid }
31 +
32 + // An exact checksum match is valid even when it happens to be all one
33 + // case (some EIP-55 checksums are, e.g. 0x529084…9EE7).
34 + if candidate == checksummed {
35 + return .valid(checksummed: checksummed)
36 + }
37 + let letters = body.filter { $0.isLetter }
38 + let caseless = letters.isEmpty
39 + || letters.allSatisfy { $0.isLowercase }
40 + || letters.allSatisfy { $0.isUppercase }
41 + return caseless ? .validNoChecksum(checksummed: checksummed) : .invalid
42 + }
43 +}
added Sources/OSVaultKit/Utils/Hex.swift +69 −0
@@ -0,0 +1,69 @@
1 +//
2 +// Hex.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import Foundation
10 +import BigInt
11 +
12 +/// Minimal hex helpers for JSON-RPC quantities and calldata.
13 +public enum Hex {
14 +
15 + public static func quantity(_ value: BigUInt) -> String {
16 + "0x" + String(value, radix: 16)
17 + }
18 +
19 + public static func toBigUInt(_ hex: String) -> BigUInt? {
20 + let stripped = hex.hasPrefix("0x") ? String(hex.dropFirst(2)) : hex
21 + if stripped.isEmpty { return 0 }
22 + return BigUInt(stripped, radix: 16)
23 + }
24 +
25 + public static func data(_ hex: String) -> Data? {
26 + var stripped = hex.hasPrefix("0x") ? String(hex.dropFirst(2)) : hex
27 + if stripped.count % 2 != 0 { stripped = "0" + stripped }
28 + var out = Data(capacity: stripped.count / 2)
29 + var index = stripped.startIndex
30 + while index < stripped.endIndex {
31 + let next = stripped.index(index, offsetBy: 2)
32 + guard let byte = UInt8(stripped[index..<next], radix: 16) else { return nil }
33 + out.append(byte)
34 + index = next
35 + }
36 + return out
37 + }
38 +
39 + public static func string(_ data: Data) -> String {
40 + "0x" + data.map { String(format: "%02x", $0) }.joined()
41 + }
42 +
43 + /// Left-pads to a 32-byte ABI word.
44 + public static func abiWord(_ data: Data) -> Data {
45 + if data.count >= 32 { return data.suffix(32) }
46 + return Data(repeating: 0, count: 32 - data.count) + data
47 + }
48 +
49 + public static func abiWord(_ value: BigUInt) -> Data {
50 + abiWord(value.serialize())
51 + }
52 +
53 + /// ERC-20 `transfer(address,uint256)` calldata.
54 + public static func erc20TransferData(to recipient: String, amount: BigUInt) -> Data? {
55 + guard let addressData = data(recipient), addressData.count == 20 else { return nil }
56 + var calldata = Data([0xa9, 0x05, 0x9c, 0xbb])
57 + calldata.append(abiWord(addressData))
58 + calldata.append(abiWord(amount))
59 + return calldata
60 + }
61 +
62 + /// ERC-20 `balanceOf(address)` calldata.
63 + public static func erc20BalanceOfData(owner: String) -> Data? {
64 + guard let addressData = data(owner), addressData.count == 20 else { return nil }
65 + var calldata = Data([0x70, 0xa0, 0x82, 0x31])
66 + calldata.append(abiWord(addressData))
67 + return calldata
68 + }
69 +}
added Sources/OSVaultKit/Utils/QRCode.swift +25 −0
@@ -0,0 +1,25 @@
1 +//
2 +// QRCode.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import AppKit
10 +import CoreImage
11 +
12 +enum QRCode {
13 + /// Renders a crisp (non-interpolated) QR code for the given string.
14 + static func image(for string: String, side: CGFloat = 240) -> NSImage? {
15 + guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
16 + filter.setValue(Data(string.utf8), forKey: "inputMessage")
17 + filter.setValue("M", forKey: "inputCorrectionLevel")
18 + guard let output = filter.outputImage else { return nil }
19 +
20 + let scale = side / output.extent.width
21 + let scaled = output.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
22 + guard let cgImage = CIContext().createCGImage(scaled, from: scaled.extent) else { return nil }
23 + return NSImage(cgImage: cgImage, size: NSSize(width: side, height: side))
24 + }
25 +}
added Sources/OSVaultKit/Views/Bitcoin/BitcoinView.swift +373 −0
@@ -0,0 +1,373 @@
1 +//
2 +// BitcoinView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +import BigInt
11 +
12 +/// Bitcoin panel: balance (confirmed/pending), receive with address rotation,
13 +/// send with live fee presets from mempool.space, and the mainnet/signet
14 +/// switch. Same security flow as EVM sends: password → sign → discard.
15 +struct BitcoinView: View {
16 + @EnvironmentObject var app: AppState
17 + @Environment(\.dismiss) private var dismiss
18 +
19 + enum Mode { case overview, receive, send }
20 + @State private var mode: Mode = .overview
21 +
22 + // Receive
23 + @State private var receiveAddress: String?
24 +
25 + // Send
26 + @State private var recipient = ""
27 + @State private var amountInput = ""
28 + @State private var fees: BitcoinService.FeeRates?
29 + @State private var selectedRate: UInt64 = 2
30 + @State private var prepared: BitcoinService.PreparedBTCSend?
31 + @State private var password = ""
32 + @State private var sending = false
33 + @State private var sentTxid: String?
34 + @State private var errorMessage: String?
35 +
36 + // Network switch
37 + @State private var switchPassword = ""
38 + @State private var showNetworkSwitch = false
39 +
40 + var body: some View {
41 + VStack(alignment: .leading, spacing: 16) {
42 + header
43 + switch mode {
44 + case .overview: overview
45 + case .receive: receive
46 + case .send: send
47 + }
48 + }
49 + .padding(24)
50 + .frame(width: 470)
51 + .onAppear {
52 + Task { fees = await app.bitcoinService.recommendedFees()
53 + selectedRate = fees?.halfHour ?? 2 }
54 + }
55 + }
56 +
57 + private var header: some View {
58 + HStack {
59 + Text("Bitcoin").font(.title2.bold())
60 + Spacer()
61 + Text(app.btcNetwork.isTestnet ? "SIGNET · test" : "MAINNET")
62 + .font(.caption.weight(.bold))
63 + .padding(.horizontal, 10).padding(.vertical, 4)
64 + .background(app.btcNetwork.isTestnet ? Color.orange.opacity(0.25) : Color.yellow.opacity(0.25))
65 + .foregroundStyle(app.btcNetwork.isTestnet ? Color.orange : Color.yellow)
66 + .clipShape(Capsule())
67 + Button("Done") { dismiss() }
68 + }
69 + }
70 +
71 + // MARK: - Overview
72 +
73 + private var overview: some View {
74 + VStack(alignment: .leading, spacing: 14) {
75 + VStack(alignment: .leading, spacing: 8) {
76 + HStack(alignment: .firstTextBaseline) {
77 + Text("BTC").font(.headline)
78 + Spacer()
79 + VStack(alignment: .trailing, spacing: 2) {
80 + Text(BitcoinService.formatBTC(app.btcBalance?.totalSats ?? 0) + " BTC")
81 + .font(.system(size: 26, weight: .bold, design: .rounded))
82 + .monospacedDigit()
83 + if let fiat = btcFiat {
84 + Text(fiat).font(.caption).foregroundStyle(.secondary)
85 + }
86 + }
87 + }
88 + if let balance = app.btcBalance, balance.pendingSats > 0 {
89 + Text("\(BitcoinService.formatBTC(balance.confirmedSats)) confirmed + \(BitcoinService.formatBTC(balance.pendingSats)) pending")
90 + .font(.caption).foregroundStyle(.orange)
91 + }
92 + if app.btcSyncing {
93 + HStack { ProgressView().controlSize(.small); Text("Syncing…").font(.caption).foregroundStyle(.secondary) }
94 + }
95 + if let error = app.btcError {
96 + Label(error, systemImage: "wifi.exclamationmark")
97 + .font(.caption).foregroundStyle(.orange)
98 + }
99 + }
100 + .padding(14)
101 + .background(.quaternary.opacity(0.4))
102 + .clipShape(RoundedRectangle(cornerRadius: 10))
103 +
104 + HStack(spacing: 12) {
105 + Button {
106 + mode = .send
107 + } label: {
108 + Label("Send", systemImage: "arrow.up.circle.fill").frame(maxWidth: .infinity)
109 + }
110 + .buttonStyle(.borderedProminent)
111 + Button {
112 + mode = .receive
113 + receiveAddress = nil
114 + } label: {
115 + Label("Receive", systemImage: "arrow.down.circle").frame(maxWidth: .infinity)
116 + }
117 + Button {
118 + Task { await app.refreshBitcoin() }
119 + } label: {
120 + Image(systemName: "arrow.clockwise")
121 + }
122 + .help("Sync now")
123 + }
124 +
125 + Text("Native SegWit (BIP-84) from your existing recovery phrase. Sync, fees and broadcast via mempool.space — keyless, with automatic fallback.")
126 + .font(.caption)
127 + .foregroundStyle(.secondary)
128 +
129 + DisclosureGroup("Network", isExpanded: $showNetworkSwitch) {
130 + VStack(alignment: .leading, spacing: 8) {
131 + Text("Switching re-derives your Bitcoin wallet on the other network. Enter your vault password to apply.")
132 + .font(.caption).foregroundStyle(.secondary)
133 + HStack {
134 + SecureField("Vault password", text: $switchPassword)
135 + .textFieldStyle(.roundedBorder)
136 + Button(app.btcNetwork == .signet ? "Switch to mainnet" : "Switch to signet") {
137 + switchNetwork()
138 + }
139 + .disabled(switchPassword.isEmpty)
140 + }
141 + }
142 + .padding(.top, 6)
143 + }
144 + .font(.callout)
145 + }
146 + }
147 +
148 + private var btcFiat: String? {
149 + guard app.pricesEnabled, let sats = app.btcBalance?.totalSats, sats > 0,
150 + let price = app.fiatPrices["BTC"] else { return nil }
151 + let value = PriceService.fiatValue(units: BigUInt(sats), decimals: 8, price: price)
152 + return "≈ " + PriceService.formatFiat(value, currency: app.fiatCurrency)
153 + }
154 +
155 + private func switchNetwork() {
156 + let target: BitcoinService.BTCNetwork = app.btcNetwork == .signet ? .mainnet : .signet
157 + let candidate = switchPassword
158 + errorMessage = nil
159 + Task {
160 + do {
161 + try await app.switchBitcoinNetwork(to: target, password: candidate)
162 + switchPassword = ""
163 + showNetworkSwitch = false
164 + } catch {
165 + errorMessage = error.localizedDescription
166 + }
167 + }
168 + }
169 +
170 + // MARK: - Receive
171 +
172 + private var receive: some View {
173 + VStack(spacing: 14) {
174 + if let address = receiveAddress {
175 + if let qr = QRCode.image(for: address) {
176 + Image(nsImage: qr)
177 + .interpolation(.none)
178 + .resizable()
179 + .frame(width: 200, height: 200)
180 + .background(.white)
181 + .clipShape(RoundedRectangle(cornerRadius: 8))
182 + }
183 + Text(address)
184 + .font(.callout.monospaced())
185 + .textSelection(.enabled)
186 + .padding(8)
187 + .background(.quaternary.opacity(0.4))
188 + .clipShape(RoundedRectangle(cornerRadius: 8))
189 + CopyButton(text: address)
190 + Text("A fresh address is revealed on every use (privacy). Older addresses keep working.")
191 + .font(.caption).foregroundStyle(.secondary)
192 + .multilineTextAlignment(.center)
193 + } else {
194 + ProgressView()
195 + }
196 + if let errorMessage {
197 + Text(errorMessage).foregroundStyle(.red).font(.callout)
198 + }
199 + Button("Back") { mode = .overview }
200 + }
201 + .frame(maxWidth: .infinity)
202 + .onAppear {
203 + Task {
204 + do { receiveAddress = try await app.bitcoinService.receiveAddress() }
205 + catch { errorMessage = error.localizedDescription }
206 + }
207 + }
208 + }
209 +
210 + // MARK: - Send
211 +
212 + private var send: some View {
213 + VStack(alignment: .leading, spacing: 12) {
214 + if let txid = sentTxid {
215 + sentView(txid)
216 + } else if let prepared {
217 + confirmView(prepared)
218 + } else {
219 + sendForm
220 + }
221 + }
222 + }
223 +
224 + private var sendForm: some View {
225 + VStack(alignment: .leading, spacing: 12) {
226 + TextField("Recipient (bc1q… / tb1q…)", text: $recipient)
227 + .textFieldStyle(.roundedBorder)
228 + .font(.body.monospaced())
229 + .autocorrectionDisabled()
230 + if !recipient.isEmpty && !BitcoinService.validate(address: recipient, network: app.btcNetwork) {
231 + Label("Not a valid \(app.btcNetwork.displayName) address", systemImage: "xmark.circle")
232 + .font(.caption).foregroundStyle(.red)
233 + }
234 + HStack {
235 + TextField("Amount", text: $amountInput)
236 + .textFieldStyle(.roundedBorder)
237 + .font(.body.monospaced())
238 + Text("BTC").foregroundStyle(.secondary)
239 + }
240 + Text("Balance: \(BitcoinService.formatBTC(app.btcBalance?.totalSats ?? 0)) BTC")
241 + .font(.caption).foregroundStyle(.secondary)
242 +
243 + if let fees {
244 + Picker("Fee", selection: $selectedRate) {
245 + Text("Fast (~10 min) · \(fees.fastest) sat/vB").tag(fees.fastest)
246 + Text("Normal (~30 min) · \(fees.halfHour) sat/vB").tag(fees.halfHour)
247 + Text("Slow (~1 h) · \(fees.hour) sat/vB").tag(fees.hour)
248 + Text("Economy · \(fees.economy) sat/vB").tag(fees.economy)
249 + }
250 + }
251 + if let errorMessage {
252 + Text(errorMessage).foregroundStyle(.red).font(.callout)
253 + }
254 + HStack {
255 + Button("Back") { mode = .overview; errorMessage = nil }
256 + Spacer()
257 + Button("Review") { prepare() }
258 + .buttonStyle(.borderedProminent)
259 + .disabled(!sendFormValid)
260 + }
261 + }
262 + }
263 +
264 + private var sendFormValid: Bool {
265 + BitcoinService.validate(address: recipient, network: app.btcNetwork)
266 + && (BitcoinService.parseBTC(amountInput) ?? 0) > 0
267 + }
268 +
269 + private func prepare() {
270 + guard let sats = BitcoinService.parseBTC(amountInput) else { return }
271 + errorMessage = nil
272 + let to = recipient.trimmingCharacters(in: .whitespacesAndNewlines)
273 + let rate = selectedRate
274 + Task {
275 + do {
276 + prepared = try await app.bitcoinService.prepareSend(
277 + to: to, amountSats: sats, feeRateSatVb: rate)
278 + } catch {
279 + errorMessage = error.localizedDescription
280 + }
281 + }
282 + }
283 +
284 + private func confirmView(_ p: BitcoinService.PreparedBTCSend) -> some View {
285 + VStack(alignment: .leading, spacing: 12) {
286 + Text("Confirm transaction").font(.headline)
287 + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) {
288 + GridRow {
289 + Text("Recipient").foregroundStyle(.secondary)
290 + Text(p.recipient).font(.callout.monospaced()).textSelection(.enabled)
291 + }
292 + GridRow {
293 + Text("Amount").foregroundStyle(.secondary)
294 + Text("\(BitcoinService.formatBTC(p.amountSats)) BTC").fontWeight(.semibold)
295 + }
296 + GridRow {
297 + Text("Network").foregroundStyle(.secondary)
298 + Text(p.network.displayName)
299 + }
300 + GridRow {
301 + Text("Fee").foregroundStyle(.secondary)
302 + Text("\(BitcoinService.formatBTC(p.feeSats)) BTC (\(p.feeRateSatVb) sat/vB)")
303 + }
304 + GridRow {
305 + Text("Total").foregroundStyle(.secondary)
306 + Text("\(BitcoinService.formatBTC(p.amountSats + p.feeSats)) BTC")
307 + }
308 + }
309 + .font(.callout)
310 + Divider()
311 + SecureField("Vault password to sign", text: $password)
312 + .textFieldStyle(.roundedBorder)
313 + if let errorMessage {
314 + Text(errorMessage).foregroundStyle(.red).font(.callout)
315 + }
316 + HStack {
317 + Button("Back") {
318 + prepared = nil
319 + password = ""
320 + Task { await app.bitcoinService.cancelPending() }
321 + }
322 + Spacer()
323 + if sending { ProgressView().controlSize(.small) }
324 + Button("Sign & send") { broadcast() }
325 + .buttonStyle(.borderedProminent)
326 + .disabled(password.isEmpty || sending)
327 + }
328 + }
329 + }
330 +
331 + private func broadcast() {
332 + sending = true
333 + errorMessage = nil
334 + let candidate = password
335 + let manager = app.keyManager
336 + Task {
337 + do {
338 + let mnemonic = try await Task.detached {
339 + try manager.unlock(password: candidate).mnemonic
340 + }.value
341 + let txid = try await app.bitcoinService.signAndBroadcast(mnemonic: mnemonic)
342 + password = ""
343 + sentTxid = txid
344 + await app.refreshBitcoin()
345 + } catch {
346 + errorMessage = error.localizedDescription
347 + }
348 + sending = false
349 + }
350 + }
351 +
352 + private func sentView(_ txid: String) -> some View {
353 + VStack(spacing: 12) {
354 + Image(systemName: "paperplane.circle.fill")
355 + .font(.system(size: 38)).foregroundStyle(.green)
356 + Text("Transaction broadcast").font(.headline)
357 + Text(txid)
358 + .font(.caption.monospaced())
359 + .textSelection(.enabled)
360 + .lineLimit(1).truncationMode(.middle)
361 + Link("View on mempool.space", destination: app.btcNetwork.explorerTxURL(txid))
362 + Button("Done") {
363 + sentTxid = nil
364 + prepared = nil
365 + recipient = ""
366 + amountInput = ""
367 + mode = .overview
368 + }
369 + .buttonStyle(.borderedProminent)
370 + }
371 + .frame(maxWidth: .infinity)
372 + }
373 +}
added Sources/OSVaultKit/Views/Home/HomeView.swift +254 −0
@@ -0,0 +1,254 @@
1 +//
2 +// HomeView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +import BigInt
11 +
12 +struct HomeView: View {
13 + @EnvironmentObject var app: AppState
14 + @State private var showSend = false
15 + @State private var showReceive = false
16 + @State private var showSettings = false
17 + @State private var showBitcoin = false
18 + @State private var showSolana = false
19 + @State private var showTron = false
20 + @State private var showXRPL = false
21 + @State private var showTON = false
22 +
23 + var body: some View {
24 + VStack(spacing: 0) {
25 + header
26 + Divider()
27 + ScrollView {
28 + VStack(spacing: 16) {
29 + balanceCard
30 + if lowOnGas {
31 + gasWarning
32 + }
33 + actionButtons
34 + historySection
35 + }
36 + .padding(20)
37 + }
38 + }
39 + .sheet(isPresented: $showSend) { SendView() }
40 + .sheet(isPresented: $showReceive) { ReceiveView() }
41 + .sheet(isPresented: $showSettings) { SettingsView() }
42 + .sheet(isPresented: $showBitcoin) { BitcoinView() }
43 + .sheet(isPresented: $showSolana) { SolanaView() }
44 + .sheet(isPresented: $showTron) { TronView() }
45 + .sheet(isPresented: $showXRPL) { XRPLView() }
46 + .sheet(isPresented: $showTON) { TONView() }
47 + }
48 +
49 + private var header: some View {
50 + HStack {
51 + NetworkBadge(network: app.network)
52 + Spacer()
53 + if let address = app.address {
54 + Text(address.shortAddress)
55 + .font(.callout.monospaced())
56 + .foregroundStyle(.secondary)
57 + CopyButton(text: address)
58 + .labelStyle(.iconOnly)
59 + .buttonStyle(.borderless)
60 + }
61 + Menu {
62 + Button("Bitcoin") { showBitcoin = true }
63 + Button("Solana") { showSolana = true }
64 + Button("Tron") { showTron = true }
65 + Button("XRP Ledger") { showXRPL = true }
66 + Button("TON") { showTON = true }
67 + } label: {
68 + Image(systemName: "link.circle")
69 + }
70 + .menuStyle(.borderlessButton)
71 + .frame(width: 40)
72 + .help("Other chains")
73 + Button {
74 + showSettings = true
75 + } label: {
76 + Image(systemName: "gearshape")
77 + }
78 + .buttonStyle(.borderless)
79 + Button {
80 + app.lock()
81 + } label: {
82 + Image(systemName: "lock.fill")
83 + }
84 + .buttonStyle(.borderless)
85 + .help("Lock the vault")
86 + }
87 + .padding(.horizontal, 20)
88 + .padding(.vertical, 12)
89 + }
90 +
91 + private var tokens: [Token] { Token.available(on: app.network) }
92 +
93 + private var balanceCard: some View {
94 + VStack(alignment: .leading, spacing: 12) {
95 + if !app.balancesLoaded && app.balanceError == nil {
96 + HStack {
97 + ProgressView().controlSize(.small)
98 + Text("Loading balances…").foregroundStyle(.secondary)
99 + }
100 + }
101 + if let error = app.balanceError, !app.balancesLoaded {
102 + Label(error, systemImage: "wifi.exclamationmark")
103 + .foregroundStyle(.orange)
104 + .font(.callout)
105 + }
106 + ForEach(tokens) { token in
107 + HStack(alignment: .firstTextBaseline) {
108 + Text(token.symbol).font(.headline)
109 + Text(token.name).font(.caption).foregroundStyle(.secondary)
110 + Spacer()
111 + VStack(alignment: .trailing, spacing: 2) {
112 + Text(TokenAmount.format(app.balances.tokenUnits[token.symbol] ?? 0,
113 + decimals: token.decimals, maxFractionDigits: 6))
114 + .font(token.symbol == "USDC" ? .system(size: 28, weight: .bold, design: .rounded)
115 + : .title3.weight(.semibold))
116 + .monospacedDigit()
117 + if let fiat = fiatLine(units: app.balances.tokenUnits[token.symbol] ?? 0,
118 + decimals: token.decimals, symbol: token.symbol) {
119 + Text(fiat).font(.caption).foregroundStyle(.secondary)
120 + }
121 + }
122 + }
123 + }
124 + Divider()
125 + HStack {
126 + Text("\(app.network.config.nativeSymbol) (gas)").font(.subheadline).foregroundStyle(.secondary)
127 + Spacer()
128 + VStack(alignment: .trailing, spacing: 2) {
129 + Text(TokenAmount.formatWei(app.balances.ethWei, maxFractionDigits: 6) + " " + app.network.config.nativeSymbol)
130 + .font(.subheadline.monospaced())
131 + .foregroundStyle(.secondary)
132 + if let fiat = fiatLine(units: app.balances.ethWei, decimals: 18,
133 + symbol: app.network.config.nativeSymbol) {
134 + Text(fiat).font(.caption).foregroundStyle(.secondary)
135 + }
136 + }
137 + }
138 + if let error = app.balanceError, app.balancesLoaded {
139 + Text("Refresh failed: \(error)").font(.caption).foregroundStyle(.orange)
140 + }
141 + }
142 + .padding(16)
143 + .background(.quaternary.opacity(0.4))
144 + .clipShape(RoundedRectangle(cornerRadius: 12))
145 + }
146 +
147 + private func fiatLine(units: BigUInt, decimals: Int, symbol: String) -> String? {
148 + guard app.pricesEnabled, units > 0, let price = app.fiatPrices[symbol] else { return nil }
149 + let value = PriceService.fiatValue(units: units, decimals: decimals, price: price)
150 + return "≈ " + PriceService.formatFiat(value, currency: app.fiatCurrency)
151 + }
152 +
153 + private var lowOnGas: Bool {
154 + // Rough per-chain floor for one ERC-20 transfer; refined at send time.
155 + guard app.balancesLoaded else { return false }
156 + let floor: BigUInt
157 + switch app.network {
158 + case .polygon, .bnb, .avalanche, .gnosis: floor = 5_000_000_000_000_000 // 0.005 native
159 + case .ethereum: floor = 1_000_000_000_000_000 // 0.001 ETH
160 + default: floor = 30_000_000_000_000 // cheap L2s
161 + }
162 + return app.balances.ethWei < floor
163 + }
164 +
165 + private var gasWarning: some View {
166 + Label("\(app.network.config.nativeSymbol) balance is very low. Gas is paid in \(app.network.config.nativeSymbol) — sends may fail until you top up.",
167 + systemImage: "fuelpump.slash")
168 + .font(.callout)
169 + .foregroundStyle(.orange)
170 + .frame(maxWidth: .infinity, alignment: .leading)
171 + .padding(12)
172 + .background(Color.orange.opacity(0.12))
173 + .clipShape(RoundedRectangle(cornerRadius: 8))
174 + }
175 +
176 + private var actionButtons: some View {
177 + HStack(spacing: 12) {
178 + Button {
179 + showSend = true
180 + } label: {
181 + Label("Send", systemImage: "arrow.up.circle.fill")
182 + .frame(maxWidth: .infinity)
183 + }
184 + .buttonStyle(.borderedProminent)
185 + .controlSize(.large)
186 +
187 + Button {
188 + showReceive = true
189 + } label: {
190 + Label("Receive", systemImage: "arrow.down.circle")
191 + .frame(maxWidth: .infinity)
192 + }
193 + .controlSize(.large)
194 +
195 + Button {
196 + Task { await app.refreshBalances() }
197 + } label: {
198 + Image(systemName: "arrow.clockwise")
199 + }
200 + .controlSize(.large)
201 + .help("Refresh balances")
202 + }
203 + }
204 +
205 + private var historySection: some View {
206 + VStack(alignment: .leading, spacing: 8) {
207 + Text("Activity").font(.headline)
208 + let visible = app.history.filter { $0.network == app.network }
209 + if visible.isEmpty {
210 + Text("Sends from this app will appear here. Full history is on the explorer.")
211 + .font(.callout)
212 + .foregroundStyle(.secondary)
213 + }
214 + ForEach(visible) { record in
215 + HStack {
216 + statusIcon(record.status)
217 + VStack(alignment: .leading, spacing: 2) {
218 + Text("Sent \(record.displayAmount) \(record.tokenSymbol)")
219 + .font(.callout.weight(.medium))
220 + Text("to \(record.recipient.shortAddress) · \(record.date.formatted(date: .abbreviated, time: .shortened))")
221 + .font(.caption)
222 + .foregroundStyle(.secondary)
223 + }
224 + Spacer()
225 + Link(destination: record.explorerURL) {
226 + Image(systemName: "arrow.up.right.square")
227 + }
228 + .help("View on the explorer")
229 + }
230 + .padding(10)
231 + .background(.quaternary.opacity(0.3))
232 + .clipShape(RoundedRectangle(cornerRadius: 8))
233 + }
234 + if let address = app.address {
235 + Link("View full history on the explorer",
236 + destination: app.network.explorerAddressURL(address))
237 + .font(.callout)
238 + .padding(.top, 4)
239 + }
240 + }
241 + .frame(maxWidth: .infinity, alignment: .leading)
242 + }
243 +
244 + private func statusIcon(_ status: TransactionRecord.Status) -> some View {
245 + switch status {
246 + case .pending:
247 + return Image(systemName: "clock").foregroundStyle(Color.orange)
248 + case .confirmed:
249 + return Image(systemName: "checkmark.circle.fill").foregroundStyle(Color.green)
250 + case .failed:
251 + return Image(systemName: "xmark.circle.fill").foregroundStyle(Color.red)
252 + }
253 + }
254 +}
added Sources/OSVaultKit/Views/Onboarding/OnboardingView.swift +307 −0
@@ -0,0 +1,307 @@
1 +//
2 +// OnboardingView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +
11 +/// Create-wallet flow: password → show mnemonic → verify 3 random words →
12 +/// vault written. Import flow: phrase + password. The vault is only written
13 +/// after backup verification succeeds (create) or the phrase validates (import).
14 +struct OnboardingView: View {
15 + @EnvironmentObject var app: AppState
16 +
17 + enum Step {
18 + case welcome
19 + case setPassword(importing: Bool)
20 + case showMnemonic
21 + case verifyMnemonic
22 + case importPhrase
23 + }
24 +
25 + @State private var step: Step = .welcome
26 + @State private var password = ""
27 + @State private var passwordConfirm = ""
28 + @State private var mnemonic = ""
29 + @State private var importInput = ""
30 + @State private var verifyIndices: [Int] = []
31 + @State private var verifyInputs: [String] = ["", "", ""]
32 + @State private var errorMessage: String?
33 +
34 + var body: some View {
35 + VStack(spacing: 0) {
36 + content
37 + }
38 + .padding(32)
39 + .frame(maxWidth: .infinity, maxHeight: .infinity)
40 + }
41 +
42 + @ViewBuilder
43 + private var content: some View {
44 + switch step {
45 + case .welcome: welcome
46 + case .setPassword(let importing): setPassword(importing: importing)
47 + case .showMnemonic: showMnemonic
48 + case .verifyMnemonic: verifyMnemonic
49 + case .importPhrase: importPhrase
50 + }
51 + }
52 +
53 + // MARK: - Welcome
54 +
55 + private var welcome: some View {
56 + VStack(spacing: 20) {
57 + Image(systemName: "lock.shield")
58 + .font(.system(size: 56))
59 + .foregroundStyle(.blue)
60 + Text("OS Vault").font(.largeTitle.bold())
61 + Text("Self-custody wallet for stablecoins, ETH and Bitcoin —\n11 EVM chains + Bitcoin from one recovery phrase.\nKeys are encrypted locally with OS Vault's own vault format; they never leave this Mac.")
62 + .multilineTextAlignment(.center)
63 + .foregroundStyle(.secondary)
64 + VStack(spacing: 12) {
65 + Button("Create a new wallet") {
66 + step = .setPassword(importing: false)
67 + }
68 + .buttonStyle(.borderedProminent)
69 + .controlSize(.large)
70 + Button("Import an existing wallet") {
71 + step = .setPassword(importing: true)
72 + }
73 + .controlSize(.large)
74 + }
75 + .padding(.top, 8)
76 + }
77 + }
78 +
79 + // MARK: - Password
80 +
81 + private func setPassword(importing: Bool) -> some View {
82 + VStack(alignment: .leading, spacing: 16) {
83 + Text("Choose a vault password").font(.title2.bold())
84 + Text("This password encrypts your recovery phrase on this Mac (AES-256-GCM). It cannot be recovered — if you forget it, only your recovery phrase can restore the wallet.")
85 + .foregroundStyle(.secondary)
86 + SecureField("Password (min. 8 characters)", text: $password)
87 + .textFieldStyle(.roundedBorder)
88 + SecureField("Confirm password", text: $passwordConfirm)
89 + .textFieldStyle(.roundedBorder)
90 + if let errorMessage {
91 + Text(errorMessage).foregroundStyle(.red).font(.callout)
92 + }
93 + HStack {
94 + Button("Back") {
95 + reset()
96 + }
97 + Spacer()
98 + Button("Continue") {
99 + guard password.count >= 8 else {
100 + errorMessage = "Password must be at least 8 characters."
101 + return
102 + }
103 + guard password == passwordConfirm else {
104 + errorMessage = "Passwords do not match."
105 + return
106 + }
107 + errorMessage = nil
108 + if importing {
109 + step = .importPhrase
110 + } else {
111 + do {
112 + mnemonic = try app.keyManager.generateMnemonic()
113 + step = .showMnemonic
114 + } catch {
115 + errorMessage = error.localizedDescription
116 + }
117 + }
118 + }
119 + .buttonStyle(.borderedProminent)
120 + }
121 + }
122 + .frame(maxWidth: 420)
123 + }
124 +
125 + // MARK: - Show mnemonic
126 +
127 + private var mnemonicWords: [String] { mnemonic.split(separator: " ").map(String.init) }
128 +
129 + private var showMnemonic: some View {
130 + VStack(alignment: .leading, spacing: 16) {
131 + Text("Your recovery phrase").font(.title2.bold())
132 + Text("Write these 12 words down on paper, in order. Anyone with these words controls your funds. OS Vault will never show them again without your password.")
133 + .foregroundStyle(.secondary)
134 + LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 10) {
135 + ForEach(Array(mnemonicWords.enumerated()), id: \.offset) { index, word in
136 + HStack {
137 + Text("\(index + 1).").foregroundStyle(.secondary).monospacedDigit()
138 + Text(word).fontWeight(.medium)
139 + Spacer()
140 + }
141 + .padding(8)
142 + .background(.quaternary.opacity(0.5))
143 + .clipShape(RoundedRectangle(cornerRadius: 6))
144 + }
145 + }
146 + HStack {
147 + Button("Back") { step = .setPassword(importing: false) }
148 + Spacer()
149 + Button("I wrote it down — verify") {
150 + verifyIndices = Array(0..<12).shuffled().prefix(3).sorted()
151 + verifyInputs = ["", "", ""]
152 + errorMessage = nil
153 + step = .verifyMnemonic
154 + }
155 + .buttonStyle(.borderedProminent)
156 + }
157 + }
158 + .frame(maxWidth: 480)
159 + }
160 +
161 + // MARK: - Verify backup
162 +
163 + private var verifyMnemonic: some View {
164 + VStack(alignment: .leading, spacing: 16) {
165 + Text("Verify your backup").font(.title2.bold())
166 + Text("Enter the requested words from your written backup.")
167 + .foregroundStyle(.secondary)
168 + ForEach(0..<3, id: \.self) { slot in
169 + HStack {
170 + Text("Word #\(verifyIndices[slot] + 1)")
171 + .frame(width: 90, alignment: .leading)
172 + TextField("word", text: $verifyInputs[slot])
173 + .textFieldStyle(.roundedBorder)
174 + .autocorrectionDisabled()
175 + }
176 + }
177 + if let errorMessage {
178 + Text(errorMessage).foregroundStyle(.red).font(.callout)
179 + }
180 + HStack {
181 + Button("Show phrase again") { step = .showMnemonic }
182 + Spacer()
183 + Button("Confirm") { finishCreate() }
184 + .buttonStyle(.borderedProminent)
185 + }
186 + }
187 + .frame(maxWidth: 420)
188 + }
189 +
190 + private func finishCreate() {
191 + let words = mnemonicWords
192 + for slot in 0..<3 {
193 + let expected = words[verifyIndices[slot]]
194 + let given = verifyInputs[slot].trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
195 + guard given == expected else {
196 + errorMessage = "Word #\(verifyIndices[slot] + 1) does not match. Check your backup."
197 + return
198 + }
199 + }
200 + persist(mnemonic: mnemonic)
201 + }
202 +
203 + // MARK: - Import
204 +
205 + private var importPhrase: some View {
206 + VStack(alignment: .leading, spacing: 16) {
207 + Text("Import wallet").font(.title2.bold())
208 + Text("Enter your 12- or 24-word recovery phrase, separated by spaces.")
209 + .foregroundStyle(.secondary)
210 + TextEditor(text: $importInput)
211 + .font(.body.monospaced())
212 + .frame(height: 90)
213 + .overlay(RoundedRectangle(cornerRadius: 6).stroke(.quaternary))
214 + .autocorrectionDisabled()
215 + if let errorMessage {
216 + Text(errorMessage).foregroundStyle(.red).font(.callout)
217 + }
218 + HStack {
219 + Button("Back") { step = .setPassword(importing: true) }
220 + Spacer()
221 + Button("Import") {
222 + guard KeyManager.validate(mnemonic: importInput) else {
223 + errorMessage = WalletError.invalidMnemonic.errorDescription
224 + return
225 + }
226 + persist(mnemonic: importInput)
227 + }
228 + .buttonStyle(.borderedProminent)
229 + }
230 + }
231 + .frame(maxWidth: 480)
232 + }
233 +
234 + // MARK: - Common
235 +
236 + private func persist(mnemonic: String) {
237 + do {
238 + let wallet = try app.keyManager.saveWallet(mnemonic: mnemonic, password: password)
239 + reset()
240 + app.didUnlock(wallet: wallet)
241 + } catch {
242 + errorMessage = error.localizedDescription
243 + }
244 + }
245 +
246 + private func reset() {
247 + password = ""
248 + passwordConfirm = ""
249 + mnemonic = ""
250 + importInput = ""
251 + verifyInputs = ["", "", ""]
252 + errorMessage = nil
253 + step = .welcome
254 + }
255 +}
256 +
257 +/// Lock screen for an existing vault.
258 +struct UnlockView: View {
259 + @EnvironmentObject var app: AppState
260 + @State private var password = ""
261 + @State private var errorMessage: String?
262 + @State private var unlocking = false
263 +
264 + var body: some View {
265 + VStack(spacing: 20) {
266 + Image(systemName: "lock.fill")
267 + .font(.system(size: 44))
268 + .foregroundStyle(.blue)
269 + Text("OS Vault is locked").font(.title2.bold())
270 + SecureField("Vault password", text: $password)
271 + .textFieldStyle(.roundedBorder)
272 + .frame(maxWidth: 280)
273 + .onSubmit(unlock)
274 + if let errorMessage {
275 + Text(errorMessage).foregroundStyle(.red).font(.callout)
276 + }
277 + Button(unlocking ? "Unlocking…" : "Unlock") { unlock() }
278 + .buttonStyle(.borderedProminent)
279 + .controlSize(.large)
280 + .disabled(unlocking || password.isEmpty)
281 + }
282 + .padding(32)
283 + .frame(maxWidth: .infinity, maxHeight: .infinity)
284 + }
285 +
286 + private func unlock() {
287 + guard !password.isEmpty else { return }
288 + unlocking = true
289 + errorMessage = nil
290 + let manager = app.keyManager
291 + let candidate = password
292 + Task.detached {
293 + // PBKDF2 at 600k rounds is deliberately slow; keep it off the main thread.
294 + let result = Result { try manager.unlock(password: candidate) }
295 + await MainActor.run {
296 + unlocking = false
297 + switch result {
298 + case .success(let wallet):
299 + password = ""
300 + app.didUnlock(wallet: wallet)
301 + case .failure(let error):
302 + errorMessage = error.localizedDescription
303 + }
304 + }
305 + }
306 + }
307 +}
added Sources/OSVaultKit/Views/Receive/ReceiveView.swift +49 −0
@@ -0,0 +1,49 @@
1 +//
2 +// ReceiveView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +
11 +struct ReceiveView: View {
12 + @EnvironmentObject var app: AppState
13 + @Environment(\.dismiss) private var dismiss
14 +
15 + var body: some View {
16 + VStack(spacing: 16) {
17 + HStack {
18 + Text("Receive").font(.title2.bold())
19 + Spacer()
20 + NetworkBadge(network: app.network)
21 + }
22 + if let address = app.address {
23 + if let qr = QRCode.image(for: address) {
24 + Image(nsImage: qr)
25 + .interpolation(.none)
26 + .resizable()
27 + .frame(width: 220, height: 220)
28 + .background(.white)
29 + .clipShape(RoundedRectangle(cornerRadius: 8))
30 + }
31 + Text(address)
32 + .font(.callout.monospaced())
33 + .textSelection(.enabled)
34 + .padding(10)
35 + .background(.quaternary.opacity(0.4))
36 + .clipShape(RoundedRectangle(cornerRadius: 8))
37 + CopyButton(text: address)
38 + Text("Send only assets on \(app.network.config.displayName) (chain ID \(String(app.network.config.chainID))) to this address.")
39 + .font(.caption)
40 + .foregroundStyle(.secondary)
41 + .multilineTextAlignment(.center)
42 + }
43 + Button("Done") { dismiss() }
44 + .keyboardShortcut(.defaultAction)
45 + }
46 + .padding(24)
47 + .frame(width: 380)
48 + }
49 +}
added Sources/OSVaultKit/Views/Send/SendView.swift +324 −0
@@ -0,0 +1,324 @@
1 +//
2 +// SendView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +import BigInt
11 +
12 +/// Send flow: token + recipient + amount → prepare (gas preview) →
13 +/// confirmation screen showing recipient, amount, network, gas and total →
14 +/// password re-entry unlocks the vault, signs, broadcasts, tracks the receipt.
15 +struct SendView: View {
16 + @EnvironmentObject var app: AppState
17 + @Environment(\.dismiss) private var dismiss
18 +
19 + enum Stage {
20 + case form
21 + case preparing
22 + case confirm(TransactionService.PreparedTransfer)
23 + case sending
24 + case sent(hash: String)
25 + }
26 +
27 + @State private var stage: Stage = .form
28 + @State private var asset: Asset = .token(.usdc)
29 + @State private var recipientInput = ""
30 + @State private var amountInput = ""
31 + @State private var password = ""
32 + @State private var errorMessage: String?
33 +
34 + var body: some View {
35 + VStack(alignment: .leading, spacing: 16) {
36 + HStack {
37 + Text("Send").font(.title2.bold())
38 + Spacer()
39 + NetworkBadge(network: app.network)
40 + }
41 + content
42 + }
43 + .padding(24)
44 + .frame(width: 460)
45 + }
46 +
47 + @ViewBuilder
48 + private var content: some View {
49 + switch stage {
50 + case .form, .preparing:
51 + form
52 + case .confirm(let prepared):
53 + confirmView(prepared)
54 + case .sending:
55 + HStack {
56 + ProgressView().controlSize(.small)
57 + Text("Signing and broadcasting…")
58 + }
59 + .frame(maxWidth: .infinity, alignment: .center)
60 + .padding(.vertical, 30)
61 + case .sent(let hash):
62 + sentView(hash)
63 + }
64 + }
65 +
66 + // MARK: - Form
67 +
68 + private var recipientVerdict: AddressValidator.Verdict {
69 + AddressValidator.validate(recipientInput)
70 + }
71 +
72 + private var form: some View {
73 + VStack(alignment: .leading, spacing: 14) {
74 + Picker("Asset", selection: $asset) {
75 + ForEach(Asset.available(on: app.network)) { candidate in
76 + Text("\(candidate.symbol(on: app.network))\(candidate.name(on: app.network))")
77 + .tag(candidate)
78 + }
79 + }
80 +
81 + VStack(alignment: .leading, spacing: 4) {
82 + TextField("Recipient address (0x…)", text: $recipientInput)
83 + .textFieldStyle(.roundedBorder)
84 + .font(.body.monospaced())
85 + .autocorrectionDisabled()
86 + switch recipientVerdict {
87 + case .valid:
88 + Label("Checksum valid", systemImage: "checkmark.circle")
89 + .font(.caption).foregroundStyle(.green)
90 + case .validNoChecksum:
91 + Label("Address has no checksum (all one case). Double-check it before sending.",
92 + systemImage: "exclamationmark.triangle")
93 + .font(.caption).foregroundStyle(.orange)
94 + case .invalid:
95 + if !recipientInput.isEmpty {
96 + Label("Not a valid address", systemImage: "xmark.circle")
97 + .font(.caption).foregroundStyle(.red)
98 + }
99 + }
100 + }
101 +
102 + VStack(alignment: .leading, spacing: 4) {
103 + HStack {
104 + TextField("Amount", text: $amountInput)
105 + .textFieldStyle(.roundedBorder)
106 + .font(.body.monospaced())
107 + Text(asset.symbol(on: app.network)).foregroundStyle(.secondary)
108 + Button("Max") {
109 + amountInput = TokenAmount.format(assetBalance, decimals: asset.decimals)
110 + }
111 + .controlSize(.small)
112 + }
113 + Text("Balance: \(TokenAmount.format(assetBalance, decimals: asset.decimals)) \(asset.symbol(on: app.network))")
114 + .font(.caption)
115 + .foregroundStyle(.secondary)
116 + }
117 +
118 + if let errorMessage {
119 + Text(errorMessage).foregroundStyle(.red).font(.callout)
120 + }
121 +
122 + HStack {
123 + Button("Cancel") { dismiss() }
124 + Spacer()
125 + if case .preparing = stage {
126 + ProgressView().controlSize(.small)
127 + }
128 + Button("Review") { prepare() }
129 + .buttonStyle(.borderedProminent)
130 + .disabled(!formValid || isPreparing)
131 + }
132 + }
133 + .onAppear { resetAssetIfUnavailable() }
134 + .onChange(of: app.network) { _, _ in resetAssetIfUnavailable(force: true) }
135 + }
136 +
137 + private func resetAssetIfUnavailable(force: Bool = false) {
138 + let available = Asset.available(on: app.network)
139 + if force || !available.contains(asset) {
140 + asset = available.first ?? .native
141 + }
142 + }
143 +
144 + private var assetBalance: BigUInt {
145 + switch asset {
146 + case .native: return app.balances.ethWei
147 + case .token(let token): return app.balances.tokenUnits[token.symbol] ?? 0
148 + }
149 + }
150 +
151 + private var isPreparing: Bool {
152 + if case .preparing = stage { return true }
153 + return false
154 + }
155 +
156 + private var formValid: Bool {
157 + recipientVerdict != .invalid
158 + && TokenAmount.parse(amountInput, decimals: asset.decimals).map { $0 > 0 } == true
159 + }
160 +
161 + private func prepare() {
162 + guard let from = app.address,
163 + let amount = TokenAmount.parse(amountInput, decimals: asset.decimals) else { return }
164 + let checksummedRecipient: String
165 + switch recipientVerdict {
166 + case .valid(let c), .validNoChecksum(let c): checksummedRecipient = c
167 + case .invalid: return
168 + }
169 + errorMessage = nil
170 + stage = .preparing
171 + let network = app.network
172 + let rpc = app.rpc()
173 + let balances = app.balances
174 + let selectedAsset = asset
175 + Task {
176 + do {
177 + let prepared = try await TransactionService.prepare(
178 + asset: selectedAsset, network: network, from: from,
179 + recipient: checksummedRecipient, amountUnits: amount,
180 + rpc: rpc, balances: balances
181 + )
182 + stage = .confirm(prepared)
183 + } catch {
184 + errorMessage = error.localizedDescription
185 + stage = .form
186 + }
187 + }
188 + }
189 +
190 + // MARK: - Confirm
191 +
192 + private func confirmView(_ prepared: TransactionService.PreparedTransfer) -> some View {
193 + VStack(alignment: .leading, spacing: 14) {
194 + Text("Confirm transaction").font(.headline)
195 +
196 + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) {
197 + GridRow {
198 + Text("Recipient").foregroundStyle(.secondary)
199 + Text(prepared.recipient).font(.callout.monospaced()).textSelection(.enabled)
200 + }
201 + GridRow {
202 + Text("Amount").foregroundStyle(.secondary)
203 + Text("\(TokenAmount.format(prepared.amountUnits, decimals: prepared.asset.decimals)) \(prepared.asset.symbol(on: prepared.network))")
204 + .fontWeight(.semibold)
205 + }
206 + GridRow {
207 + Text("Network").foregroundStyle(.secondary)
208 + Text("\(prepared.network.config.displayName) (chain \(String(prepared.network.config.chainID)))")
209 + }
210 + GridRow {
211 + Text("Max gas").foregroundStyle(.secondary)
212 + Text("\(TokenAmount.formatWei(prepared.maxGasCostWei)) \(prepared.network.config.nativeSymbol)" + (prepared.l1DataFee > 0 ? " (incl. L1 data fee)" : ""))
213 + }
214 + GridRow {
215 + Text("Total").foregroundStyle(.secondary)
216 + totalText(prepared)
217 + }
218 + }
219 + .font(.callout)
220 +
221 + Divider()
222 + Text("Enter your vault password to sign.")
223 + .font(.callout)
224 + .foregroundStyle(.secondary)
225 + SecureField("Vault password", text: $password)
226 + .textFieldStyle(.roundedBorder)
227 + if let errorMessage {
228 + Text(errorMessage).foregroundStyle(.red).font(.callout)
229 + }
230 + HStack {
231 + Button("Back") {
232 + password = ""
233 + errorMessage = nil
234 + stage = .form
235 + }
236 + Spacer()
237 + Button("Sign & send") { send(prepared) }
238 + .buttonStyle(.borderedProminent)
239 + .disabled(password.isEmpty)
240 + }
241 + }
242 + }
243 +
244 + private func totalText(_ prepared: TransactionService.PreparedTransfer) -> Text {
245 + let native = prepared.network.config.nativeSymbol
246 + switch prepared.asset {
247 + case .native:
248 + let total = prepared.amountUnits + prepared.maxGasCostWei
249 + return Text("≤ \(TokenAmount.formatWei(total)) \(native) (amount + max gas)")
250 + case .token(let token):
251 + return Text("\(TokenAmount.format(prepared.amountUnits, decimals: token.decimals)) \(token.symbol) + gas in \(native)")
252 + }
253 + }
254 +
255 + private func send(_ prepared: TransactionService.PreparedTransfer) {
256 + errorMessage = nil
257 + stage = .sending
258 + let manager = app.keyManager
259 + let candidate = password
260 + let rpc = app.rpc()
261 + Task {
262 + do {
263 + // Unlock off the main thread (slow KDF), sign, discard the key.
264 + let wallet = try await Task.detached {
265 + try manager.unlock(password: candidate)
266 + }.value
267 + let hash = try await TransactionService.send(prepared, privateKey: wallet.privateKey, rpc: rpc)
268 + password = ""
269 + app.recordSend(TransactionRecord(
270 + hash: hash, asset: prepared.asset, amountUnits: prepared.amountUnits,
271 + recipient: prepared.recipient, network: prepared.network, status: .pending
272 + ))
273 + stage = .sent(hash: hash)
274 + trackReceipt(hash: hash, rpc: rpc)
275 + } catch {
276 + errorMessage = error.localizedDescription
277 + stage = .confirm(prepared)
278 + }
279 + }
280 + }
281 +
282 + private func trackReceipt(hash: String, rpc: RPCService) {
283 + Task {
284 + let outcome = await TransactionService.waitForReceipt(hash: hash, rpc: rpc)
285 + switch outcome {
286 + case .confirmed:
287 + app.updateRecord(hash: hash, status: .confirmed)
288 + case .failed:
289 + app.updateRecord(hash: hash, status: .failed)
290 + case .timedOut:
291 + break // stays pending; explorer link tells the full story
292 + }
293 + await app.refreshBalances()
294 + }
295 + }
296 +
297 + // MARK: - Sent
298 +
299 + private func sentView(_ hash: String) -> some View {
300 + VStack(spacing: 14) {
301 + Image(systemName: "paperplane.circle.fill")
302 + .font(.system(size: 40))
303 + .foregroundStyle(.green)
304 + Text("Transaction broadcast").font(.headline)
305 + Text(hash)
306 + .font(.caption.monospaced())
307 + .textSelection(.enabled)
308 + .lineLimit(1)
309 + .truncationMode(.middle)
310 + Text("Status will update in Activity once the network confirms it (usually a few seconds on Base).")
311 + .font(.callout)
312 + .foregroundStyle(.secondary)
313 + .multilineTextAlignment(.center)
314 + HStack {
315 + Link("View on BaseScan", destination: app.network.explorerTxURL(hash))
316 + Spacer()
317 + Button("Done") { dismiss() }
318 + .buttonStyle(.borderedProminent)
319 + .keyboardShortcut(.defaultAction)
320 + }
321 + }
322 + .frame(maxWidth: .infinity)
323 + }
324 +}
added Sources/OSVaultKit/Views/Settings/SettingsView.swift +201 −0
@@ -0,0 +1,201 @@
1 +//
2 +// SettingsView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +
11 +struct SettingsView: View {
12 + @EnvironmentObject var app: AppState
13 + @Environment(\.dismiss) private var dismiss
14 +
15 + @State private var rpcOverride = ""
16 + @State private var exportPassword = ""
17 + @State private var exportedMnemonic: String?
18 + @State private var exportError: String?
19 + @State private var deleteConfirmation = ""
20 + @State private var deleteError: String?
21 +
22 + var body: some View {
23 + VStack(alignment: .leading, spacing: 0) {
24 + HStack {
25 + Text("Settings").font(.title2.bold())
26 + Spacer()
27 + Button("Done") { dismiss() }
28 + .keyboardShortcut(.defaultAction)
29 + }
30 + .padding(.bottom, 12)
31 +
32 + ScrollView {
33 + VStack(alignment: .leading, spacing: 20) {
34 + networkSection
35 + Divider()
36 + pricesSection
37 + Divider()
38 + rpcSection
39 + Divider()
40 + exportSection
41 + Divider()
42 + deleteSection
43 + }
44 + .padding(.vertical, 4)
45 + }
46 + }
47 + .padding(24)
48 + .frame(width: 480, height: 560)
49 + .onAppear {
50 + rpcOverride = UserDefaults.standard.string(forKey: app.network.rpcOverrideKey) ?? ""
51 + }
52 + }
53 +
54 + // MARK: - Network
55 +
56 + private var networkSection: some View {
57 + VStack(alignment: .leading, spacing: 8) {
58 + Text("Network").font(.headline)
59 + Picker("Active network", selection: $app.network) {
60 + ForEach(Network.allCases) { network in
61 + Text(network.config.displayName + (network.config.isTestnet ? " (testnet)" : ""))
62 + .tag(network)
63 + }
64 + }
65 + .pickerStyle(.menu)
66 + if !app.network.config.isTestnet {
67 + Label("Mainnet moves real funds. Double-check every send.",
68 + systemImage: "exclamationmark.triangle.fill")
69 + .font(.callout)
70 + .foregroundStyle(.orange)
71 + }
72 + }
73 + .onChange(of: app.network) { _, newNetwork in
74 + rpcOverride = UserDefaults.standard.string(forKey: newNetwork.rpcOverrideKey) ?? ""
75 + }
76 + }
77 +
78 + // MARK: - Prices
79 +
80 + private var pricesSection: some View {
81 + VStack(alignment: .leading, spacing: 8) {
82 + Text("Fiat values").font(.headline)
83 + Toggle("Show fiat values (fetches prices from CoinGecko, keyless)", isOn: $app.pricesEnabled)
84 + if app.pricesEnabled {
85 + Picker("Currency", selection: $app.fiatCurrency) {
86 + ForEach(PriceService.fiatOptions, id: \.self) { Text($0).tag($0) }
87 + }
88 + .pickerStyle(.segmented)
89 + .frame(maxWidth: 260)
90 + }
91 + Text("Balances are always exact on-chain amounts; fiat values are display estimates. Turning this off removes the only non-blockchain network call.")
92 + .font(.caption)
93 + .foregroundStyle(.secondary)
94 + }
95 + }
96 +
97 + // MARK: - RPC
98 +
99 + private var rpcSection: some View {
100 + VStack(alignment: .leading, spacing: 8) {
101 + Text("Custom RPC for \(app.network.config.displayName)").font(.headline)
102 + Text("Leave empty to use the built-in keyless endpoints (\(app.network.config.rpcs.map(\.host!).joined(separator: ", "))) with automatic failover. A dedicated Alchemy/QuickNode URL is more reliable; no key is ever required to run OS Vault.")
103 + .font(.caption)
104 + .foregroundStyle(.secondary)
105 + HStack {
106 + TextField("https://…", text: $rpcOverride)
107 + .textFieldStyle(.roundedBorder)
108 + .autocorrectionDisabled()
109 + Button("Save") {
110 + let trimmed = rpcOverride.trimmingCharacters(in: .whitespacesAndNewlines)
111 + if trimmed.isEmpty {
112 + UserDefaults.standard.removeObject(forKey: app.network.rpcOverrideKey)
113 + } else {
114 + UserDefaults.standard.set(trimmed, forKey: app.network.rpcOverrideKey)
115 + }
116 + Task { await app.refreshBalances() }
117 + }
118 + }
119 + }
120 + }
121 +
122 + // MARK: - Export seed
123 +
124 + private var exportSection: some View {
125 + VStack(alignment: .leading, spacing: 8) {
126 + Text("Recovery phrase").font(.headline)
127 + if let exportedMnemonic {
128 + Text(exportedMnemonic)
129 + .font(.callout.monospaced())
130 + .textSelection(.enabled)
131 + .padding(10)
132 + .frame(maxWidth: .infinity, alignment: .leading)
133 + .background(Color.orange.opacity(0.12))
134 + .clipShape(RoundedRectangle(cornerRadius: 8))
135 + Button("Hide") {
136 + self.exportedMnemonic = nil
137 + exportPassword = ""
138 + }
139 + } else {
140 + Text("Reveals the 12 words that control your funds. Make sure nobody can see your screen.")
141 + .font(.caption)
142 + .foregroundStyle(.secondary)
143 + HStack {
144 + SecureField("Vault password", text: $exportPassword)
145 + .textFieldStyle(.roundedBorder)
146 + Button("Reveal") { export() }
147 + .disabled(exportPassword.isEmpty)
148 + }
149 + if let exportError {
150 + Text(exportError).foregroundStyle(.red).font(.callout)
151 + }
152 + }
153 + }
154 + }
155 +
156 + private func export() {
157 + exportError = nil
158 + let manager = app.keyManager
159 + let candidate = exportPassword
160 + Task {
161 + let result = await Task.detached {
162 + Result { try manager.exportMnemonic(password: candidate) }
163 + }.value
164 + switch result {
165 + case .success(let mnemonic): exportedMnemonic = mnemonic
166 + case .failure(let error): exportError = error.localizedDescription
167 + }
168 + }
169 + }
170 +
171 + // MARK: - Delete
172 +
173 + private var deleteSection: some View {
174 + VStack(alignment: .leading, spacing: 8) {
175 + Text("Danger zone").font(.headline).foregroundStyle(.red)
176 + Text("Deletes the encrypted vault from this Mac. Without your written recovery phrase, the funds are unrecoverable. Type DELETE to confirm.")
177 + .font(.caption)
178 + .foregroundStyle(.secondary)
179 + HStack {
180 + TextField("Type DELETE", text: $deleteConfirmation)
181 + .textFieldStyle(.roundedBorder)
182 + Button("Delete wallet", role: .destructive) {
183 + guard deleteConfirmation == "DELETE" else {
184 + deleteError = "Type DELETE (all caps) to confirm."
185 + return
186 + }
187 + do {
188 + try app.keyManager.deleteVault()
189 + dismiss()
190 + app.walletDeleted()
191 + } catch {
192 + deleteError = error.localizedDescription
193 + }
194 + }
195 + }
196 + if let deleteError {
197 + Text(deleteError).foregroundStyle(.red).font(.callout)
198 + }
199 + }
200 + }
201 +}
added Sources/OSVaultKit/Views/Shared.swift +51 −0
@@ -0,0 +1,51 @@
1 +//
2 +// Shared.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +
11 +/// Prominent badge so the user always knows which chain they are on.
12 +struct NetworkBadge: View {
13 + let network: Network
14 +
15 + var body: some View {
16 + Text(network.config.isTestnet ? "TESTNET · \(network.config.displayName)" : network.config.displayName)
17 + .font(.caption.weight(.bold))
18 + .padding(.horizontal, 10)
19 + .padding(.vertical, 4)
20 + .background(network.config.isTestnet ? Color.orange.opacity(0.25) : Color.blue.opacity(0.18))
21 + .foregroundStyle(network.config.isTestnet ? Color.orange : Color.blue)
22 + .clipShape(Capsule())
23 + }
24 +}
25 +
26 +extension String {
27 + /// "0x9858…da94" for tight UI spots.
28 + var shortAddress: String {
29 + guard count == 42 else { return self }
30 + return "\(prefix(6))\(suffix(4))"
31 + }
32 +}
33 +
34 +struct CopyButton: View {
35 + let text: String
36 + @State private var copied = false
37 +
38 + var body: some View {
39 + Button {
40 + NSPasteboard.general.clearContents()
41 + NSPasteboard.general.setString(text, forType: .string)
42 + copied = true
43 + Task {
44 + try? await Task.sleep(for: .seconds(1.5))
45 + copied = false
46 + }
47 + } label: {
48 + Label(copied ? "Copied" : "Copy", systemImage: copied ? "checkmark" : "doc.on.doc")
49 + }
50 + }
51 +}
added Sources/OSVaultKit/Views/Solana/SolanaView.swift +337 −0
@@ -0,0 +1,337 @@
1 +//
2 +// SolanaView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +import BigInt
11 +
12 +/// Solana panel: SOL + USDC balances, receive, send (with ATA-rent warning
13 +/// when the recipient has no USDC account yet), devnet/mainnet switch.
14 +/// Sends follow the vault flow: password → derive keypair → sign → discard.
15 +struct SolanaView: View {
16 + @EnvironmentObject var app: AppState
17 + @Environment(\.dismiss) private var dismiss
18 +
19 + enum Mode { case overview, receive, send }
20 + @State private var mode: Mode = .overview
21 +
22 + @State private var sendUSDC = true
23 + @State private var recipient = ""
24 + @State private var amountInput = ""
25 + @State private var prepared: SolanaService.PreparedSOLSend?
26 + @State private var password = ""
27 + @State private var sending = false
28 + @State private var sentSignature: String?
29 + @State private var errorMessage: String?
30 +
31 + var body: some View {
32 + VStack(alignment: .leading, spacing: 16) {
33 + header
34 + switch mode {
35 + case .overview: overview
36 + case .receive: receive
37 + case .send: send
38 + }
39 + }
40 + .padding(24)
41 + .frame(width: 470)
42 + }
43 +
44 + private var header: some View {
45 + HStack {
46 + Text("Solana").font(.title2.bold())
47 + Spacer()
48 + Text(app.solNetwork.isTestnet ? "DEVNET · test" : "MAINNET")
49 + .font(.caption.weight(.bold))
50 + .padding(.horizontal, 10).padding(.vertical, 4)
51 + .background(app.solNetwork.isTestnet ? Color.orange.opacity(0.25) : Color.purple.opacity(0.25))
52 + .foregroundStyle(app.solNetwork.isTestnet ? Color.orange : Color.purple)
53 + .clipShape(Capsule())
54 + Button("Done") { dismiss() }
55 + }
56 + }
57 +
58 + // MARK: - Overview
59 +
60 + private var overview: some View {
61 + VStack(alignment: .leading, spacing: 14) {
62 + VStack(alignment: .leading, spacing: 10) {
63 + HStack(alignment: .firstTextBaseline) {
64 + Text("USDC").font(.headline)
65 + Spacer()
66 + VStack(alignment: .trailing, spacing: 2) {
67 + Text(TokenAmount.format(BigUInt(app.solBalances?.usdcUnits ?? 0), decimals: 6))
68 + .font(.system(size: 26, weight: .bold, design: .rounded))
69 + .monospacedDigit()
70 + if let fiat = fiatLine(units: app.solBalances?.usdcUnits ?? 0, decimals: 6, symbol: "USDC") {
71 + Text(fiat).font(.caption).foregroundStyle(.secondary)
72 + }
73 + }
74 + }
75 + Divider()
76 + HStack {
77 + Text("SOL (fees)").font(.subheadline).foregroundStyle(.secondary)
78 + Spacer()
79 + VStack(alignment: .trailing, spacing: 2) {
80 + Text(SolanaService.formatSOL(app.solBalances?.lamports ?? 0) + " SOL")
81 + .font(.subheadline.monospaced())
82 + .foregroundStyle(.secondary)
83 + if let fiat = fiatLine(units: app.solBalances?.lamports ?? 0, decimals: 9, symbol: "SOL") {
84 + Text(fiat).font(.caption).foregroundStyle(.secondary)
85 + }
86 + }
87 + }
88 + if let error = app.solError {
89 + Label(error, systemImage: "wifi.exclamationmark")
90 + .font(.caption).foregroundStyle(.orange)
91 + }
92 + }
93 + .padding(14)
94 + .background(.quaternary.opacity(0.4))
95 + .clipShape(RoundedRectangle(cornerRadius: 10))
96 +
97 + HStack(spacing: 12) {
98 + Button {
99 + mode = .send
100 + } label: {
101 + Label("Send", systemImage: "arrow.up.circle.fill").frame(maxWidth: .infinity)
102 + }
103 + .buttonStyle(.borderedProminent)
104 + Button {
105 + mode = .receive
106 + } label: {
107 + Label("Receive", systemImage: "arrow.down.circle").frame(maxWidth: .infinity)
108 + }
109 + Button {
110 + Task { await app.refreshSolana() }
111 + } label: {
112 + Image(systemName: "arrow.clockwise")
113 + }
114 + .help("Refresh")
115 + }
116 +
117 + Text("ed25519 at m/44'/501'/0'/0' from your existing recovery phrase (Phantom-compatible). Fees are paid in SOL.")
118 + .font(.caption)
119 + .foregroundStyle(.secondary)
120 +
121 + Picker("Network", selection: Binding(
122 + get: { app.solNetwork },
123 + set: { newValue in Task { await app.switchSolanaNetwork(to: newValue) } }
124 + )) {
125 + ForEach(SolanaService.SOLNetwork.allCases, id: \.self) { network in
126 + Text(network.displayName).tag(network)
127 + }
128 + }
129 + .pickerStyle(.segmented)
130 + }
131 + }
132 +
133 + private func fiatLine(units: UInt64, decimals: Int, symbol: String) -> String? {
134 + guard app.pricesEnabled, units > 0, let price = app.fiatPrices[symbol] else { return nil }
135 + let value = PriceService.fiatValue(units: BigUInt(units), decimals: decimals, price: price)
136 + return "≈ " + PriceService.formatFiat(value, currency: app.fiatCurrency)
137 + }
138 +
139 + // MARK: - Receive
140 +
141 + private var receive: some View {
142 + VStack(spacing: 14) {
143 + if let address = app.solAddress {
144 + if let qr = QRCode.image(for: address) {
145 + Image(nsImage: qr)
146 + .interpolation(.none)
147 + .resizable()
148 + .frame(width: 200, height: 200)
149 + .background(.white)
150 + .clipShape(RoundedRectangle(cornerRadius: 8))
151 + }
152 + Text(address)
153 + .font(.callout.monospaced())
154 + .textSelection(.enabled)
155 + .padding(8)
156 + .background(.quaternary.opacity(0.4))
157 + .clipShape(RoundedRectangle(cornerRadius: 8))
158 + CopyButton(text: address)
159 + Text("One address for SOL and every SPL token on \(app.solNetwork.displayName).")
160 + .font(.caption).foregroundStyle(.secondary)
161 + }
162 + Button("Back") { mode = .overview }
163 + }
164 + .frame(maxWidth: .infinity)
165 + }
166 +
167 + // MARK: - Send
168 +
169 + private var send: some View {
170 + VStack(alignment: .leading, spacing: 12) {
171 + if let signature = sentSignature {
172 + sentView(signature)
173 + } else if let prepared {
174 + confirmView(prepared)
175 + } else {
176 + sendForm
177 + }
178 + }
179 + }
180 +
181 + private var sendForm: some View {
182 + VStack(alignment: .leading, spacing: 12) {
183 + Picker("Asset", selection: $sendUSDC) {
184 + Text("USDC").tag(true)
185 + Text("SOL").tag(false)
186 + }
187 + .pickerStyle(.segmented)
188 + TextField("Recipient (Solana address)", text: $recipient)
189 + .textFieldStyle(.roundedBorder)
190 + .font(.body.monospaced())
191 + .autocorrectionDisabled()
192 + if !recipient.isEmpty && !SolanaService.validate(address: recipient) {
193 + Label("Not a valid Solana address", systemImage: "xmark.circle")
194 + .font(.caption).foregroundStyle(.red)
195 + }
196 + HStack {
197 + TextField("Amount", text: $amountInput)
198 + .textFieldStyle(.roundedBorder)
199 + .font(.body.monospaced())
200 + Text(sendUSDC ? "USDC" : "SOL").foregroundStyle(.secondary)
201 + }
202 + Text(sendUSDC
203 + ? "Balance: \(TokenAmount.format(BigUInt(app.solBalances?.usdcUnits ?? 0), decimals: 6)) USDC"
204 + : "Balance: \(SolanaService.formatSOL(app.solBalances?.lamports ?? 0)) SOL")
205 + .font(.caption).foregroundStyle(.secondary)
206 + if let errorMessage {
207 + Text(errorMessage).foregroundStyle(.red).font(.callout)
208 + }
209 + HStack {
210 + Button("Back") { mode = .overview; errorMessage = nil }
211 + Spacer()
212 + Button("Review") { estimate() }
213 + .buttonStyle(.borderedProminent)
214 + .disabled(!formValid)
215 + }
216 + }
217 + }
218 +
219 + private var parsedAmount: UInt64? {
220 + sendUSDC ? SolanaService.parseUSDC(amountInput) : SolanaService.parseSOL(amountInput)
221 + }
222 +
223 + private var formValid: Bool {
224 + SolanaService.validate(address: recipient) && (parsedAmount ?? 0) > 0
225 + }
226 +
227 + private func estimate() {
228 + guard let amount = parsedAmount else { return }
229 + errorMessage = nil
230 + let to = recipient.trimmingCharacters(in: .whitespacesAndNewlines)
231 + let usdc = sendUSDC
232 + Task {
233 + do {
234 + prepared = try await app.solanaService.estimateSend(
235 + to: to, amountUnits: amount, isUSDC: usdc)
236 + } catch {
237 + errorMessage = error.localizedDescription
238 + }
239 + }
240 + }
241 +
242 + private func confirmView(_ p: SolanaService.PreparedSOLSend) -> some View {
243 + VStack(alignment: .leading, spacing: 12) {
244 + Text("Confirm transaction").font(.headline)
245 + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) {
246 + GridRow {
247 + Text("Recipient").foregroundStyle(.secondary)
248 + Text(p.recipient).font(.callout.monospaced())
249 + .textSelection(.enabled)
250 + .lineLimit(1).truncationMode(.middle)
251 + }
252 + GridRow {
253 + Text("Amount").foregroundStyle(.secondary)
254 + Text(p.isUSDC
255 + ? "\(TokenAmount.format(BigUInt(p.amountUnits), decimals: 6)) USDC"
256 + : "\(SolanaService.formatSOL(p.amountUnits)) SOL")
257 + .fontWeight(.semibold)
258 + }
259 + GridRow {
260 + Text("Network").foregroundStyle(.secondary)
261 + Text(p.network.displayName)
262 + }
263 + GridRow {
264 + Text("Est. fee").foregroundStyle(.secondary)
265 + Text("\(SolanaService.formatSOL(p.estimatedFeeLamports)) SOL")
266 + }
267 + }
268 + .font(.callout)
269 + if p.createsTokenAccount {
270 + Label("The recipient has no USDC account yet — you fund its creation (~0.002 SOL rent, included in the fee above).",
271 + systemImage: "info.circle")
272 + .font(.caption)
273 + .foregroundStyle(.orange)
274 + }
275 + Divider()
276 + SecureField("Vault password to sign", text: $password)
277 + .textFieldStyle(.roundedBorder)
278 + if let errorMessage {
279 + Text(errorMessage).foregroundStyle(.red).font(.callout)
280 + }
281 + HStack {
282 + Button("Back") {
283 + prepared = nil
284 + password = ""
285 + }
286 + Spacer()
287 + if sending { ProgressView().controlSize(.small) }
288 + Button("Sign & send") { broadcast(p) }
289 + .buttonStyle(.borderedProminent)
290 + .disabled(password.isEmpty || sending)
291 + }
292 + }
293 + }
294 +
295 + private func broadcast(_ p: SolanaService.PreparedSOLSend) {
296 + sending = true
297 + errorMessage = nil
298 + let candidate = password
299 + let manager = app.keyManager
300 + Task {
301 + do {
302 + let mnemonic = try await Task.detached {
303 + try manager.unlock(password: candidate).mnemonic
304 + }.value
305 + let signature = try await app.solanaService.send(p, mnemonic: mnemonic)
306 + password = ""
307 + sentSignature = signature
308 + await app.refreshSolana()
309 + } catch {
310 + errorMessage = error.localizedDescription
311 + }
312 + sending = false
313 + }
314 + }
315 +
316 + private func sentView(_ signature: String) -> some View {
317 + VStack(spacing: 12) {
318 + Image(systemName: "paperplane.circle.fill")
319 + .font(.system(size: 38)).foregroundStyle(.green)
320 + Text("Transaction sent").font(.headline)
321 + Text(signature)
322 + .font(.caption.monospaced())
323 + .textSelection(.enabled)
324 + .lineLimit(1).truncationMode(.middle)
325 + Link("View on Solana Explorer", destination: app.solNetwork.explorerTxURL(signature))
326 + Button("Done") {
327 + sentSignature = nil
328 + prepared = nil
329 + recipient = ""
330 + amountInput = ""
331 + mode = .overview
332 + }
333 + .buttonStyle(.borderedProminent)
334 + }
335 + .frame(maxWidth: .infinity)
336 + }
337 +}
added Sources/OSVaultKit/Views/TON/TONView.swift +345 −0
@@ -0,0 +1,345 @@
1 +//
2 +// TONView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +import BigInt
11 +
12 +/// TON panel: TON + USDT (jetton) balances, receive, send, testnet/mainnet
13 +/// switch. USDT lives on mainnet only (no official testnet jetton).
14 +struct TONView: View {
15 + @EnvironmentObject var app: AppState
16 + @Environment(\.dismiss) private var dismiss
17 +
18 + enum Mode { case overview, receive, send }
19 + @State private var mode: Mode = .overview
20 +
21 + @State private var sendUSDT = false
22 + @State private var recipient = ""
23 + @State private var amountInput = ""
24 + @State private var prepared: TONService.PreparedTONSend?
25 + @State private var password = ""
26 + @State private var busy = false
27 + @State private var sentRef: String?
28 + @State private var errorMessage: String?
29 +
30 + var body: some View {
31 + VStack(alignment: .leading, spacing: 16) {
32 + header
33 + switch mode {
34 + case .overview: overview
35 + case .receive: receive
36 + case .send: send
37 + }
38 + }
39 + .padding(24)
40 + .frame(width: 470)
41 + }
42 +
43 + private var header: some View {
44 + HStack {
45 + Text("TON").font(.title2.bold())
46 + Spacer()
47 + Text(app.tonNetwork.isTestnet ? "TESTNET" : "MAINNET")
48 + .font(.caption.weight(.bold))
49 + .padding(.horizontal, 10).padding(.vertical, 4)
50 + .background(app.tonNetwork.isTestnet ? Color.orange.opacity(0.25) : Color.cyan.opacity(0.2))
51 + .foregroundStyle(app.tonNetwork.isTestnet ? Color.orange : Color.cyan)
52 + .clipShape(Capsule())
53 + Button("Done") { dismiss() }
54 + }
55 + }
56 +
57 + // MARK: - Overview
58 +
59 + private var overview: some View {
60 + VStack(alignment: .leading, spacing: 14) {
61 + VStack(alignment: .leading, spacing: 10) {
62 + if app.tonNetwork.usdtAvailable {
63 + HStack(alignment: .firstTextBaseline) {
64 + Text("USDT").font(.headline)
65 + Spacer()
66 + VStack(alignment: .trailing, spacing: 2) {
67 + Text(TokenAmount.format(BigUInt(app.tonBalancesState?.usdtUnits ?? 0), decimals: 6))
68 + .font(.system(size: 26, weight: .bold, design: .rounded))
69 + .monospacedDigit()
70 + if let fiat = fiatLine(units: app.tonBalancesState?.usdtUnits ?? 0, decimals: 6, symbol: "USDT") {
71 + Text(fiat).font(.caption).foregroundStyle(.secondary)
72 + }
73 + }
74 + }
75 + Divider()
76 + }
77 + HStack {
78 + Text("TON (fees)").font(.subheadline).foregroundStyle(.secondary)
79 + Spacer()
80 + VStack(alignment: .trailing, spacing: 2) {
81 + Text(TONService.formatTON(app.tonBalancesState?.nanotons ?? 0) + " TON")
82 + .font(.subheadline.monospaced())
83 + .foregroundStyle(.secondary)
84 + if let fiat = fiatLine(units: app.tonBalancesState?.nanotons ?? 0, decimals: 9, symbol: "TON") {
85 + Text(fiat).font(.caption).foregroundStyle(.secondary)
86 + }
87 + }
88 + }
89 + if app.tonBalancesState?.deployed == false, (app.tonBalancesState?.nanotons ?? 0) > 0 {
90 + Text("Wallet contract deploys automatically with your first send.")
91 + .font(.caption).foregroundStyle(.secondary)
92 + }
93 + if let error = app.tonError {
94 + Label(error, systemImage: "wifi.exclamationmark")
95 + .font(.caption).foregroundStyle(.orange)
96 + }
97 + }
98 + .padding(14)
99 + .background(.quaternary.opacity(0.4))
100 + .clipShape(RoundedRectangle(cornerRadius: 10))
101 +
102 + HStack(spacing: 12) {
103 + Button {
104 + mode = .send
105 + } label: {
106 + Label("Send", systemImage: "arrow.up.circle.fill").frame(maxWidth: .infinity)
107 + }
108 + .buttonStyle(.borderedProminent)
109 + Button {
110 + mode = .receive
111 + } label: {
112 + Label("Receive", systemImage: "arrow.down.circle").frame(maxWidth: .infinity)
113 + }
114 + Button {
115 + Task { await app.refreshTON() }
116 + } label: {
117 + Image(systemName: "arrow.clockwise")
118 + }
119 + .help("Refresh")
120 + }
121 +
122 + Text("ed25519 (wallet v4R2) from your existing recovery phrase — note: Tonkeeper's default import expects TON-native 24-word phrases, not BIP-39. USDT is a jetton: sends attach ~0.07 TON for fees, the unused part is refunded.")
123 + .font(.caption)
124 + .foregroundStyle(.secondary)
125 +
126 + Picker("Network", selection: Binding(
127 + get: { app.tonNetwork },
128 + set: { newValue in Task { await app.switchTONNetwork(to: newValue) } }
129 + )) {
130 + ForEach(TONService.TONNetwork.allCases, id: \.self) { network in
131 + Text(network.displayName).tag(network)
132 + }
133 + }
134 + .pickerStyle(.segmented)
135 + }
136 + }
137 +
138 + private func fiatLine(units: UInt64, decimals: Int, symbol: String) -> String? {
139 + guard app.pricesEnabled, units > 0, let price = app.fiatPrices[symbol] else { return nil }
140 + let value = PriceService.fiatValue(units: BigUInt(units), decimals: decimals, price: price)
141 + return "≈ " + PriceService.formatFiat(value, currency: app.fiatCurrency)
142 + }
143 +
144 + // MARK: - Receive
145 +
146 + private var receive: some View {
147 + VStack(spacing: 14) {
148 + if let address = app.tonAddress {
149 + if let qr = QRCode.image(for: address) {
150 + Image(nsImage: qr)
151 + .interpolation(.none)
152 + .resizable()
153 + .frame(width: 200, height: 200)
154 + .background(.white)
155 + .clipShape(RoundedRectangle(cornerRadius: 8))
156 + }
157 + Text(address)
158 + .font(.callout.monospaced())
159 + .textSelection(.enabled)
160 + .padding(8)
161 + .background(.quaternary.opacity(0.4))
162 + .clipShape(RoundedRectangle(cornerRadius: 8))
163 + CopyButton(text: address)
164 + Text("One address for TON and every jetton on \(app.tonNetwork.displayName).")
165 + .font(.caption).foregroundStyle(.secondary)
166 + }
167 + Button("Back") { mode = .overview }
168 + }
169 + .frame(maxWidth: .infinity)
170 + }
171 +
172 + // MARK: - Send
173 +
174 + private var send: some View {
175 + VStack(alignment: .leading, spacing: 12) {
176 + if let ref = sentRef {
177 + sentView(ref)
178 + } else if let prepared {
179 + confirmView(prepared)
180 + } else {
181 + sendForm
182 + }
183 + }
184 + }
185 +
186 + private var sendForm: some View {
187 + VStack(alignment: .leading, spacing: 12) {
188 + if app.tonNetwork.usdtAvailable {
189 + Picker("Asset", selection: $sendUSDT) {
190 + Text("TON").tag(false)
191 + Text("USDT").tag(true)
192 + }
193 + .pickerStyle(.segmented)
194 + }
195 + TextField("Recipient (UQ… / EQ…)", text: $recipient)
196 + .textFieldStyle(.roundedBorder)
197 + .font(.body.monospaced())
198 + .autocorrectionDisabled()
199 + if !recipient.isEmpty && !TONService.validate(address: recipient) {
200 + Label("Not a valid TON address", systemImage: "xmark.circle")
201 + .font(.caption).foregroundStyle(.red)
202 + }
203 + HStack {
204 + TextField("Amount", text: $amountInput)
205 + .textFieldStyle(.roundedBorder)
206 + .font(.body.monospaced())
207 + Text(sendUSDT ? "USDT" : "TON").foregroundStyle(.secondary)
208 + }
209 + Text(sendUSDT
210 + ? "Balance: \(TokenAmount.format(BigUInt(app.tonBalancesState?.usdtUnits ?? 0), decimals: 6)) USDT"
211 + : "Balance: \(TONService.formatTON(app.tonBalancesState?.nanotons ?? 0)) TON")
212 + .font(.caption).foregroundStyle(.secondary)
213 + if let errorMessage {
214 + Text(errorMessage).foregroundStyle(.red).font(.callout)
215 + }
216 + HStack {
217 + Button("Back") { mode = .overview; errorMessage = nil }
218 + Spacer()
219 + if busy { ProgressView().controlSize(.small) }
220 + Button("Review") { estimate() }
221 + .buttonStyle(.borderedProminent)
222 + .disabled(!formValid || busy)
223 + }
224 + }
225 + }
226 +
227 + private var parsedAmount: UInt64? {
228 + sendUSDT ? TONService.parseUSDT(amountInput) : TONService.parseTON(amountInput)
229 + }
230 +
231 + private var formValid: Bool {
232 + TONService.validate(address: recipient) && (parsedAmount ?? 0) > 0
233 + }
234 +
235 + private func estimate() {
236 + guard let amount = parsedAmount else { return }
237 + errorMessage = nil
238 + busy = true
239 + let to = recipient.trimmingCharacters(in: .whitespacesAndNewlines)
240 + let usdt = sendUSDT
241 + Task {
242 + do {
243 + prepared = try await app.tonService.estimateSend(
244 + to: to, amountUnits: amount, isUSDT: usdt)
245 + } catch {
246 + errorMessage = error.localizedDescription
247 + }
248 + busy = false
249 + }
250 + }
251 +
252 + private func confirmView(_ p: TONService.PreparedTONSend) -> some View {
253 + VStack(alignment: .leading, spacing: 12) {
254 + Text("Confirm transaction").font(.headline)
255 + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) {
256 + GridRow {
257 + Text("Recipient").foregroundStyle(.secondary)
258 + Text(p.recipient).font(.callout.monospaced())
259 + .textSelection(.enabled)
260 + .lineLimit(1).truncationMode(.middle)
261 + }
262 + GridRow {
263 + Text("Amount").foregroundStyle(.secondary)
264 + Text(p.isUSDT
265 + ? "\(TokenAmount.format(BigUInt(p.amountUnits), decimals: 6)) USDT"
266 + : "\(TONService.formatTON(p.amountUnits)) TON")
267 + .fontWeight(.semibold)
268 + }
269 + GridRow {
270 + Text("Network").foregroundStyle(.secondary)
271 + Text(p.network.displayName)
272 + }
273 + GridRow {
274 + Text("Est. fee").foregroundStyle(.secondary)
275 + Text("≈ \(TONService.formatTON(p.estimatedFeeNanotons)) TON" + (p.isUSDT ? " (excess refunded)" : ""))
276 + }
277 + }
278 + .font(.callout)
279 + Divider()
280 + SecureField("Vault password to sign", text: $password)
281 + .textFieldStyle(.roundedBorder)
282 + if let errorMessage {
283 + Text(errorMessage).foregroundStyle(.red).font(.callout)
284 + }
285 + HStack {
286 + Button("Back") {
287 + prepared = nil
288 + password = ""
289 + }
290 + Spacer()
291 + if busy { ProgressView().controlSize(.small) }
292 + Button("Sign & send") { broadcast(p) }
293 + .buttonStyle(.borderedProminent)
294 + .disabled(password.isEmpty || busy)
295 + }
296 + }
297 + }
298 +
299 + private func broadcast(_ p: TONService.PreparedTONSend) {
300 + busy = true
301 + errorMessage = nil
302 + let candidate = password
303 + let manager = app.keyManager
304 + Task {
305 + do {
306 + let mnemonic = try await Task.detached {
307 + try manager.unlock(password: candidate).mnemonic
308 + }.value
309 + let ref = try await app.tonService.send(p, mnemonic: mnemonic)
310 + password = ""
311 + sentRef = ref
312 + await app.refreshTON()
313 + } catch {
314 + errorMessage = error.localizedDescription
315 + }
316 + busy = false
317 + }
318 + }
319 +
320 + private func sentView(_ ref: String) -> some View {
321 + VStack(spacing: 12) {
322 + Image(systemName: "paperplane.circle.fill")
323 + .font(.system(size: 38)).foregroundStyle(.green)
324 + Text("Transaction sent").font(.headline)
325 + Text("It will appear on the explorer within seconds.")
326 + .font(.callout).foregroundStyle(.secondary)
327 + if let address = app.tonAddress {
328 + Link("View account on Tonviewer", destination: app.tonNetwork.explorerAddressURL(address))
329 + }
330 + Button("Done") {
331 + sentRef = nil
332 + prepared = nil
333 + recipient = ""
334 + amountInput = ""
335 + mode = .overview
336 + }
337 + .buttonStyle(.borderedProminent)
338 + }
339 + .frame(maxWidth: .infinity)
340 + }
341 +}
342 +
343 +extension TONService.TONNetwork {
344 + var usdtAvailable: Bool { usdtMaster != nil }
345 +}
added Sources/OSVaultKit/Views/Tron/TronView.swift +340 −0
@@ -0,0 +1,340 @@
1 +//
2 +// TronView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +import BigInt
11 +
12 +/// Tron panel: USDT (TRC-20) + TRX balances, receive, send with the energy
13 +/// burn estimate surfaced before signing, Nile/mainnet switch.
14 +struct TronView: View {
15 + @EnvironmentObject var app: AppState
16 + @Environment(\.dismiss) private var dismiss
17 +
18 + enum Mode { case overview, receive, send }
19 + @State private var mode: Mode = .overview
20 +
21 + @State private var sendUSDT = true
22 + @State private var recipient = ""
23 + @State private var amountInput = ""
24 + @State private var prepared: TronService.PreparedTronSend?
25 + @State private var password = ""
26 + @State private var sending = false
27 + @State private var estimating = false
28 + @State private var sentTxid: String?
29 + @State private var errorMessage: String?
30 +
31 + var body: some View {
32 + VStack(alignment: .leading, spacing: 16) {
33 + header
34 + switch mode {
35 + case .overview: overview
36 + case .receive: receive
37 + case .send: send
38 + }
39 + }
40 + .padding(24)
41 + .frame(width: 470)
42 + }
43 +
44 + private var header: some View {
45 + HStack {
46 + Text("Tron").font(.title2.bold())
47 + Spacer()
48 + Text(app.tronNetwork.isTestnet ? "NILE · test" : "MAINNET")
49 + .font(.caption.weight(.bold))
50 + .padding(.horizontal, 10).padding(.vertical, 4)
51 + .background(app.tronNetwork.isTestnet ? Color.orange.opacity(0.25) : Color.red.opacity(0.22))
52 + .foregroundStyle(app.tronNetwork.isTestnet ? Color.orange : Color.red)
53 + .clipShape(Capsule())
54 + Button("Done") { dismiss() }
55 + }
56 + }
57 +
58 + // MARK: - Overview
59 +
60 + private var overview: some View {
61 + VStack(alignment: .leading, spacing: 14) {
62 + VStack(alignment: .leading, spacing: 10) {
63 + HStack(alignment: .firstTextBaseline) {
64 + Text("USDT").font(.headline)
65 + Spacer()
66 + VStack(alignment: .trailing, spacing: 2) {
67 + Text(TokenAmount.format(BigUInt(app.tronBalances?.usdtUnits ?? 0), decimals: 6))
68 + .font(.system(size: 26, weight: .bold, design: .rounded))
69 + .monospacedDigit()
70 + if let fiat = fiatLine(units: app.tronBalances?.usdtUnits ?? 0, decimals: 6, symbol: "USDT") {
71 + Text(fiat).font(.caption).foregroundStyle(.secondary)
72 + }
73 + }
74 + }
75 + Divider()
76 + HStack {
77 + Text("TRX (fees)").font(.subheadline).foregroundStyle(.secondary)
78 + Spacer()
79 + VStack(alignment: .trailing, spacing: 2) {
80 + Text(TronService.formatTRX(app.tronBalances?.trxSun ?? 0) + " TRX")
81 + .font(.subheadline.monospaced())
82 + .foregroundStyle(.secondary)
83 + if let fiat = fiatLine(units: app.tronBalances?.trxSun ?? 0, decimals: 6, symbol: "TRX") {
84 + Text(fiat).font(.caption).foregroundStyle(.secondary)
85 + }
86 + }
87 + }
88 + if let error = app.tronError {
89 + Label(error, systemImage: "wifi.exclamationmark")
90 + .font(.caption).foregroundStyle(.orange)
91 + }
92 + }
93 + .padding(14)
94 + .background(.quaternary.opacity(0.4))
95 + .clipShape(RoundedRectangle(cornerRadius: 10))
96 +
97 + HStack(spacing: 12) {
98 + Button {
99 + mode = .send
100 + } label: {
101 + Label("Send", systemImage: "arrow.up.circle.fill").frame(maxWidth: .infinity)
102 + }
103 + .buttonStyle(.borderedProminent)
104 + Button {
105 + mode = .receive
106 + } label: {
107 + Label("Receive", systemImage: "arrow.down.circle").frame(maxWidth: .infinity)
108 + }
109 + Button {
110 + Task { await app.refreshTron() }
111 + } label: {
112 + Image(systemName: "arrow.clockwise")
113 + }
114 + .help("Refresh")
115 + }
116 +
117 + Text("secp256k1 at m/44'/195'/0'/0/0 from your existing recovery phrase. USDT transfers burn TRX for energy (~13–27 TRX without staked energy) — the exact estimate is shown before you sign.")
118 + .font(.caption)
119 + .foregroundStyle(.secondary)
120 +
121 + Picker("Network", selection: Binding(
122 + get: { app.tronNetwork },
123 + set: { newValue in Task { await app.switchTronNetwork(to: newValue) } }
124 + )) {
125 + ForEach(TronService.TronNetwork.allCases, id: \.self) { network in
126 + Text(network.displayName).tag(network)
127 + }
128 + }
129 + .pickerStyle(.segmented)
130 + }
131 + }
132 +
133 + private func fiatLine(units: UInt64, decimals: Int, symbol: String) -> String? {
134 + guard app.pricesEnabled, units > 0, let price = app.fiatPrices[symbol] else { return nil }
135 + let value = PriceService.fiatValue(units: BigUInt(units), decimals: decimals, price: price)
136 + return "≈ " + PriceService.formatFiat(value, currency: app.fiatCurrency)
137 + }
138 +
139 + // MARK: - Receive
140 +
141 + private var receive: some View {
142 + VStack(spacing: 14) {
143 + if let address = app.tronAddress {
144 + if let qr = QRCode.image(for: address) {
145 + Image(nsImage: qr)
146 + .interpolation(.none)
147 + .resizable()
148 + .frame(width: 200, height: 200)
149 + .background(.white)
150 + .clipShape(RoundedRectangle(cornerRadius: 8))
151 + }
152 + Text(address)
153 + .font(.callout.monospaced())
154 + .textSelection(.enabled)
155 + .padding(8)
156 + .background(.quaternary.opacity(0.4))
157 + .clipShape(RoundedRectangle(cornerRadius: 8))
158 + CopyButton(text: address)
159 + Text("One address for TRX and every TRC-20 token on \(app.tronNetwork.displayName).")
160 + .font(.caption).foregroundStyle(.secondary)
161 + }
162 + Button("Back") { mode = .overview }
163 + }
164 + .frame(maxWidth: .infinity)
165 + }
166 +
167 + // MARK: - Send
168 +
169 + private var send: some View {
170 + VStack(alignment: .leading, spacing: 12) {
171 + if let txid = sentTxid {
172 + sentView(txid)
173 + } else if let prepared {
174 + confirmView(prepared)
175 + } else {
176 + sendForm
177 + }
178 + }
179 + }
180 +
181 + private var sendForm: some View {
182 + VStack(alignment: .leading, spacing: 12) {
183 + Picker("Asset", selection: $sendUSDT) {
184 + Text("USDT").tag(true)
185 + Text("TRX").tag(false)
186 + }
187 + .pickerStyle(.segmented)
188 + TextField("Recipient (T…)", text: $recipient)
189 + .textFieldStyle(.roundedBorder)
190 + .font(.body.monospaced())
191 + .autocorrectionDisabled()
192 + if !recipient.isEmpty && !TronService.validate(address: recipient) {
193 + Label("Not a valid Tron address", systemImage: "xmark.circle")
194 + .font(.caption).foregroundStyle(.red)
195 + }
196 + HStack {
197 + TextField("Amount", text: $amountInput)
198 + .textFieldStyle(.roundedBorder)
199 + .font(.body.monospaced())
200 + Text(sendUSDT ? "USDT" : "TRX").foregroundStyle(.secondary)
201 + }
202 + Text(sendUSDT
203 + ? "Balance: \(TokenAmount.format(BigUInt(app.tronBalances?.usdtUnits ?? 0), decimals: 6)) USDT"
204 + : "Balance: \(TronService.formatTRX(app.tronBalances?.trxSun ?? 0)) TRX")
205 + .font(.caption).foregroundStyle(.secondary)
206 + if let errorMessage {
207 + Text(errorMessage).foregroundStyle(.red).font(.callout)
208 + }
209 + HStack {
210 + Button("Back") { mode = .overview; errorMessage = nil }
211 + Spacer()
212 + if estimating { ProgressView().controlSize(.small) }
213 + Button("Review") { estimate() }
214 + .buttonStyle(.borderedProminent)
215 + .disabled(!formValid || estimating)
216 + }
217 + }
218 + }
219 +
220 + private var parsedAmount: UInt64? {
221 + sendUSDT ? TronService.parseUSDT(amountInput) : TronService.parseTRX(amountInput)
222 + }
223 +
224 + private var formValid: Bool {
225 + TronService.validate(address: recipient) && (parsedAmount ?? 0) > 0
226 + }
227 +
228 + private func estimate() {
229 + guard let amount = parsedAmount else { return }
230 + errorMessage = nil
231 + estimating = true
232 + let to = recipient.trimmingCharacters(in: .whitespacesAndNewlines)
233 + let usdt = sendUSDT
234 + Task {
235 + do {
236 + prepared = try await app.tronService.estimateSend(
237 + to: to, amountUnits: amount, isUSDT: usdt)
238 + } catch {
239 + errorMessage = error.localizedDescription
240 + }
241 + estimating = false
242 + }
243 + }
244 +
245 + private func confirmView(_ p: TronService.PreparedTronSend) -> some View {
246 + VStack(alignment: .leading, spacing: 12) {
247 + Text("Confirm transaction").font(.headline)
248 + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) {
249 + GridRow {
250 + Text("Recipient").foregroundStyle(.secondary)
251 + Text(p.recipient).font(.callout.monospaced())
252 + .textSelection(.enabled)
253 + .lineLimit(1).truncationMode(.middle)
254 + }
255 + GridRow {
256 + Text("Amount").foregroundStyle(.secondary)
257 + Text(p.isUSDT
258 + ? "\(TokenAmount.format(BigUInt(p.amountUnits), decimals: 6)) USDT"
259 + : "\(TronService.formatTRX(p.amountUnits)) TRX")
260 + .fontWeight(.semibold)
261 + }
262 + GridRow {
263 + Text("Network").foregroundStyle(.secondary)
264 + Text(p.network.displayName)
265 + }
266 + GridRow {
267 + Text("Est. fee").foregroundStyle(.secondary)
268 + Text("≤ \(TronService.formatTRX(p.estimatedFeeSun)) TRX (burned)")
269 + }
270 + }
271 + .font(.callout)
272 + if p.isUSDT, (app.tronBalances?.trxSun ?? 0) < p.estimatedFeeSun {
273 + Label("Not enough TRX to cover the energy burn. Top up TRX first.",
274 + systemImage: "exclamationmark.triangle")
275 + .font(.caption)
276 + .foregroundStyle(.red)
277 + }
278 + Divider()
279 + SecureField("Vault password to sign", text: $password)
280 + .textFieldStyle(.roundedBorder)
281 + if let errorMessage {
282 + Text(errorMessage).foregroundStyle(.red).font(.callout)
283 + }
284 + HStack {
285 + Button("Back") {
286 + prepared = nil
287 + password = ""
288 + }
289 + Spacer()
290 + if sending { ProgressView().controlSize(.small) }
291 + Button("Sign & send") { broadcast(p) }
292 + .buttonStyle(.borderedProminent)
293 + .disabled(password.isEmpty || sending)
294 + }
295 + }
296 + }
297 +
298 + private func broadcast(_ p: TronService.PreparedTronSend) {
299 + sending = true
300 + errorMessage = nil
301 + let candidate = password
302 + let manager = app.keyManager
303 + Task {
304 + do {
305 + let mnemonic = try await Task.detached {
306 + try manager.unlock(password: candidate).mnemonic
307 + }.value
308 + let txid = try await app.tronService.send(p, mnemonic: mnemonic)
309 + password = ""
310 + sentTxid = txid
311 + await app.refreshTron()
312 + } catch {
313 + errorMessage = error.localizedDescription
314 + }
315 + sending = false
316 + }
317 + }
318 +
319 + private func sentView(_ txid: String) -> some View {
320 + VStack(spacing: 12) {
321 + Image(systemName: "paperplane.circle.fill")
322 + .font(.system(size: 38)).foregroundStyle(.green)
323 + Text("Transaction sent").font(.headline)
324 + Text(txid)
325 + .font(.caption.monospaced())
326 + .textSelection(.enabled)
327 + .lineLimit(1).truncationMode(.middle)
328 + Link("View on Tronscan", destination: app.tronNetwork.explorerTxURL(txid))
329 + Button("Done") {
330 + sentTxid = nil
331 + prepared = nil
332 + recipient = ""
333 + amountInput = ""
334 + mode = .overview
335 + }
336 + .buttonStyle(.borderedProminent)
337 + }
338 + .frame(maxWidth: .infinity)
339 + }
340 +}
added Sources/OSVaultKit/Views/XRPL/XRPLView.swift +389 −0
@@ -0,0 +1,389 @@
1 +//
2 +// XRPLView.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import SwiftUI
10 +import BigInt
11 +
12 +/// XRP Ledger panel: XRP + RLUSD balances (reserve shown as locked), receive,
13 +/// send with trustline checks, one-tap RLUSD trustline, testnet/mainnet switch.
14 +struct XRPLView: View {
15 + @EnvironmentObject var app: AppState
16 + @Environment(\.dismiss) private var dismiss
17 +
18 + enum Mode { case overview, receive, send }
19 + @State private var mode: Mode = .overview
20 +
21 + @State private var sendRLUSD = false
22 + @State private var recipient = ""
23 + @State private var amountInput = ""
24 + @State private var prepared: XRPLService.PreparedXRPLSend?
25 + @State private var password = ""
26 + @State private var trustlinePassword = ""
27 + @State private var showTrustline = false
28 + @State private var busy = false
29 + @State private var sentHash: String?
30 + @State private var errorMessage: String?
31 +
32 + var body: some View {
33 + VStack(alignment: .leading, spacing: 16) {
34 + header
35 + switch mode {
36 + case .overview: overview
37 + case .receive: receive
38 + case .send: send
39 + }
40 + }
41 + .padding(24)
42 + .frame(width: 470)
43 + }
44 +
45 + private var header: some View {
46 + HStack {
47 + Text("XRP Ledger").font(.title2.bold())
48 + Spacer()
49 + Text(app.xrplNetwork.isTestnet ? "TESTNET" : "MAINNET")
50 + .font(.caption.weight(.bold))
51 + .padding(.horizontal, 10).padding(.vertical, 4)
52 + .background(app.xrplNetwork.isTestnet ? Color.orange.opacity(0.25) : Color.blue.opacity(0.2))
53 + .foregroundStyle(app.xrplNetwork.isTestnet ? Color.orange : Color.blue)
54 + .clipShape(Capsule())
55 + Button("Done") { dismiss() }
56 + }
57 + }
58 +
59 + // MARK: - Overview
60 +
61 + private var overview: some View {
62 + VStack(alignment: .leading, spacing: 14) {
63 + VStack(alignment: .leading, spacing: 10) {
64 + HStack(alignment: .firstTextBaseline) {
65 + Text("XRP").font(.headline)
66 + Spacer()
67 + VStack(alignment: .trailing, spacing: 2) {
68 + Text(XRPLService.formatXRP(app.xrplBalances?.drops ?? 0))
69 + .font(.system(size: 26, weight: .bold, design: .rounded))
70 + .monospacedDigit()
71 + if let fiat = fiatLine(units: app.xrplBalances?.drops ?? 0, decimals: 6, symbol: "XRP") {
72 + Text(fiat).font(.caption).foregroundStyle(.secondary)
73 + }
74 + }
75 + }
76 + if let balances = app.xrplBalances, balances.accountExists {
77 + Text("Spendable: \(XRPLService.formatXRP(balances.spendableDrops)) XRP (\(XRPLService.formatXRP(balances.reserveDrops)) locked as reserve)")
78 + .font(.caption).foregroundStyle(.secondary)
79 + }
80 + Divider()
81 + HStack(alignment: .firstTextBaseline) {
82 + Text("RLUSD").font(.headline)
83 + Spacer()
84 + if app.xrplBalances?.hasRLUSDTrustline == true {
85 + Text(app.xrplBalances?.rlusdValue ?? "0")
86 + .font(.title3.weight(.semibold)).monospacedDigit()
87 + } else {
88 + Text("no trustline").font(.callout).foregroundStyle(.secondary)
89 + }
90 + }
91 + if app.xrplBalances?.accountExists == false {
92 + Label("Account not funded yet — the first deposit must be at least 1 XRP.",
93 + systemImage: "info.circle")
94 + .font(.caption).foregroundStyle(.orange)
95 + }
96 + if let error = app.xrplError {
97 + Label(error, systemImage: "wifi.exclamationmark")
98 + .font(.caption).foregroundStyle(.orange)
99 + }
100 + }
101 + .padding(14)
102 + .background(.quaternary.opacity(0.4))
103 + .clipShape(RoundedRectangle(cornerRadius: 10))
104 +
105 + HStack(spacing: 12) {
106 + Button {
107 + mode = .send
108 + } label: {
109 + Label("Send", systemImage: "arrow.up.circle.fill").frame(maxWidth: .infinity)
110 + }
111 + .buttonStyle(.borderedProminent)
112 + Button {
113 + mode = .receive
114 + } label: {
115 + Label("Receive", systemImage: "arrow.down.circle").frame(maxWidth: .infinity)
116 + }
117 + Button {
118 + Task { await app.refreshXRPL() }
119 + } label: {
120 + Image(systemName: "arrow.clockwise")
121 + }
122 + .help("Refresh")
123 + }
124 +
125 + if app.xrplBalances?.hasRLUSDTrustline != true, app.xrplBalances?.accountExists == true {
126 + DisclosureGroup("Enable RLUSD (create trustline)", isExpanded: $showTrustline) {
127 + VStack(alignment: .leading, spacing: 8) {
128 + Text("A one-time transaction that lets this account hold RLUSD. Locks 0.2 XRP of reserve.")
129 + .font(.caption).foregroundStyle(.secondary)
130 + HStack {
131 + SecureField("Vault password", text: $trustlinePassword)
132 + .textFieldStyle(.roundedBorder)
133 + Button("Enable") { createTrustline() }
134 + .disabled(trustlinePassword.isEmpty || busy)
135 + }
136 + if let errorMessage {
137 + Text(errorMessage).foregroundStyle(.red).font(.callout)
138 + }
139 + }
140 + .padding(.top, 6)
141 + }
142 + .font(.callout)
143 + }
144 +
145 + Text("secp256k1 at m/44'/144'/0'/0/0 from your existing recovery phrase. Fees are ~12 drops (0.000012 XRP).")
146 + .font(.caption)
147 + .foregroundStyle(.secondary)
148 +
149 + Picker("Network", selection: Binding(
150 + get: { app.xrplNetwork },
151 + set: { newValue in Task { await app.switchXRPLNetwork(to: newValue) } }
152 + )) {
153 + ForEach(XRPLService.XRPLNetwork.allCases, id: \.self) { network in
154 + Text(network.displayName).tag(network)
155 + }
156 + }
157 + .pickerStyle(.segmented)
158 + }
159 + }
160 +
161 + private func fiatLine(units: UInt64, decimals: Int, symbol: String) -> String? {
162 + guard app.pricesEnabled, units > 0, let price = app.fiatPrices[symbol] else { return nil }
163 + let value = PriceService.fiatValue(units: BigUInt(units), decimals: decimals, price: price)
164 + return "≈ " + PriceService.formatFiat(value, currency: app.fiatCurrency)
165 + }
166 +
167 + private func createTrustline() {
168 + busy = true
169 + errorMessage = nil
170 + let candidate = trustlinePassword
171 + let manager = app.keyManager
172 + Task {
173 + do {
174 + let mnemonic = try await Task.detached {
175 + try manager.unlock(password: candidate).mnemonic
176 + }.value
177 + _ = try await app.xrplService.createRLUSDTrustline(mnemonic: mnemonic)
178 + trustlinePassword = ""
179 + showTrustline = false
180 + await app.refreshXRPL()
181 + } catch {
182 + errorMessage = error.localizedDescription
183 + }
184 + busy = false
185 + }
186 + }
187 +
188 + // MARK: - Receive
189 +
190 + private var receive: some View {
191 + VStack(spacing: 14) {
192 + if let address = app.xrplAddress {
193 + if let qr = QRCode.image(for: address) {
194 + Image(nsImage: qr)
195 + .interpolation(.none)
196 + .resizable()
197 + .frame(width: 200, height: 200)
198 + .background(.white)
199 + .clipShape(RoundedRectangle(cornerRadius: 8))
200 + }
201 + Text(address)
202 + .font(.callout.monospaced())
203 + .textSelection(.enabled)
204 + .padding(8)
205 + .background(.quaternary.opacity(0.4))
206 + .clipShape(RoundedRectangle(cornerRadius: 8))
207 + CopyButton(text: address)
208 + Text("First deposit must be ≥ 1 XRP (activates the account). RLUSD requires the trustline.")
209 + .font(.caption).foregroundStyle(.secondary)
210 + .multilineTextAlignment(.center)
211 + }
212 + Button("Back") { mode = .overview }
213 + }
214 + .frame(maxWidth: .infinity)
215 + }
216 +
217 + // MARK: - Send
218 +
219 + private var send: some View {
220 + VStack(alignment: .leading, spacing: 12) {
221 + if let hash = sentHash {
222 + sentView(hash)
223 + } else if let prepared {
224 + confirmView(prepared)
225 + } else {
226 + sendForm
227 + }
228 + }
229 + }
230 +
231 + private var sendForm: some View {
232 + VStack(alignment: .leading, spacing: 12) {
233 + Picker("Asset", selection: $sendRLUSD) {
234 + Text("XRP").tag(false)
235 + Text("RLUSD").tag(true)
236 + }
237 + .pickerStyle(.segmented)
238 + TextField("Recipient (r…)", text: $recipient)
239 + .textFieldStyle(.roundedBorder)
240 + .font(.body.monospaced())
241 + .autocorrectionDisabled()
242 + if !recipient.isEmpty && !XRPLService.validate(address: recipient) {
243 + Label("Not a valid XRPL address", systemImage: "xmark.circle")
244 + .font(.caption).foregroundStyle(.red)
245 + }
246 + HStack {
247 + TextField("Amount", text: $amountInput)
248 + .textFieldStyle(.roundedBorder)
249 + .font(.body.monospaced())
250 + Text(sendRLUSD ? "RLUSD" : "XRP").foregroundStyle(.secondary)
251 + }
252 + Text(sendRLUSD
253 + ? "Balance: \(app.xrplBalances?.rlusdValue ?? "0") RLUSD"
254 + : "Spendable: \(XRPLService.formatXRP(app.xrplBalances?.spendableDrops ?? 0)) XRP")
255 + .font(.caption).foregroundStyle(.secondary)
256 + if let errorMessage {
257 + Text(errorMessage).foregroundStyle(.red).font(.callout)
258 + }
259 + HStack {
260 + Button("Back") { mode = .overview; errorMessage = nil }
261 + Spacer()
262 + if busy { ProgressView().controlSize(.small) }
263 + Button("Review") { estimate() }
264 + .buttonStyle(.borderedProminent)
265 + .disabled(!formValid || busy)
266 + }
267 + }
268 + }
269 +
270 + private var formValid: Bool {
271 + guard XRPLService.validate(address: recipient) else { return false }
272 + if sendRLUSD {
273 + return XRPLService.validRLUSDAmount(amountInput) != nil
274 + }
275 + return (XRPLService.parseXRP(amountInput) ?? 0) > 0
276 + }
277 +
278 + private func estimate() {
279 + errorMessage = nil
280 + busy = true
281 + let to = recipient.trimmingCharacters(in: .whitespacesAndNewlines)
282 + let rlusd = sendRLUSD
283 + let drops = XRPLService.parseXRP(amountInput) ?? 0
284 + let value = XRPLService.validRLUSDAmount(amountInput) ?? "0"
285 + Task {
286 + do {
287 + prepared = try await app.xrplService.estimateSend(
288 + to: to, amountDrops: drops, amountValue: value, isRLUSD: rlusd)
289 + } catch {
290 + errorMessage = error.localizedDescription
291 + }
292 + busy = false
293 + }
294 + }
295 +
296 + private func confirmView(_ p: XRPLService.PreparedXRPLSend) -> some View {
297 + VStack(alignment: .leading, spacing: 12) {
298 + Text("Confirm transaction").font(.headline)
299 + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) {
300 + GridRow {
301 + Text("Recipient").foregroundStyle(.secondary)
302 + Text(p.recipient).font(.callout.monospaced())
303 + .textSelection(.enabled)
304 + .lineLimit(1).truncationMode(.middle)
305 + }
306 + GridRow {
307 + Text("Amount").foregroundStyle(.secondary)
308 + Text(p.isRLUSD ? "\(p.amountValue) RLUSD" : "\(XRPLService.formatXRP(p.amountDrops)) XRP")
309 + .fontWeight(.semibold)
310 + }
311 + GridRow {
312 + Text("Network").foregroundStyle(.secondary)
313 + Text(p.network.displayName)
314 + }
315 + GridRow {
316 + Text("Fee").foregroundStyle(.secondary)
317 + Text("\(XRPLService.formatXRP(p.feeDrops)) XRP")
318 + }
319 + }
320 + .font(.callout)
321 + if p.activatesRecipient {
322 + Label("The recipient account doesn't exist yet — 1 XRP of the amount becomes its locked base reserve.",
323 + systemImage: "info.circle")
324 + .font(.caption)
325 + .foregroundStyle(.orange)
326 + }
327 + Divider()
328 + SecureField("Vault password to sign", text: $password)
329 + .textFieldStyle(.roundedBorder)
330 + if let errorMessage {
331 + Text(errorMessage).foregroundStyle(.red).font(.callout)
332 + }
333 + HStack {
334 + Button("Back") {
335 + prepared = nil
336 + password = ""
337 + }
338 + Spacer()
339 + if busy { ProgressView().controlSize(.small) }
340 + Button("Sign & send") { broadcast(p) }
341 + .buttonStyle(.borderedProminent)
342 + .disabled(password.isEmpty || busy)
343 + }
344 + }
345 + }
346 +
347 + private func broadcast(_ p: XRPLService.PreparedXRPLSend) {
348 + busy = true
349 + errorMessage = nil
350 + let candidate = password
351 + let manager = app.keyManager
352 + Task {
353 + do {
354 + let mnemonic = try await Task.detached {
355 + try manager.unlock(password: candidate).mnemonic
356 + }.value
357 + let hash = try await app.xrplService.send(p, mnemonic: mnemonic)
358 + password = ""
359 + sentHash = hash
360 + await app.refreshXRPL()
361 + } catch {
362 + errorMessage = error.localizedDescription
363 + }
364 + busy = false
365 + }
366 + }
367 +
368 + private func sentView(_ hash: String) -> some View {
369 + VStack(spacing: 12) {
370 + Image(systemName: "paperplane.circle.fill")
371 + .font(.system(size: 38)).foregroundStyle(.green)
372 + Text("Transaction sent").font(.headline)
373 + Text(hash)
374 + .font(.caption.monospaced())
375 + .textSelection(.enabled)
376 + .lineLimit(1).truncationMode(.middle)
377 + Link("View on XRPL Explorer", destination: app.xrplNetwork.explorerTxURL(hash))
378 + Button("Done") {
379 + sentHash = nil
380 + prepared = nil
381 + recipient = ""
382 + amountInput = ""
383 + mode = .overview
384 + }
385 + .buttonStyle(.borderedProminent)
386 + }
387 + .frame(maxWidth: .infinity)
388 + }
389 +}
added Support/Info.plist +49 −0
@@ -0,0 +1,49 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + Info.plist
4 + OS Vault
5 +
6 + Author: Simon-Pierre Boucher
7 + Mail: contact@spboucher.ai
8 +-->
9 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
10 +<plist version="1.0">
11 +<dict>
12 + <key>CFBundleDevelopmentRegion</key>
13 + <string>en</string>
14 + <key>CFBundleDisplayName</key>
15 + <string>OS Vault</string>
16 + <key>CFBundleExecutable</key>
17 + <string>OSVault</string>
18 + <key>CFBundleIconFile</key>
19 + <string>AppIcon</string>
20 + <key>CFBundleIdentifier</key>
21 + <string>com.zyquo.osvault</string>
22 + <key>CFBundleInfoDictionaryVersion</key>
23 + <string>6.0</string>
24 + <key>CFBundleName</key>
25 + <string>OS Vault</string>
26 + <key>CFBundlePackageType</key>
27 + <string>APPL</string>
28 + <key>CFBundleShortVersionString</key>
29 + <string>1.0.0</string>
30 + <key>CFBundleVersion</key>
31 + <string>6</string>
32 + <key>LSApplicationCategoryType</key>
33 + <string>public.app-category.finance</string>
34 + <key>LSArchitecturePriority</key>
35 + <array>
36 + <string>arm64</string>
37 + </array>
38 + <key>LSMinimumSystemVersion</key>
39 + <string>14.0</string>
40 + <key>NSHighResolutionCapable</key>
41 + <true/>
42 + <key>NSHumanReadableCopyright</key>
43 + <string>© 2026 Simon-Pierre Boucher</string>
44 + <key>NSMainNibFile</key>
45 + <string></string>
46 + <key>NSPrincipalClass</key>
47 + <string>NSApplication</string>
48 +</dict>
49 +</plist>
added Support/entitlements.plist +21 −0
@@ -0,0 +1,21 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + entitlements.plist
4 + OS Vault
5 +
6 + Author: Simon-Pierre Boucher
7 + Mail: contact@spboucher.ai
8 +-->
9 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
10 +<plist version="1.0">
11 +<dict>
12 + <!-- App Sandbox with outbound network only: the app's sole egress is
13 + JSON-RPC to the configured Base endpoint. The encrypted vault lives
14 + in the sandbox container's Application Support. Hardened runtime is
15 + enabled at signing time (codesign - -options runtime). -->
16 + <key>com.apple.security.app-sandbox</key>
17 + <true/>
18 + <key>com.apple.security.network.client</key>
19 + <true/>
20 +</dict>
21 +</plist>
added Tests/OSVaultTests/BitcoinTests.swift +57 −0
@@ -0,0 +1,57 @@
1 +//
2 +// BitcoinTests.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import XCTest
10 +import BitcoinDevKit
11 +@testable import OSVaultKit
12 +
13 +final class BitcoinTests: XCTestCase {
14 +
15 + // Official BIP-84 test vector (public, not a real wallet): the
16 + // all-"abandon" mnemonic must derive these first addresses at m/84'/0'/0'.
17 + let vectorMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
18 +
19 + func testBIP84VectorFirstAddress() throws {
20 + let (external, internalD) = try BitcoinService.secretDescriptors(
21 + mnemonic: vectorMnemonic, network: .mainnet)
22 + let wallet = try Wallet(descriptor: external, changeDescriptor: internalD,
23 + network: .bitcoin, persister: Persister.newInMemory())
24 + let first = wallet.revealNextAddress(keychain: .external)
25 + XCTAssertEqual(first.address.description, "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu")
26 + let second = wallet.revealNextAddress(keychain: .external)
27 + XCTAssertEqual(second.address.description, "bc1qnjg0jd8228aq7egyzacy8cys3knf9xvrerkf9g")
28 + let change = wallet.revealNextAddress(keychain: .internal)
29 + XCTAssertEqual(change.address.description, "bc1q8c6fshw2dlwun7ekn9qwf37cu2rn755upcp6el")
30 + }
31 +
32 + func testPublicDescriptorsAreWatchOnly() throws {
33 + let (external, _) = try BitcoinService.publicDescriptors(
34 + mnemonic: vectorMnemonic, network: .mainnet)
35 + // A public descriptor must not contain private key material.
36 + XCTAssertFalse(external.description.contains("xprv"))
37 + XCTAssertTrue(external.description.contains("xpub"))
38 + }
39 +
40 + func testAddressValidationPerNetwork() {
41 + XCTAssertTrue(BitcoinService.validate(
42 + address: "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", network: .mainnet))
43 + XCTAssertFalse(BitcoinService.validate(
44 + address: "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", network: .signet))
45 + XCTAssertFalse(BitcoinService.validate(address: "not-an-address", network: .mainnet))
46 + XCTAssertFalse(BitcoinService.validate(
47 + address: "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", network: .mainnet))
48 + }
49 +
50 + func testBTCAmountParsing() {
51 + XCTAssertEqual(BitcoinService.parseBTC("1"), 100_000_000)
52 + XCTAssertEqual(BitcoinService.parseBTC("0.00000001"), 1)
53 + XCTAssertNil(BitcoinService.parseBTC("0.000000001")) // sub-sat
54 + XCTAssertEqual(BitcoinService.formatBTC(150_000_000), "1.5")
55 + XCTAssertEqual(BitcoinService.formatBTC(1), "0.00000001")
56 + }
57 +}
added Tests/OSVaultTests/CoreTests.swift +211 −0
@@ -0,0 +1,211 @@
1 +//
2 +// CoreTests.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import XCTest
10 +import BigInt
11 +@testable import OSVaultKit
12 +
13 +final class DerivationTests: XCTestCase {
14 +
15 + // Standard BIP-39/BIP-44 test vector (public, not a real wallet):
16 + // the all-"abandon" mnemonic derives this well-known address at
17 + // m/44'/60'/0'/0/0 across every major wallet implementation.
18 + let vectorMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
19 + let vectorAddress = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
20 +
21 + func testKnownVectorDerivesKnownAddress() throws {
22 + let wallet = try KeyManager.derive(mnemonic: vectorMnemonic)
23 + XCTAssertEqual(wallet.address, vectorAddress)
24 + XCTAssertEqual(wallet.privateKey.count, 32)
25 + }
26 +
27 + func testGeneratedMnemonicIsValidAndDerives() throws {
28 + let manager = KeyManager(vaultURL: tempVaultURL())
29 + let mnemonic = try manager.generateMnemonic()
30 + XCTAssertEqual(mnemonic.split(separator: " ").count, 12)
31 + XCTAssertTrue(KeyManager.validate(mnemonic: mnemonic))
32 + let wallet = try KeyManager.derive(mnemonic: mnemonic)
33 + XCTAssertTrue(wallet.address.hasPrefix("0x"))
34 + XCTAssertEqual(wallet.address.count, 42)
35 + }
36 +
37 + func testInvalidMnemonicRejected() {
38 + XCTAssertFalse(KeyManager.validate(mnemonic: "not a real phrase at all"))
39 + XCTAssertFalse(KeyManager.validate(mnemonic: "abandon abandon abandon"))
40 + // Right words, wrong checksum word.
41 + XCTAssertFalse(KeyManager.validate(mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon"))
42 + }
43 +
44 + func testNormalizationHandlesCaseAndWhitespace() throws {
45 + let messy = " Abandon ABANDON abandon\nabandon abandon abandon abandon abandon abandon abandon abandon about "
46 + let wallet = try KeyManager.derive(mnemonic: messy)
47 + XCTAssertEqual(wallet.address, vectorAddress)
48 + }
49 +}
50 +
51 +final class VaultCryptoTests: XCTestCase {
52 +
53 + func testSealOpenRoundtrip() throws {
54 + let secret = Data("twelve words of nothing sensitive here".utf8)
55 + // Low iteration count keeps the test fast; production uses 600k.
56 + let vault = try VaultCrypto.seal(secret: secret, password: "correct horse", iterations: 10_000)
57 + let opened = try VaultCrypto.open(vault, password: "correct horse")
58 + XCTAssertEqual(opened, secret)
59 + }
60 +
61 + func testWrongPasswordFails() throws {
62 + let vault = try VaultCrypto.seal(secret: Data("s".utf8), password: "right", iterations: 10_000)
63 + XCTAssertThrowsError(try VaultCrypto.open(vault, password: "wrong")) { error in
64 + XCTAssertEqual(error as? WalletError, .wrongPassword)
65 + }
66 + }
67 +
68 + func testTamperedCiphertextFails() throws {
69 + let vault = try VaultCrypto.seal(secret: Data("s".utf8), password: "pw", iterations: 10_000)
70 + var combined = Data(base64Encoded: vault.ciphertext)!
71 + combined[combined.count - 1] ^= 0xFF
72 + let tampered = VaultCrypto.VaultFile(
73 + version: vault.version, kdf: vault.kdf,
74 + cipher: vault.cipher, ciphertext: combined.base64EncodedString()
75 + )
76 + XCTAssertThrowsError(try VaultCrypto.open(tampered, password: "pw"))
77 + }
78 +
79 + func testKeyManagerVaultLifecycle() throws {
80 + let url = tempVaultURL()
81 + let manager = KeyManager(vaultURL: url)
82 + XCTAssertFalse(manager.hasVault)
83 +
84 + let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
85 + let saved = try manager.saveWallet(mnemonic: mnemonic, password: "test-password-123")
86 + XCTAssertTrue(manager.hasVault)
87 +
88 + let unlocked = try manager.unlock(password: "test-password-123")
89 + XCTAssertEqual(unlocked.address, saved.address)
90 + XCTAssertEqual(unlocked.mnemonic, mnemonic)
91 +
92 + XCTAssertThrowsError(try manager.unlock(password: "nope")) { error in
93 + XCTAssertEqual(error as? WalletError, .wrongPassword)
94 + }
95 +
96 + // Vault file on disk must never contain the mnemonic in clear.
97 + let raw = try String(contentsOf: url, encoding: .utf8)
98 + XCTAssertFalse(raw.contains("abandon"))
99 +
100 + try manager.deleteVault()
101 + XCTAssertFalse(manager.hasVault)
102 + }
103 +}
104 +
105 +final class TokenAmountTests: XCTestCase {
106 +
107 + func testUSDCSixDecimals() {
108 + XCTAssertEqual(TokenAmount.parse("1", decimals: 6), 1_000_000)
109 + XCTAssertEqual(TokenAmount.parse("12.5", decimals: 6), 12_500_000)
110 + XCTAssertEqual(TokenAmount.parse("0.000001", decimals: 6), 1)
111 + XCTAssertEqual(TokenAmount.parse("1,25", decimals: 6), 1_250_000)
112 + XCTAssertNil(TokenAmount.parse("0.0000001", decimals: 6)) // too many digits
113 + XCTAssertNil(TokenAmount.parse("", decimals: 6))
114 + XCTAssertNil(TokenAmount.parse("1.2.3", decimals: 6))
115 + XCTAssertNil(TokenAmount.parse("abc", decimals: 6))
116 + XCTAssertNil(TokenAmount.parse("-1", decimals: 6))
117 + }
118 +
119 + func testDAIEighteenDecimals() {
120 + XCTAssertEqual(TokenAmount.parse("1", decimals: 18), BigUInt(10).power(18))
121 + XCTAssertEqual(TokenAmount.format(BigUInt(10).power(18), decimals: 18), "1")
122 + XCTAssertEqual(TokenAmount.format(BigUInt(1_500) * BigUInt(10).power(15), decimals: 18), "1.5")
123 + }
124 +
125 + func testFormatting() {
126 + XCTAssertEqual(TokenAmount.format(1_000_000, decimals: 6), "1")
127 + XCTAssertEqual(TokenAmount.format(12_500_000, decimals: 6), "12.5")
128 + XCTAssertEqual(TokenAmount.format(1, decimals: 6), "0.000001")
129 + XCTAssertEqual(TokenAmount.format(0, decimals: 6), "0")
130 + // Truncation, never rounding up.
131 + XCTAssertEqual(TokenAmount.format(1_999_999, decimals: 6, maxFractionDigits: 2), "1.99")
132 + }
133 +
134 + func testRoundtrip() {
135 + let cases = ["0.1", "123456.654321", "1", "0.000001"]
136 + for c in cases {
137 + let parsed = TokenAmount.parse(c, decimals: 6)!
138 + XCTAssertEqual(TokenAmount.format(parsed, decimals: 6), c)
139 + }
140 + }
141 +}
142 +
143 +final class AddressValidationTests: XCTestCase {
144 +
145 + func testChecksummedAddressValid() {
146 + // EIP-55 reference vectors.
147 + let valid = [
148 + "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
149 + "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
150 + "0x52908400098527886E0F7030069857D2E4169EE7"
151 + ]
152 + for address in valid {
153 + guard case .valid(let checksummed) = AddressValidator.validate(address) else {
154 + return XCTFail("\(address) should be valid")
155 + }
156 + XCTAssertEqual(checksummed, address)
157 + }
158 + }
159 +
160 + func testBadChecksumInvalid() {
161 + // One flipped case letter breaks the checksum.
162 + XCTAssertEqual(AddressValidator.validate("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAeD"), .invalid)
163 + }
164 +
165 + func testLowercaseWarnsButPasses() {
166 + let result = AddressValidator.validate("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
167 + guard case .validNoChecksum(let checksummed) = result else {
168 + return XCTFail("lowercase should pass with warning")
169 + }
170 + XCTAssertEqual(checksummed, "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")
171 + }
172 +
173 + func testGarbageInvalid() {
174 + XCTAssertEqual(AddressValidator.validate(""), .invalid)
175 + XCTAssertEqual(AddressValidator.validate("0x123"), .invalid)
176 + XCTAssertEqual(AddressValidator.validate("5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"), .invalid)
177 + XCTAssertEqual(AddressValidator.validate("0xZZZeb6053F3E94C9b9A09f33669435E7Ef1BeAed"), .invalid)
178 + }
179 +}
180 +
181 +final class CalldataTests: XCTestCase {
182 +
183 + func testTransferCalldataShape() {
184 + let recipient = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
185 + let calldata = Hex.erc20TransferData(to: recipient, amount: 1_000_000)!
186 + XCTAssertEqual(calldata.count, 4 + 32 + 32)
187 + XCTAssertEqual(calldata.prefix(4), Data([0xa9, 0x05, 0x9c, 0xbb]))
188 + XCTAssertEqual(Hex.string(calldata.suffix(32)),
189 + "0x00000000000000000000000000000000000000000000000000000000000f4240")
190 + }
191 +
192 + func testBalanceOfCalldata() {
193 + let owner = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
194 + let calldata = Hex.erc20BalanceOfData(owner: owner)!
195 + XCTAssertEqual(calldata.count, 4 + 32)
196 + XCTAssertEqual(calldata.prefix(4), Data([0x70, 0xa0, 0x82, 0x31]))
197 + }
198 +
199 + func testQuantityHelpers() {
200 + XCTAssertEqual(Hex.quantity(0), "0x0")
201 + XCTAssertEqual(Hex.quantity(255), "0xff")
202 + XCTAssertEqual(Hex.toBigUInt("0xff"), 255)
203 + XCTAssertEqual(Hex.toBigUInt("0x"), 0)
204 + XCTAssertNil(Hex.toBigUInt("0xzz"))
205 + }
206 +}
207 +
208 +func tempVaultURL() -> URL {
209 + FileManager.default.temporaryDirectory
210 + .appendingPathComponent("osvault-tests-\(UUID().uuidString)/vault.json")
211 +}
added Tests/OSVaultTests/SolanaTests.swift +42 −0
@@ -0,0 +1,42 @@
1 +//
2 +// SolanaTests.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import XCTest
10 +import SolanaSwift
11 +@testable import OSVaultKit
12 +
13 +final class SolanaTests: XCTestCase {
14 +
15 + // Public BIP-44 test vector: the all-"abandon" mnemonic at
16 + // m/44'/501'/0'/0' (bip44Change) — the Phantom/Solflare default.
17 + let vectorMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
18 +
19 + func testDerivationIsDeterministicAndPhantomPath() async throws {
20 + let first = try await SolanaService.deriveKeyPair(mnemonic: vectorMnemonic, network: .mainnet)
21 + let second = try await SolanaService.deriveKeyPair(mnemonic: vectorMnemonic, network: .devnet)
22 + // Cluster must not change the derivation; the keypair is path-only.
23 + XCTAssertEqual(first.publicKey.base58EncodedString, second.publicKey.base58EncodedString)
24 + XCTAssertEqual(first.secretKey.count, 64)
25 + XCTAssertTrue(SolanaService.validate(address: first.publicKey.base58EncodedString))
26 + }
27 +
28 + func testAddressValidation() {
29 + XCTAssertTrue(SolanaService.validate(address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"))
30 + XCTAssertFalse(SolanaService.validate(address: "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"))
31 + XCTAssertFalse(SolanaService.validate(address: "not-an-address"))
32 + XCTAssertFalse(SolanaService.validate(address: ""))
33 + }
34 +
35 + func testAmountParsing() {
36 + XCTAssertEqual(SolanaService.parseSOL("1"), 1_000_000_000)
37 + XCTAssertEqual(SolanaService.parseSOL("0.000000001"), 1)
38 + XCTAssertNil(SolanaService.parseSOL("0.0000000001")) // sub-lamport
39 + XCTAssertEqual(SolanaService.parseUSDC("12.5"), 12_500_000)
40 + XCTAssertEqual(SolanaService.formatSOL(1_500_000_000), "1.5")
41 + }
42 +}
added Tests/OSVaultTests/WalletCoreTests.swift +78 −0
@@ -0,0 +1,78 @@
1 +//
2 +// WalletCoreTests.swift
3 +// OS Vault
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +
9 +import XCTest
10 +import WalletCore
11 +import Web3Core
12 +@testable import OSVaultKit
13 +
14 +final class WalletCoreTests: XCTestCase {
15 +
16 + // Same public test vector as the rest of the suite.
17 + let vectorMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
18 +
19 + func testEthereumAddressMatchesWeb3swift() throws {
20 + // Cross-check the two independent secp256k1/BIP-32 stacks: wallet-core
21 + // must derive the exact address web3swift derives (and the BIP-44 vector).
22 + let hd = HDWallet(mnemonic: vectorMnemonic, passphrase: "")!
23 + XCTAssertEqual(hd.getAddressForCoin(coin: .ethereum),
24 + "0x9858EfFD232B4033E47d90003D41EC34EcaEda94")
25 + }
26 +
27 + func testTronDerivationConsistentAcrossStacks() throws {
28 + // Derive the Tron key with web3swift's HD stack at m/44'/195'/0'/0/0,
29 + // feed the raw private key to wallet-core, and require the same
30 + // address wallet-core derives internally from the mnemonic.
31 + let hd = HDWallet(mnemonic: vectorMnemonic, passphrase: "")!
32 + let fromMnemonic = hd.getAddressForCoin(coin: .tron)
33 +
34 + let seed = BIP39.seedFromMmemonics(vectorMnemonic, password: "", language: .english)!
35 + let node = HDNode(seed: seed)!.derive(path: "m/44'/195'/0'/0/0", derivePrivateKey: true)!
36 + let key = PrivateKey(data: node.privateKey!)!
37 + let fromRawKey = CoinType.tron.deriveAddress(privateKey: key)
38 +
39 + XCTAssertEqual(fromMnemonic, fromRawKey)
40 + XCTAssertTrue(fromMnemonic.hasPrefix("T"))
41 + XCTAssertEqual(fromMnemonic.count, 34)
42 + }
43 +
44 + func testXRPAndTONAddressesDerive() throws {
45 + let hd = HDWallet(mnemonic: vectorMnemonic, passphrase: "")!
46 + let xrp = hd.getAddressForCoin(coin: .xrp)
47 + XCTAssertTrue(xrp.hasPrefix("r"))
48 + let ton = hd.getAddressForCoin(coin: .ton)
49 + XCTAssertTrue(ton.hasPrefix("UQ") || ton.hasPrefix("EQ"))
50 + }
51 +
52 + func testTronAddressValidation() {
53 + XCTAssertTrue(AnyAddress.isValid(string: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", coin: .tron))
54 + XCTAssertFalse(AnyAddress.isValid(string: "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", coin: .tron))
55 + XCTAssertFalse(AnyAddress.isValid(string: "Tinvalid", coin: .tron))
56 + }
57 +}
58 +
59 +final class XRPLTONTests: XCTestCase {
60 +
61 + func testXRPLValidationAndAmounts() {
62 + XCTAssertTrue(XRPLService.validate(address: "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De"))
63 + XCTAssertFalse(XRPLService.validate(address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"))
64 + XCTAssertEqual(XRPLService.parseXRP("1"), 1_000_000)
65 + XCTAssertEqual(XRPLService.formatXRP(1_500_000), "1.5")
66 + XCTAssertEqual(XRPLService.validRLUSDAmount("12,5"), "12.5")
67 + XCTAssertNil(XRPLService.validRLUSDAmount("abc"))
68 + XCTAssertNil(XRPLService.validRLUSDAmount("0"))
69 + }
70 +
71 + func testTONValidationAndAmounts() {
72 + XCTAssertTrue(TONService.validate(address: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"))
73 + XCTAssertFalse(TONService.validate(address: "not-a-ton-address"))
74 + XCTAssertEqual(TONService.parseTON("1"), 1_000_000_000)
75 + XCTAssertEqual(TONService.parseUSDT("2.5"), 2_500_000)
76 + XCTAssertEqual(TONService.formatTON(1_500_000_000), "1.5")
77 + }
78 +}
added assets/icon/AppIcon.icns +0 −0

Binary file not shown.

added assets/icon/os-vault-simple.svg +25 −0
@@ -0,0 +1,25 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + os-vault-simple.svg — OS Vault app icon, simplified variant baked at 16/32 px.
4 +
5 + Author: Simon-Pierre Boucher
6 + Mail: contact@spboucher.ai
7 +-->
8 +<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
9 + <defs>
10 + <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
11 + <stop offset="0" stop-color="#24355a"/>
12 + <stop offset="1" stop-color="#0a1122"/>
13 + </linearGradient>
14 + </defs>
15 + <rect x="64" y="64" width="896" height="896" rx="200" fill="url(#bg)"/>
16 + <!-- bold wheel -->
17 + <circle cx="512" cy="512" r="300" fill="none" stroke="#c9d3e2" stroke-width="96"/>
18 + <g stroke="#c9d3e2" stroke-width="88" stroke-linecap="round">
19 + <line x1="512" y1="252" x2="512" y2="772"/>
20 + <line x1="287" y1="382" x2="737" y2="642"/>
21 + <line x1="737" y1="382" x2="287" y2="642"/>
22 + </g>
23 + <circle cx="512" cy="512" r="150" fill="#3ec3ff"/>
24 + <circle cx="512" cy="512" r="150" fill="none" stroke="#0a1122" stroke-width="40"/>
25 +</svg>
added assets/icon/os-vault.svg +158 −0
@@ -0,0 +1,158 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + os-vault.svg — OS Vault app icon (full detail, >= 64 px)
4 +
5 + Author: Simon-Pierre Boucher
6 + Mail: contact@spboucher.ai
7 +
8 + Concept: a titanium vault door on a deep-space navy squircle, six-spoke
9 + locking wheel, luminous cyan core with keyhole — self-custody, engineered
10 + to feel unbreakable.
11 +-->
12 +<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
13 + <defs>
14 + <!-- background -->
15 + <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
16 + <stop offset="0" stop-color="#233457"/>
17 + <stop offset="0.55" stop-color="#131d36"/>
18 + <stop offset="1" stop-color="#080d1c"/>
19 + </linearGradient>
20 + <radialGradient id="bgGlow" cx="0.5" cy="0.28" r="0.75">
21 + <stop offset="0" stop-color="#3f6fd8" stop-opacity="0.45"/>
22 + <stop offset="0.5" stop-color="#2a4a9e" stop-opacity="0.12"/>
23 + <stop offset="1" stop-color="#000000" stop-opacity="0"/>
24 + </radialGradient>
25 +
26 + <!-- metals -->
27 + <linearGradient id="steel" x1="0" y1="0" x2="0" y2="1">
28 + <stop offset="0" stop-color="#f2f6fb"/>
29 + <stop offset="0.35" stop-color="#c3ccd9"/>
30 + <stop offset="0.7" stop-color="#8e9aac"/>
31 + <stop offset="1" stop-color="#6a7689"/>
32 + </linearGradient>
33 + <linearGradient id="steelDeep" x1="0" y1="0" x2="0" y2="1">
34 + <stop offset="0" stop-color="#39445c"/>
35 + <stop offset="0.5" stop-color="#232c42"/>
36 + <stop offset="1" stop-color="#161d30"/>
37 + </linearGradient>
38 + <linearGradient id="steelRim" x1="0" y1="1" x2="0" y2="0">
39 + <stop offset="0" stop-color="#f0f4fa"/>
40 + <stop offset="0.5" stop-color="#aab4c4"/>
41 + <stop offset="1" stop-color="#78849a"/>
42 + </linearGradient>
43 + <linearGradient id="spoke" x1="0" y1="0" x2="0" y2="1">
44 + <stop offset="0" stop-color="#eef2f8"/>
45 + <stop offset="0.5" stop-color="#b5bfce"/>
46 + <stop offset="1" stop-color="#7f8ba0"/>
47 + </linearGradient>
48 +
49 + <!-- accent core -->
50 + <radialGradient id="core" cx="0.5" cy="0.42" r="0.7">
51 + <stop offset="0" stop-color="#9be8ff"/>
52 + <stop offset="0.45" stop-color="#3ec3ff"/>
53 + <stop offset="0.8" stop-color="#1470e0"/>
54 + <stop offset="1" stop-color="#0b4bb0"/>
55 + </radialGradient>
56 + <radialGradient id="coreHalo" cx="0.5" cy="0.5" r="0.5">
57 + <stop offset="0.55" stop-color="#3ec3ff" stop-opacity="0"/>
58 + <stop offset="0.8" stop-color="#3ec3ff" stop-opacity="0.35"/>
59 + <stop offset="1" stop-color="#3ec3ff" stop-opacity="0"/>
60 + </radialGradient>
61 +
62 + <filter id="doorShadow" x="-30%" y="-30%" width="160%" height="160%">
63 + <feDropShadow dx="0" dy="26" stdDeviation="34" flood-color="#000000" flood-opacity="0.55"/>
64 + </filter>
65 + <filter id="lift" x="-40%" y="-40%" width="180%" height="180%">
66 + <feDropShadow dx="0" dy="8" stdDeviation="10" flood-color="#000000" flood-opacity="0.45"/>
67 + </filter>
68 +
69 + <clipPath id="squircle">
70 + <rect x="96" y="96" width="832" height="832" rx="186"/>
71 + </clipPath>
72 + </defs>
73 +
74 + <!-- squircle plate -->
75 + <g>
76 + <rect x="96" y="96" width="832" height="832" rx="186" fill="url(#bg)"/>
77 + <g clip-path="url(#squircle)">
78 + <rect x="96" y="96" width="832" height="832" fill="url(#bgGlow)"/>
79 + <!-- engraved corner braces -->
80 + <g stroke="#5f79b3" stroke-opacity="0.28" stroke-width="10" fill="none">
81 + <path d="M158 300 v-70 a72 72 0 0 1 72 -72 h70"/>
82 + <path d="M866 300 v-70 a72 72 0 0 0 -72 -72 h-70"/>
83 + <path d="M158 724 v70 a72 72 0 0 0 72 72 h70"/>
84 + <path d="M866 724 v70 a72 72 0 0 1 -72 72 h-70"/>
85 + </g>
86 + <!-- inner bevel of the plate -->
87 + <rect x="110" y="110" width="804" height="804" rx="174" fill="none"
88 + stroke="#8fb0ff" stroke-opacity="0.16" stroke-width="4"/>
89 + </g>
90 + </g>
91 +
92 + <!-- vault door -->
93 + <g filter="url(#doorShadow)">
94 + <circle cx="512" cy="512" r="308" fill="url(#steelRim)"/>
95 + <circle cx="512" cy="512" r="308" fill="none" stroke="#101624" stroke-opacity="0.55" stroke-width="3"/>
96 + </g>
97 + <!-- recessed track -->
98 + <circle cx="512" cy="512" r="262" fill="url(#steelDeep)"/>
99 + <circle cx="512" cy="512" r="262" fill="none" stroke="#0a0f1c" stroke-width="6" stroke-opacity="0.7"/>
100 + <circle cx="512" cy="512" r="240" fill="none" stroke="#9fc6ff" stroke-opacity="0.14" stroke-width="3"/>
101 +
102 + <!-- rim bolts -->
103 + <g fill="url(#steel)" stroke="#141a29" stroke-width="3">
104 + <circle cx="512" cy="228" r="17"/>
105 + <circle cx="712.8" cy="311.2" r="17"/>
106 + <circle cx="796" cy="512" r="17"/>
107 + <circle cx="712.8" cy="712.8" r="17"/>
108 + <circle cx="512" cy="796" r="17"/>
109 + <circle cx="311.2" cy="712.8" r="17"/>
110 + <circle cx="228" cy="512" r="17"/>
111 + <circle cx="311.2" cy="311.2" r="17"/>
112 + </g>
113 +
114 + <!-- locking wheel: six spokes -->
115 + <g filter="url(#lift)">
116 + <g fill="url(#spoke)" stroke="#1a2233" stroke-width="4">
117 + <g transform="rotate(0 512 512)">
118 + <rect x="492" y="292" width="40" height="440" rx="20"/>
119 + </g>
120 + <g transform="rotate(60 512 512)">
121 + <rect x="492" y="292" width="40" height="440" rx="20"/>
122 + </g>
123 + <g transform="rotate(120 512 512)">
124 + <rect x="492" y="292" width="40" height="440" rx="20"/>
125 + </g>
126 + </g>
127 + <!-- wheel outer ring -->
128 + <circle cx="512" cy="512" r="220" fill="none" stroke="url(#steel)" stroke-width="42"/>
129 + <circle cx="512" cy="512" r="242" fill="none" stroke="#0d1220" stroke-opacity="0.6" stroke-width="4"/>
130 + <circle cx="512" cy="512" r="199" fill="none" stroke="#0d1220" stroke-opacity="0.6" stroke-width="4"/>
131 + <!-- spoke grips -->
132 + <g fill="url(#steel)" stroke="#141a29" stroke-width="4">
133 + <circle cx="512" cy="292" r="34"/>
134 + <circle cx="702.5" cy="622" r="34"/>
135 + <circle cx="321.5" cy="622" r="34"/>
136 + <circle cx="512" cy="732" r="34"/>
137 + <circle cx="321.5" cy="402" r="34"/>
138 + <circle cx="702.5" cy="402" r="34"/>
139 + </g>
140 + </g>
141 +
142 + <!-- luminous core hub -->
143 + <circle cx="512" cy="512" r="150" fill="url(#coreHalo)"/>
144 + <g filter="url(#lift)">
145 + <circle cx="512" cy="512" r="112" fill="url(#steel)"/>
146 + <circle cx="512" cy="512" r="112" fill="none" stroke="#10162a" stroke-width="4"/>
147 + </g>
148 + <circle cx="512" cy="512" r="88" fill="url(#core)"/>
149 + <circle cx="512" cy="512" r="88" fill="none" stroke="#062a66" stroke-width="5"/>
150 + <!-- keyhole -->
151 + <g fill="#04122e">
152 + <circle cx="512" cy="488" r="26"/>
153 + <path d="M496 500 L528 500 L540 566 A10 10 0 0 1 530 576 L494 576 A10 10 0 0 1 484 566 Z"/>
154 + </g>
155 + <!-- specular sweep on the door -->
156 + <path d="M254 388 A 300 300 0 0 1 770 388 A 380 380 0 0 0 254 388 Z"
157 + fill="#ffffff" opacity="0.10"/>
158 +</svg>
added docs/RESEARCH-MULTICHAIN.md +93 −0
@@ -0,0 +1,93 @@
1 +<!--
2 + RESEARCH-MULTICHAIN.md
3 + OS Vault
4 +
5 + Author: Simon-Pierre Boucher
6 + Mail: contact@spboucher.ai
7 +-->
8 +
9 +# Multi-chain implementation research — synthesis (2026-08-05)
10 +
11 +Five parallel research tracks (wallet-core/architecture, Bitcoin, non-EVM
12 +chains, EVM expansion, keyless infra), all endpoint/address claims **verified
13 +live** during research. This file is the implementation blueprint; statuses
14 +below reflect what is already shipped in the code.
15 +
16 +## Verdicts at a glance
17 +
18 +| Track | Verdict | Status in OS Vault |
19 +|---|---|---|
20 +| EVM multichain | Data-driven: 11 chains, 4 real fee models, PublicNode primary keyless RPC + failover | ✅ **Implemented** (`Network.swift`, `TransactionService.swift`) |
21 +| Native coin send | Always `eth_estimateGas` (never 21000); OP-stack/Scroll L1 data fee via oracle | ✅ **Implemented** |
22 +| Stablecoin matrix | Verified per-chain addresses; BNB peg = 18 decimals; USDC.e ≠ USDC by address only | ✅ **Implemented** (`Token.swift`) |
23 +| Bitcoin | **bdk-swift 3.0.0** — only maintained macOS+SPM option; BIP-84; keyless Esplora (mempool.space) | ✅ **Implemented** (`BitcoinService.swift`, watch-only + transient signer) |
24 +| Fiat prices | CoinGecko keyless batched (`/simple/price`, USD/CAD/EUR); DefiLlama fallback; prices-OFF mode | ✅ **Implemented** (`PriceService.swift`) |
25 +| wallet-core (Tron/TON/XRPL signing) | Vendored at `vendor/WalletCoreSPM` (binaryTarget; duplicate Rust `_rust_eh_personality` vs bdkFFI demoted surgically in the archive — see vendor script) | ✅ **Vendored + tested** (ETH vector, Tron cross-stack, XRP/TON derive) |
26 +| Solana | `p2p-org/solana-swift` vendored (`vendor/solana-swift` — its Boilertalk secp256k1 dep clashed with web3swift's target name; CKSecp256k1 re-backed by Web3Core); PublicNode RPC keyless; ATA rent surfaced pre-send | ✅ **Implemented** (`SolanaService.swift`, SOL + USDC, devnet default) |
27 +| Tron | wallet-core `TransferContract`/`TransferTRC20Contract` + TronGrid keyless; energy burn estimated pre-send via `triggerconstantcontract`, fee_limit 100 TRX; Nile default (USDT `TXYZ…AeBf` verified live) | ✅ **Implemented** (`TronService.swift`) |
28 +| TON | tonkeeper/ton-swift + toncenter (1 req/s keyless); jetton indirection; BIP-39 path m/44'/607' (Tonkeeper won't import directly — document) | ⏭ Next |
29 +| XRPL | wallet-core signer (TrustSet + issued currencies = RLUSD); xrplcluster.com genuinely free; 1 XRP base reserve + 0.2/trustline | ⏭ Next |
30 +| Stellar | Soneso stellar-ios-mac-sdk — best non-EVM Swift SDK, nearly free to add | ⏭ Bonus |
31 +| History indexing | No keyless multi-chain indexer exists. Per chain: Blockscout v2 (7 EVM chains), Routescan (Avalanche/Mantle/Blast), mempool.space (BTC), else eth_getLogs incremental. BNB/Linea = optional user key | ⏭ Next |
32 +| Fiat FX | Frankfurter (ECB, keyless, unlimited); avoid exchangerate.host (keyed now) | Covered via CoinGecko native CAD/EUR |
33 +| Auto-update | Sparkle 2 via SPM, EdDSA + notarization, static appcast on GitHub Releases | ⏭ When distribution starts |
34 +
35 +## Key implementation facts (already coded)
36 +
37 +- **Fee models** (`Network.FeeModel`): `eip1559` · `zeroBaseFee` (BSC/BEP-226:
38 + price via `eth_gasPrice`) · `opStackL1Fee` (Base/OP: add
39 + `GasPriceOracle.getL1Fee(unsigned tx)` at `0x42…0F` to the confirm total) ·
40 + `scrollL1Fee` (oracle `0x5300…0002`) · `arbitrumInclusive` (estimate already
41 + includes L1 buffer, tip 0, use verbatim) · `lineaPinnedBase` (base pinned at
42 + 7 wei, cost rides in the tip).
43 +- **RPC failover** (`RPCService`): ordered keyless endpoints per chain
44 + (PublicNode primary — all 11 verified; official RPC fallback), sticky
45 + primary, 60 s demotion cooldown, node-side errors surface immediately.
46 + Dead/keyed providers found in research: llamarpc (521), Ankr (key now),
47 + 1rpc (quota), polygon-rpc.com (401 intermittent).
48 +- **Registry traps**: BNB USDT/USDC are 18 decimals (separate Token entries);
49 + USDC.e shares `symbol()` with native USDC on Arb/OP/Polygon (distinguish by
50 + address, display "USDC.e"); Arbitrum/Polygon USDT upgraded in place to USDT0
51 + (same address/decimals — never assert symbol strings); Gnosis native xDAI is
52 + itself dollar-pegged.
53 +- **Bitcoin** (`BitcoinService`): BIP-84 descriptors from the same vault
54 + mnemonic (BIP-84 spec vector unit-tested); watch-only persisted wallet
55 + (public descriptors, BDK SQLite) for sync/balance/receive with address
56 + rotation; sends build the PSBT on the watch wallet, then a throwaway
57 + in-memory signer wallet (secret descriptors re-derived from the password)
58 + signs and is discarded. Esplora keyless: mempool.space (+ blockstream.info
59 + broadcast fallback on mainnet); fees from `/api/v1/fees/recommended`.
60 + Default network **signet** (testnet-first), mainnet behind the switch.
61 +- **Prices** (`PriceService`): one batched CoinGecko call for every asset ×
62 + USD/CAD/EUR at ≥120 s TTL (≈0.5 calls/min vs 5–15/min keyless budget);
63 + stale-while-revalidate JSON cache; Settings toggle removes the only
64 + non-blockchain egress. CoinCap and CryptoCompare are dead as keyless
65 + options; Binance geoblocks; Coinbase spot is the per-pair fallback.
66 +
67 +## wallet-core vendoring (next phase enabler)
68 +
69 +Upstream declined macOS SPM support (PR #3529), but the **official CocoaPods
70 +tarball** (`TrustWalletCore-<v>.tar.xz` on GitHub releases) contains
71 +`WalletCoreCommon.xcframework` with a `macos-arm64_x86_64` slice plus the
72 +Swift wrappers. `scripts/vendor-walletcore.sh` automates: download → verify →
73 +C-headers target (incl. the **security-critical `SecRandom.m`** RNG shim) →
74 +sed module imports → local SPM package in `vendor/WalletCoreSPM`. Proven by a
75 +local build that derived BTC/ETH/Solana/Tron/TON/XRP addresses from one
76 +runtime mnemonic. Cost: ~33 MB binary. One library then signs every remaining
77 +chain (Tron `TransferTRC20Contract`, TON `JettonTransfer` + wallet v5R1, XRPL
78 +`TrustSet`/issued currencies, Solana `CreateAndTransferToken`).
79 +
80 +## Non-EVM priority order (stablecoin volume × cost)
81 +
82 +1. **Solana / USDC** — cheapest build (solana-swift is macOS-native) and top
83 + USDC venue; pipe-cleaner for the adapter pattern.
84 +2. **Tron / USDT-TRC20** — largest USDT corridor on earth; energy-fee UX is
85 + the main work (estimate via `triggerconstantcontract`, `fee_limit` 100 TRX).
86 +3. **TON / USDT jetton** — jetton-wallet indirection, 1 rps toncenter queue.
87 +4. **XRPL / RLUSD + XRP** — trustline UX (one-tap TrustSet, check recipient
88 + `account_lines` pre-send), reserves surfaced as non-spendable.
89 +5. **Stellar / USDC** — Soneso SDK, trustlines like XRPL, nearly free to add.
90 +
91 +Full per-chain details (curves, derivation paths, endpoints, faucets, rate
92 +limits, sources) live in the research transcripts; the numbers used in code
93 +are restated in comments at their point of use.
added docs/ROADMAP.md +65 −0
@@ -0,0 +1,65 @@
1 +<!--
2 + ROADMAP.md
3 + OS Vault
4 +
5 + Author: Simon-Pierre Boucher
6 + Mail: contact@spboucher.ai
7 +-->
8 +
9 +# OS Vault — Multi-chain / multi-stablecoin roadmap
10 +
11 +v1 is Base-only (Sepolia default, mainnet behind the network switch) with a
12 +data-driven token registry (USDC default + EURC, DAI, USDT). The goal is broad
13 +stablecoin coverage across chains. Target matrix (user-provided, 2026-08-05):
14 +
15 +| Stablecoin | Main chains |
16 +|---|---|
17 +| USDT | Ethereum, Tron, Solana, BNB Chain, Avalanche, Arbitrum, Optimism, Polygon, TON, Aptos, Celo, EOS, Near, Tezos, Algorand, Cosmos (Noble), Kaia, Ink… |
18 +| USDC | Ethereum, Solana, Base, Arbitrum, Optimism, Polygon, Avalanche, Stellar, Aptos, Sui, Hedera, Algorand, Celo, Near, ZKsync, Starknet, Linea, Monad, XRP Ledger, World Chain, Unichain, XDC, Sei, Sonic, Polkadot, Morph, Ink, HyperEVM, Noble… (30+ networks) |
19 +| USDe | Ethereum, Solana, BNB Chain, Base, Arbitrum, Optimism, Mantle, Scroll |
20 +| DAI / USDS | Ethereum, Arbitrum, Optimism, Base, Polygon, Avalanche, BNB Chain, Gnosis, Linea, Scroll, Unichain |
21 +| FDUSD | Ethereum, BNB Chain |
22 +| USDB | Blast, Ethereum |
23 +| PYUSD | Ethereum, Solana |
24 +| RLUSD | XRP Ledger, Ethereum |
25 +| USDG | Ethereum, Solana, Ink |
26 +| TUSD | Ethereum, Tron, BNB Chain, Avalanche |
27 +
28 +> **Status 2026-08-05**: Phase A is **shipped** (11 EVM chains, verified token
29 +> matrix, fee models incl. L1 data fees, keyless RPC failover, native coin
30 +> sends) plus **Bitcoin** (bdk-swift, BIP-84, keyless Esplora) and fiat prices
31 +> (CoinGecko keyless). Non-EVM adapters are next — see
32 +> docs/RESEARCH-MULTICHAIN.md for the full blueprint and the wallet-core
33 +> vendoring path (`scripts/vendor-walletcore.sh`).
34 +
35 +## Phase A — EVM expansion (cheap: registry entries, no new signer)
36 +
37 +Every EVM chain reuses the existing stack unchanged: secp256k1 keys at
38 +m/44'/60'/0'/0/0, EIP-1559 signing, JSON-RPC, ERC-20 calldata. Adding
39 +Ethereum/Arbitrum/Optimism/Polygon/BNB/Avalanche/Scroll/Linea/Gnosis/Blast… =
40 +new `Network.ChainConfig` entries (chain id, RPC, explorer) + token addresses
41 +in the registry, each verified on-chain before shipping (decimals() + symbol()
42 +eth_call), exactly like docs/STABLECOINS.md. Watch out for: legacy-fee chains
43 +(BNB has no EIP-1559 → needs type-0 path), native-gas symbol per chain
44 +(POL, AVAX, BNB…), and chains where USDT is non-standard ERC-20 (no return
45 +value — fine, we don't use the return value).
46 +
47 +## Phase B — Non-EVM chains (new signers, per-family adapters)
48 +
49 +Each family is a `ChainAdapter` implementation (derivation path, address
50 +format, tx builder, RPC protocol):
51 +
52 +- **Solana** (USDC, USDT, PYUSD, USDe, USDG): ed25519 keys (m/44'/501'/…),
53 + SPL-token transfers, its own RPC. Biggest payoff after EVM.
54 +- **Tron** (huge USDT volume): secp256k1 but base58 addresses + TRC-20.
55 +- **XRPL** (RLUSD), **Stellar** (USDC), **TON**, **Aptos/Sui**, **Noble/Cosmos**:
56 + one adapter each, prioritized by user demand.
57 +
58 +The vault format already supports this: one mnemonic → per-chain derivation,
59 +`VaultPayload.derivationPath` becomes a per-adapter map.
60 +
61 +## Phase C — polish
62 +
63 +- On-chain history via explorer APIs per chain (graceful fallback).
64 +- Fiat (USD/CAD/EUR) valuation of balances, price feed optional & privacy-safe.
65 +- Address book, per-token hide/show, Ledger-style hardware signing.
added docs/STABLECOINS.md +94 −0
@@ -0,0 +1,94 @@
1 +<!--
2 + STABLECOINS.md
3 + OS Vault
4 +
5 + Author: Simon-Pierre Boucher
6 + Mail: contact@spboucher.ai
7 +-->
8 +
9 +# How USDC and other stablecoins work (on Base)
10 +
11 +Written before implementation, per project rule: *understand the asset before building the wallet.*
12 +Every address and decimal count below was **verified live on-chain on 2026-08-05** via
13 +`eth_call` against `https://mainnet.base.org` / `https://sepolia.base.org` and the
14 +Etherscan contract-source API — not taken from memory.
15 +
16 +## 1. What a stablecoin is, mechanically
17 +
18 +A stablecoin like USDC is **not a native blockchain asset**. It is an entry in the
19 +storage of an **ERC-20 smart contract**. "Holding 10 USDC" means the USDC contract's
20 +internal `balances[yourAddress]` equals `10_000_000` (10 × 10⁶ base units).
21 +
22 +Consequences for a wallet:
23 +
24 +- **Balances** are read with `balanceOf(address)` (an `eth_call`, selector `0x70a08231`),
25 + not `eth_getBalance` (which returns native ETH).
26 +- **Transfers** are transactions **to the token contract**, with calldata
27 + `transfer(to, amount)` (selector `0xa9059cbb`), `value = 0`. The recipient address
28 + lives inside the calldata, not in the tx `to` field.
29 +- **Gas is always paid in ETH**, never in the stablecoin. A wallet full of USDC with
30 + 0 ETH cannot move — the UI must surface this before the user hits a failed send.
31 +- Incoming/outgoing movements are observed via the contract's `Transfer(from, to, value)`
32 + event logs, which is what explorers index for token history.
33 +
34 +## 2. Issuance models (why "stable")
35 +
36 +| Model | Example | Peg mechanism | Trust assumption |
37 +|---|---|---|---|
38 +| Fiat-backed, centralized | **USDC, EURC** (Circle), **USDT** (Tether) | 1:1 reserves (cash + T-bills); mint/burn on deposit/redemption | Issuer solvency + banking rails |
39 +| Crypto-collateralized | **DAI** (MakerDAO/Sky) | Overcollateralized vaults + rates | Protocol governance + collateral quality |
40 +| Bridged representation | **USDbC** (Base) | Lock on L1, mint wrapped on L2 | The bridge, **plus** the original issuer |
41 +
42 +Key operational facts for fiat-backed coins (USDC family):
43 +
44 +- The contract is an **upgradeable proxy**. Verified: Base USDC is Circle's
45 + `FiatTokenProxy` (AdminUpgradeabilityProxy pattern, implementation at
46 + `0x2ce6311ddae708829bc0784c967b7d77d19fd779`, upgradeable by Circle's admin key).
47 + Behavior can change under the same address — one more reason a wallet should treat
48 + token metadata (decimals) as per-token config, verified on-chain, not assumptions.
49 +- The issuer can **blocklist addresses** (`blacklist(address)` in FiatToken). Funds at a
50 + blocklisted address are frozen at the contract level. Self-custody protects keys, not
51 + against issuer-level freezing — worth knowing, nothing for the wallet to implement.
52 +- Some support gasless-approval extensions (EIP-2612 `permit`, EIP-3009
53 + `transferWithAuthorization`). v1 uses plain `transfer` only.
54 +
55 +## 3. Decimals — the #1 bug source (verified live)
56 +
57 +**Decimals differ per token.** A wallet must never hardcode 6.
58 +
59 +| Token | Base mainnet address (chain 8453) | Decimals | Notes |
60 +|---|---|---|---|
61 +| USDC | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | **6** | Native Circle issue — the default token |
62 +| EURC | `0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42` | **6** | Circle euro coin |
63 +| USDT | `0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2` | **6** | Tether on Base |
64 +| DAI | `0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb` | **18** | ⚠ 18, like ETH — not 6 |
65 +| USDbC | `0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA` | **6** | Legacy bridged USDC; receive/display only, discourage new use |
66 +
67 +Testnet (Base Sepolia, chain 84532): USDC `0x036CbD53842c5426634e7929541eC2318f3dCF7e`,
68 +decimals **6** (verified). Circle faucet: https://faucet.circle.com (20 USDC / 2 h);
69 +gas ETH from a Base Sepolia faucet.
70 +
71 +Rules the code enforces:
72 +- All amounts are `BigUInt` base units internally; `Double` is banned for money.
73 +- Conversion display ⇄ base units goes through per-token `decimals` from the registry
74 + (`TokenAmount`), unit-tested for 6- and 18-decimal tokens.
75 +- ETH (gas) is 18 decimals; wei ⇄ ETH uses the same integer math.
76 +
77 +## 4. Chain facts (verified live)
78 +
79 +- Base mainnet `eth_chainId``0x2105` = **8453**; Base Sepolia → `0x14a34` = **84532**.
80 +- Base is an OP-stack L2: EIP-1559 fees (`maxFeePerGas` / `maxPriorityFeePerGas`),
81 + tips are tiny (fractions of a gwei), an ERC-20 transfer costs well under a cent.
82 +- The signed transaction embeds the chain ID (EIP-155/1559) — replay protection across
83 + Sepolia/mainnet is automatic as long as the wallet signs with the selected network's ID.
84 +
85 +## 5. What this means for OS Vault's design
86 +
87 +- A **token registry** (`Token` model) instead of a hardcoded USDC constant: symbol,
88 + name, per-network contract address, decimals. v1 ships USDC as default with EURC,
89 + DAI, USDT registered; adding a stablecoin is a registry entry, not a code change.
90 +- Per-token balance = one `eth_call` each; ETH balance fetched alongside for the gas
91 + warning ("not enough ETH to send").
92 +- Send flow is token-generic: encode `transfer(to, amount)` with the token's address
93 + and decimals; everything else (nonce, fees, signing, receipt polling) is identical
94 + across stablecoins.
added scripts/make-icon.sh +36 −0
@@ -0,0 +1,36 @@
1 +#!/bin/bash
2 +#
3 +# make-icon.sh
4 +# OS Vault
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Mail: contact@spboucher.ai
8 +#
9 +# SVG → AppIcon.icns. Full-detail SVG for ≥64 px, simplified variant for 16/32 px.
10 +
11 +set -euo pipefail
12 +cd "$(dirname "$0")/../assets/icon"
13 +
14 +RSVG=rsvg-convert
15 +command -v $RSVG >/dev/null || { echo "rsvg-convert not found (brew install librsvg)"; exit 1; }
16 +
17 +ICONSET=AppIcon.iconset
18 +rm -rf "$ICONSET" && mkdir "$ICONSET"
19 +
20 +# 16/32 from the simplified variant (16@2x = 32 px also simplified)
21 +$RSVG -w 16 -h 16 os-vault-simple.svg -o "$ICONSET/icon_16x16.png"
22 +$RSVG -w 32 -h 32 os-vault-simple.svg -o "$ICONSET/icon_16x16@2x.png"
23 +$RSVG -w 32 -h 32 os-vault-simple.svg -o "$ICONSET/icon_32x32.png"
24 +# ≥64 from the full-detail icon
25 +$RSVG -w 64 -h 64 os-vault.svg -o "$ICONSET/icon_32x32@2x.png"
26 +$RSVG -w 128 -h 128 os-vault.svg -o "$ICONSET/icon_128x128.png"
27 +$RSVG -w 256 -h 256 os-vault.svg -o "$ICONSET/icon_128x128@2x.png"
28 +$RSVG -w 256 -h 256 os-vault.svg -o "$ICONSET/icon_256x256.png"
29 +$RSVG -w 512 -h 512 os-vault.svg -o "$ICONSET/icon_256x256@2x.png"
30 +$RSVG -w 512 -h 512 os-vault.svg -o "$ICONSET/icon_512x512.png"
31 +$RSVG -w 1024 -h 1024 os-vault.svg -o "$ICONSET/icon_512x512@2x.png"
32 +
33 +iconutil -c icns "$ICONSET" -o AppIcon.icns
34 +rm -rf "$ICONSET"
35 +
36 +echo "AppIcon.icns generated."
added scripts/release.sh +84 −0
@@ -0,0 +1,84 @@
1 +#!/bin/bash
2 +#
3 +# release.sh
4 +# OS Vault
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Mail: contact@spboucher.ai
8 +#
9 +# Developer ID signing, notarization and stapling for OS Vault.
10 +# Identity and notarytool profile reused from the Zyquo Local/Term pipeline.
11 +#
12 +# Usage:
13 +# scripts/release.sh # full: build + bundle + sign + notarize + staple + dmg
14 +# scripts/release.sh sign|notarize|dmg # individual steps
15 +
16 +set -euo pipefail
17 +cd "$(dirname "$0")/.."
18 +
19 +IDENTITY="Developer ID Application: Simon-Pierre Boucher (3YM54G49SN)"
20 +KEYCHAIN_PROFILE="MacLustr-Notarize"
21 +APP_DIR="dist/OS Vault.app"
22 +ZIP_NAME="dist/OSVault.zip"
23 +DMG_NAME="dist/OSVault.dmg"
24 +ENTITLEMENTS="Support/entitlements.plist"
25 +
26 +build() {
27 + echo "=== Release build + bundle ==="
28 + make bundle-release
29 +}
30 +
31 +sign() {
32 + [ -d "$APP_DIR" ] || { echo "ERROR: $APP_DIR missing — run 'make bundle-release' first" >&2; exit 1; }
33 + echo "=== Signing (Developer ID, hardened runtime, sandboxed) ==="
34 + codesign --force --options runtime --timestamp \
35 + --entitlements "$ENTITLEMENTS" \
36 + --sign "$IDENTITY" "$APP_DIR"
37 + codesign --verify --deep --strict --verbose=2 "$APP_DIR"
38 + echo "Signature valid."
39 +}
40 +
41 +notarize() {
42 + echo "=== Notarizing app (profile: $KEYCHAIN_PROFILE) ==="
43 + rm -f "$ZIP_NAME"
44 + ditto -c -k --keepParent "$APP_DIR" "$ZIP_NAME"
45 + xcrun notarytool submit "$ZIP_NAME" --keychain-profile "$KEYCHAIN_PROFILE" --wait
46 + xcrun stapler staple "$APP_DIR"
47 + xcrun stapler validate "$APP_DIR"
48 + spctl -a -vv "$APP_DIR"
49 + echo "App notarized and stapled."
50 +}
51 +
52 +dmg() {
53 + echo "=== Creating signed + notarized DMG (custom volume icon) ==="
54 + rm -f "$DMG_NAME"
55 + DMG_TEMP="dist/dmg_temp"
56 + DMG_RW="dist/OSVault-rw.dmg"
57 + rm -rf "$DMG_TEMP" "$DMG_RW"
58 + mkdir -p "$DMG_TEMP"
59 + cp -R "$APP_DIR" "$DMG_TEMP/"
60 + ln -s /Applications "$DMG_TEMP/Applications"
61 + cp assets/icon/AppIcon.icns "$DMG_TEMP/.VolumeIcon.icns"
62 +
63 + # Read-write image first so the volume's custom-icon flag can be set,
64 + # then compress to the final UDZO.
65 + hdiutil create -volname "OS Vault" -srcfolder "$DMG_TEMP" -ov -format UDRW "$DMG_RW"
66 + MOUNT_DIR=$(hdiutil attach "$DMG_RW" -nobrowse | awk -F'\t' '/\/Volumes\//{print $NF; exit}')
67 + SetFile -a C "$MOUNT_DIR"
68 + hdiutil detach "$MOUNT_DIR" -quiet
69 + hdiutil convert "$DMG_RW" -format UDZO -o "$DMG_NAME"
70 + rm -rf "$DMG_TEMP" "$DMG_RW"
71 +
72 + codesign --force --sign "$IDENTITY" --timestamp "$DMG_NAME"
73 + xcrun notarytool submit "$DMG_NAME" --keychain-profile "$KEYCHAIN_PROFILE" --wait
74 + xcrun stapler staple "$DMG_NAME"
75 + echo "DMG ready: $DMG_NAME"
76 +}
77 +
78 +case "${1:-dist}" in
79 + sign) sign ;;
80 + notarize) notarize ;;
81 + dmg) dmg ;;
82 + dist) build; sign; notarize; dmg ;;
83 + *) echo "Usage: $0 {sign|notarize|dmg|dist}" >&2; exit 64 ;;
84 +esac
added scripts/vendor-walletcore.sh +129 −0
@@ -0,0 +1,129 @@
1 +#!/bin/bash
2 +#
3 +# vendor-walletcore.sh
4 +# OS Vault
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Mail: contact@spboucher.ai
8 +#
9 +# Vendors Trust wallet-core as a local SwiftPM package with native macOS
10 +# support — the signing engine for the non-EVM expansion (Tron, TON, XRPL,
11 +# Solana fallback…). Upstream's SPM package is iOS-only, but the official
12 +# CocoaPods tarball ships a macos-arm64_x86_64 slice; this script repackages
13 +# it, fully automated (proven working on this machine — see
14 +# docs/RESEARCH-MULTICHAIN.md §wallet-core).
15 +#
16 +# Usage: scripts/vendor-walletcore.sh [version] (default 4.7.2)
17 +
18 +set -euo pipefail
19 +cd "$(dirname "$0")/.."
20 +
21 +VERSION="${1:-4.7.2}"
22 +URL="https://github.com/trustwallet/wallet-core/releases/download/${VERSION}/TrustWalletCore-${VERSION}.tar.xz"
23 +DEST="vendor/WalletCoreSPM"
24 +WORK="$(mktemp -d)"
25 +trap 'rm -rf "$WORK"' EXIT
26 +
27 +echo "=== Downloading official wallet-core ${VERSION} tarball ==="
28 +curl -fL --retry 3 -o "$WORK/twc.tar.xz" "$URL"
29 +tar -xJf "$WORK/twc.tar.xz" -C "$WORK"
30 +# The tarball extracts flat: include/ Sources/ WalletCoreCommon.xcframework
31 +SRC="$WORK"
32 +[ -d "$SRC/include/TrustWalletCore" ] && [ -d "$SRC/Sources" ] && [ -d "$SRC/WalletCoreCommon.xcframework" ] ||
33 + { echo "ERROR: tarball layout unexpected" >&2; exit 1; }
34 +
35 +echo "=== Assembling local SwiftPM package in $DEST ==="
36 +rm -rf "$DEST"
37 +mkdir -p "$DEST/Sources/WalletCoreC/include" "$DEST/Sources/WalletCore"
38 +
39 +# C target: public headers + the Security.framework RNG shim (SECURITY-CRITICAL:
40 +# trezor-crypto takes entropy from these consumer-provided symbols).
41 +cp -R "$SRC/include/TrustWalletCore" "$DEST/Sources/WalletCoreC/include/"
42 +find "$SRC" -name 'SecRandom.m' -exec cp {} "$DEST/Sources/WalletCoreC/" \;
43 +[ -f "$DEST/Sources/WalletCoreC/SecRandom.m" ] || { echo "ERROR: SecRandom.m missing" >&2; exit 1; }
44 +
45 +# Swift wrappers: rename the protobuf module, inject imports SPM needs.
46 +cp -R "$SRC/Sources/." "$DEST/Sources/WalletCore/"
47 +# Swift target must be Swift-only (SecRandom.m lives in WalletCoreC).
48 +find "$DEST/Sources/WalletCore" \( -name '*.m' -o -name '*.h' \) -delete
49 +# Global rename: the generated code also uses the module as a type qualifier.
50 +find "$DEST/Sources/WalletCore" -name '*.swift' -exec sed -i '' \
51 + -e 's/WalletCoreSwiftProtobuf/SwiftProtobuf/g' {} \;
52 +find "$DEST/Sources/WalletCore" -name '*.swift' -exec sed -i '' \
53 + -e '1s/^/import WalletCoreC\nimport Foundation\n/' {} \;
54 +
55 +# Native binary (contains the macos-arm64_x86_64 slice).
56 +cp -R "$SRC/WalletCoreCommon.xcframework" "$DEST/"
57 +plutil -p "$DEST/WalletCoreCommon.xcframework/Info.plist" | grep -q macos ||
58 + { echo "ERROR: no macOS slice in xcframework" >&2; exit 1; }
59 +
60 +# De-duplicate the Rust runtime: both wallet-core and bdkFFI (Bitcoin Dev Kit)
61 +# statically embed Rust's std, and the linker rejects the duplicate global
62 +# `_rust_eh_personality`. Demote wallet-core's copy to private in the single
63 +# archive member that defines it (surgical — merging the whole archive breaks
64 +# unused-member semantics).
65 +echo "=== Demoting duplicate _rust_eh_personality in the macOS slice ==="
66 +BIN="$DEST/WalletCoreCommon.xcframework/macos-arm64_x86_64/WalletCoreCommon.framework/Versions/A/WalletCoreCommon"
67 +FIX="$WORK/rustfix"
68 +mkdir -p "$FIX"
69 +for arch in arm64 x86_64; do
70 + mkdir -p "$FIX/$arch"
71 + ( cd "$FIX/$arch"
72 + lipo "$BIN" -thin "$arch" -output slice.a
73 + MEMBER=$(nm -gU -A slice.a 2>/dev/null | grep " T _rust_eh_personality" | head -1 | cut -d: -f2)
74 + [ -n "$MEMBER" ] || { echo "no duplicate in $arch (upstream fixed?) — skipping"; exit 0; }
75 + ar -x slice.a "$MEMBER"
76 + ld -r -arch "$arch" -platform_version macos 13.0 15.5 "$MEMBER" -o patched.o \
77 + -unexported_symbol _rust_eh_personality 2>/dev/null
78 + mv patched.o "$MEMBER"
79 + ar -r -s slice.a "$MEMBER" 2>/dev/null )
80 +done
81 +lipo -create "$FIX/arm64/slice.a" "$FIX/x86_64/slice.a" -output "$BIN"
82 +
83 +cat > "$DEST/Package.swift" <<'EOF'
84 +// swift-tools-version:5.10
85 +// Auto-generated by scripts/vendor-walletcore.sh — do not edit by hand.
86 +// The prebuilt static framework is exposed as a local binaryTarget (no
87 +// unsafeFlags — those would make the package unusable as a dependency).
88 +import PackageDescription
89 +
90 +let package = Package(
91 + name: "WalletCoreSPM",
92 + platforms: [.macOS(.v13)],
93 + products: [
94 + .library(name: "WalletCore", targets: ["WalletCore"])
95 + ],
96 + dependencies: [
97 + .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.29.0")
98 + ],
99 + targets: [
100 + .binaryTarget(
101 + name: "WalletCoreBinary",
102 + path: "WalletCoreCommon.xcframework"
103 + ),
104 + .target(
105 + name: "WalletCoreC",
106 + dependencies: ["WalletCoreBinary"],
107 + path: "Sources/WalletCoreC",
108 + publicHeadersPath: "include"
109 + ),
110 + .target(
111 + name: "WalletCore",
112 + dependencies: [
113 + "WalletCoreC",
114 + .product(name: "SwiftProtobuf", package: "swift-protobuf")
115 + ],
116 + path: "Sources/WalletCore",
117 + linkerSettings: [
118 + .linkedLibrary("c++"),
119 + .linkedFramework("Security")
120 + ]
121 + )
122 + ]
123 +)
124 +EOF
125 +
126 +echo "=== Done ==="
127 +echo "Vendored wallet-core ${VERSION} → $DEST"
128 +echo "Add to Package.swift deps: .package(path: \"vendor/WalletCoreSPM\") and"
129 +echo "product .product(name: \"WalletCore\", package: \"WalletCoreSPM\")."
\ No newline at end of file
added vendor/WalletCoreSPM/Package.swift +40 −0
@@ -0,0 +1,40 @@
1 +// swift-tools-version:5.10
2 +// Auto-generated by scripts/vendor-walletcore.sh — do not edit by hand.
3 +// The prebuilt static framework is exposed as a local binaryTarget (no
4 +// unsafeFlags — those would make the package unusable as a dependency).
5 +import PackageDescription
6 +
7 +let package = Package(
8 + name: "WalletCoreSPM",
9 + platforms: [.macOS(.v13)],
10 + products: [
11 + .library(name: "WalletCore", targets: ["WalletCore"])
12 + ],
13 + dependencies: [
14 + .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.29.0")
15 + ],
16 + targets: [
17 + .binaryTarget(
18 + name: "WalletCoreBinary",
19 + path: "WalletCoreCommon.xcframework"
20 + ),
21 + .target(
22 + name: "WalletCoreC",
23 + dependencies: ["WalletCoreBinary"],
24 + path: "Sources/WalletCoreC",
25 + publicHeadersPath: "include"
26 + ),
27 + .target(
28 + name: "WalletCore",
29 + dependencies: [
30 + "WalletCoreC",
31 + .product(name: "SwiftProtobuf", package: "swift-protobuf")
32 + ],
33 + path: "Sources/WalletCore",
34 + linkerSettings: [
35 + .linkedLibrary("c++"),
36 + .linkedFramework("Security")
37 + ]
38 + )
39 + ]
40 +)
added vendor/WalletCoreSPM/Sources/WalletCore/AnySigner.swift +96 −0
@@ -0,0 +1,96 @@
1 +import WalletCoreC
2 +import Foundation
3 +// Copyright © 2017-2018 Trust.
4 +//
5 +// This file is part of Trust. The full Trust copyright notice, including
6 +// terms governing use, modification, and redistribution, is contained in the
7 +// file LICENSE at the root of the source code distribution tree.
8 +
9 +import Foundation
10 +import SwiftProtobuf
11 +
12 +public typealias SigningInput = Message
13 +public typealias SigningOutput = Message
14 +
15 +/// Represents a signer to sign transactions for any blockchain.
16 +public final class AnySigner {
17 +
18 + /// Signs a transaction by SigningInput message and coin type
19 + ///
20 + /// - Parameters:
21 + /// - input: The generic SigningInput SwiftProtobuf message
22 + /// - coin: CoinType
23 + /// - Returns: The generic SigningOutput SwiftProtobuf message
24 + public static func sign<SigningOutput: Message>(input: SigningInput, coin: CoinType) -> SigningOutput {
25 + do {
26 + let outputData = nativeSign(data: try input.serializedData(), coin: coin)
27 + return try SigningOutput(serializedBytes: outputData)
28 + } catch let error {
29 + fatalError(error.localizedDescription)
30 + }
31 + }
32 +
33 + /// Signs a transaction by serialized data of a SigningInput and coin type
34 + ///
35 + /// - Parameters:
36 + /// - data: The serialized data of a SigningInput
37 + /// - coin: CoinType
38 + /// - Returns: The serialized data of a SigningOutput
39 + public static func nativeSign(data: Data, coin: CoinType) -> Data {
40 + let inputData = TWDataCreateWithNSData(data)
41 + defer {
42 + TWDataDelete(inputData)
43 + }
44 + return TWDataNSData(TWAnySignerSign(inputData, TWCoinType(rawValue: coin.rawValue)))
45 + }
46 +
47 + /// Check if AnySigner supports signing JSON representation of SigningInput for a given coin.
48 + public static func supportsJSON(coin: CoinType) -> Bool {
49 + return TWAnySignerSupportsJSON(TWCoinType(rawValue: coin.rawValue))
50 + }
51 +
52 + /// Signs a transaction specified by the JSON representation of a SigningInput, coin type and a private key
53 + ///
54 + /// - Parameters:
55 + /// - json: JSON representation of a SigningInput
56 + /// - key: The private key data
57 + /// - coin: CoinType
58 + /// - Returns: The JSON representation of a SigningOutput.
59 + public static func signJSON(_ json: String, key: Data, coin: CoinType) -> String {
60 + let jsonString = TWStringCreateWithNSString(json)
61 + let keyData = TWDataCreateWithNSData(key)
62 + defer {
63 + TWDataDelete(keyData)
64 + }
65 + return TWStringNSString(TWAnySignerSignJSON(jsonString, keyData, TWCoinType(rawValue: coin.rawValue)))
66 + }
67 +
68 + /// Plans a transaction (for UTXO chains only).
69 + ///
70 + /// - Parameters:
71 + /// - input: The generic SigningInput SwiftProtobuf message
72 + /// - coin: CoinType
73 + /// - Returns: TransactionPlan SwiftProtobuf message
74 + public static func plan<TransactionPlan: Message>(input: SigningInput, coin: CoinType) -> TransactionPlan {
75 + do {
76 + let outputData = nativePlan(data: try input.serializedData(), coin: coin)
77 + return try TransactionPlan(serializedBytes: outputData)
78 + } catch let error {
79 + fatalError(error.localizedDescription)
80 + }
81 + }
82 +
83 + /// Plans a transaction (for UTXO chains only).
84 + ///
85 + /// - Parameters:
86 + /// - input: The serialized data of a SigningInput
87 + /// - coin: CoinType
88 + /// - Returns: The serialized data of a TransactionPlan
89 + public static func nativePlan(data: Data, coin: CoinType) -> Data {
90 + let inputData = TWDataCreateWithNSData(data)
91 + defer {
92 + TWDataDelete(inputData)
93 + }
94 + return TWDataNSData(TWAnySignerPlan(inputData, TWCoinType(rawValue: coin.rawValue)))
95 + }
96 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/Account+Codable.swift +92 −0
@@ -0,0 +1,92 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +import Foundation
8 +
9 +extension Account: Equatable {
10 + public static func == (lhs: Account, rhs: Account) -> Bool {
11 + return lhs.coin == rhs.coin &&
12 + lhs.address == rhs.address &&
13 + lhs.derivation == rhs.derivation &&
14 + lhs.derivationPath == rhs.derivationPath &&
15 + lhs.publicKey == rhs.publicKey &&
16 + lhs.extendedPublicKey == rhs.extendedPublicKey
17 + }
18 +}
19 +
20 +extension Account: Hashable {
21 + public func hash(into hasher: inout Hasher) {
22 + hasher.combine(coin)
23 + hasher.combine(address)
24 + hasher.combine(derivation)
25 + hasher.combine(derivationPath)
26 + hasher.combine(publicKey)
27 + hasher.combine(extendedPublicKey)
28 + }
29 +}
30 +
31 +extension Account: Codable {
32 + private enum CodingKeys: String, CodingKey {
33 + case coin
34 + case address
35 + case derivation
36 + case derivationPath
37 + case publicKey
38 + case extendedPublicKey
39 + }
40 +
41 + public func encode(to encoder: Encoder) throws {
42 + var container = encoder.container(keyedBy: CodingKeys.self)
43 + try container.encode(coin.rawValue, forKey: .coin)
44 + try container.encode(address, forKey: .address)
45 + try container.encode(derivation.rawValue, forKey: .derivation)
46 + try container.encode(derivationPath, forKey: .derivationPath)
47 + try container.encode(publicKey, forKey: .publicKey)
48 + try container.encode(extendedPublicKey, forKey: .extendedPublicKey)
49 + }
50 +
51 + public convenience init(from decoder: Decoder) throws {
52 + let container = try decoder.container(keyedBy: CodingKeys.self)
53 + let rawCoin = try container.decode(UInt32.self, forKey: .coin)
54 + let address = try container.decode(String.self, forKey: .address)
55 + let rawDerivation = try container.decode(UInt32.self, forKey: .derivation)
56 + let derivationPath = try container.decode(String.self, forKey: .derivationPath)
57 + let publicKey = try container.decode(String.self, forKey: .publicKey)
58 + let extendedPublicKey = try container.decode(String.self, forKey: .extendedPublicKey)
59 +
60 + guard let coin = CoinType(rawValue: rawCoin) else {
61 + throw DecodingError.dataCorruptedError(forKey: .coin, in: container,
62 + debugDescription: "Unknown coin type: \(rawCoin)")
63 + }
64 + guard let derivation = Derivation(rawValue: rawDerivation) else {
65 + throw DecodingError.dataCorruptedError(forKey: .derivation, in: container,
66 + debugDescription: "Unknown derivation: \(rawDerivation)")
67 + }
68 + // Call TWAccountCreate directly rather than using the Account failable init:
69 + // if we created an intermediate Account and copied its rawValue, that wrapper's
70 + // deinit would call TWAccountDelete before self uses the pointer (use-after-free).
71 + let addressString = TWStringCreateWithNSString(address)
72 + defer { TWStringDelete(addressString) }
73 + let derivationPathString = TWStringCreateWithNSString(derivationPath)
74 + defer { TWStringDelete(derivationPathString) }
75 + let publicKeyString = TWStringCreateWithNSString(publicKey)
76 + defer { TWStringDelete(publicKeyString) }
77 + let extendedPublicKeyString = TWStringCreateWithNSString(extendedPublicKey)
78 + defer { TWStringDelete(extendedPublicKeyString) }
79 + guard let rawValue = TWAccountCreate(
80 + addressString,
81 + TWCoinType(rawValue: coin.rawValue),
82 + TWDerivation(rawValue: derivation.rawValue),
83 + derivationPathString,
84 + publicKeyString,
85 + extendedPublicKeyString
86 + ) else {
87 + throw DecodingError.dataCorruptedError(forKey: .derivationPath, in: container,
88 + debugDescription: "Invalid derivation path: \(derivationPath)")
89 + }
90 + self.init(rawValue: rawValue)
91 + }
92 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/AddressProtocol.swift +12 −0
@@ -0,0 +1,12 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +import Foundation
8 +
9 +/// Generic Address protocol for AnyAddress / SegwitAddress / SolanaAddress
10 +public protocol Address: CustomStringConvertible {}
11 +
12 +extension AnyAddress: Equatable {}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/BitcoinAddress+Extension.swift +25 −0
@@ -0,0 +1,25 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +import Foundation
8 +
9 +extension BitcoinAddress: Equatable {
10 + public var base58String: String {
11 + return description
12 + }
13 +
14 + public func hash(into hasher: inout Hasher) {
15 + hasher.combine(description)
16 + }
17 +
18 + /// Creates a legacy Bitcoin address for segwit redeem script.
19 + public static func compatibleAddress(publicKey: PublicKey, prefix: UInt8) -> BitcoinAddress {
20 + let witnessVersion = Data([0x00, 0x14])
21 + let redeemScript = Hash.sha256RIPEMD(data: witnessVersion + publicKey.bitcoinKeyHash)
22 + let address = Base58.encode(data: [prefix] + redeemScript)
23 + return BitcoinAddress(string: address)!
24 + }
25 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/CoinType+Address.swift +14 −0
@@ -0,0 +1,14 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +import Foundation
8 +
9 +public extension CoinType {
10 + /// Converts a string to an address for this coin type.
11 + func address(string: String) -> AnyAddress? {
12 + return AnyAddress(string: string, coin: self)
13 + }
14 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/Data+Hex.swift +84 −0
@@ -0,0 +1,84 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +import Foundation
8 +
9 +extension Data {
10 + /// Initializes `Data` with a hex string representation.
11 + public init?(hexString: String) {
12 + let string: String
13 + if hexString.hasPrefix("0x") {
14 + string = String(hexString.dropFirst(2))
15 + } else {
16 + string = hexString
17 + }
18 +
19 + // Check odd length hex string
20 + if string.count % 2 != 0 {
21 + return nil
22 + }
23 +
24 + // Check odd characters
25 + if string.contains(where: { !$0.isHexDigit }) {
26 + return nil
27 + }
28 +
29 + // Convert the string to bytes for better performance
30 + guard let stringData = string.data(using: .ascii, allowLossyConversion: true) else {
31 + return nil
32 + }
33 +
34 + self.init(capacity: string.count / 2)
35 + let stringBytes = Array(stringData)
36 + for i in stride(from: 0, to: stringBytes.count, by: 2) {
37 + guard let high = Data.value(of: stringBytes[i]) else {
38 + return nil
39 + }
40 + if i < stringBytes.count - 1, let low = Data.value(of: stringBytes[i + 1]) {
41 + append((high << 4) | low)
42 + } else {
43 + append(high)
44 + }
45 + }
46 + }
47 +
48 + /// Converts an ASCII byte to a hex value.
49 + private static func value(of nibble: UInt8) -> UInt8? {
50 + guard let letter = String(bytes: [nibble], encoding: .ascii) else { return nil }
51 + return UInt8(letter, radix: 16)
52 + }
53 +
54 + /// Reverses and parses hex string as `Data`
55 + public static func reverse(hexString: String) -> Data {
56 + guard let data = Data(hexString: hexString) else { return Data() }
57 + return Data(data.reversed())
58 + }
59 +
60 + /// Returns the hex string representation of the data.
61 + public var hexString: String {
62 + return map({ String(format: "%02x", $0) }).joined()
63 + }
64 +}
65 +
66 +public extension KeyedDecodingContainerProtocol {
67 + func decodeHexString(forKey key: Self.Key) throws -> Data {
68 + let hexString = try decode(String.self, forKey: key)
69 + guard let data = Data(hexString: hexString) else {
70 + throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Expected hexadecimal string")
71 + }
72 + return data
73 + }
74 +
75 + func decodeHexStringIfPresent(forKey key: Self.Key) throws -> Data? {
76 + guard let hexString = try decodeIfPresent(String.self, forKey: key) else {
77 + return nil
78 + }
79 + guard let data = Data(hexString: hexString) else {
80 + throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Expected hexadecimal string")
81 + }
82 + return data
83 + }
84 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/DerivationPath+Extension.swift +119 −0
@@ -0,0 +1,119 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +import Foundation
8 +
9 +extension DerivationPath: Equatable, Hashable, CustomStringConvertible {
10 +
11 + public typealias Index = DerivationPathIndex
12 +
13 + public static func == (lhs: DerivationPath, rhs: DerivationPath) -> Bool {
14 + return lhs.description == rhs.description
15 + }
16 +
17 + public var coinType: UInt32 {
18 + coin
19 + }
20 +
21 + public var indices: [Index] {
22 + var result = [Index]()
23 + for i in 0..<indicesCount() {
24 + guard let index = indexAt(index: i) else {
25 + continue
26 + }
27 + result.append(index)
28 + }
29 + return result
30 + }
31 +
32 + public convenience init(purpose: Purpose, coin: UInt32) {
33 + self.init(purpose: purpose, coin: coin, account: 0, change: 0, address: 0)
34 + }
35 +
36 + public convenience init?(_ string: String) {
37 + self.init(string: string)
38 + }
39 +
40 + public subscript(index: Int) -> DerivationPathIndex? {
41 + return self.indexAt(index: UInt32(index))
42 + }
43 +
44 + public func hash(into hasher: inout Hasher) {
45 + let count = indicesCount()
46 + for i in 0..<count {
47 + hasher.combine(self[Int(i)])
48 + }
49 + }
50 +}
51 +
52 +extension DerivationPath: Codable {
53 + private enum CodingKeys: String, CodingKey {
54 + case purpose
55 + case coin
56 + case account
57 + case change
58 + case address
59 + }
60 +
61 + public func encode(to encoder: Encoder) throws {
62 + var container = encoder.container(keyedBy: CodingKeys.self)
63 + try container.encode(purpose.rawValue, forKey: .purpose)
64 + try container.encode(coin, forKey: .coin)
65 + try container.encode(account, forKey: .account)
66 + try container.encode(change, forKey: .change)
67 + try container.encode(address, forKey: .address)
68 + }
69 +
70 + public convenience init(from decoder: Decoder) throws {
71 + let container = try decoder.container(keyedBy: CodingKeys.self)
72 + let purpose = try container.decode(UInt32.self, forKey: .purpose)
73 + guard
74 + let purposeEnum = Purpose(rawValue: purpose)
75 + else {
76 + throw DecodingError.dataCorruptedError(forKey: CodingKeys.purpose, in: container, debugDescription: "purpose value is not valid")
77 + }
78 + let coin = try container.decode(UInt32.self, forKey: .coin)
79 + let account = try container.decode(UInt32.self, forKey: .account)
80 + let change = try container.decode(UInt32.self, forKey: .change)
81 + let address = try container.decode(UInt32.self, forKey: .address)
82 + self.init(purpose: purposeEnum, coin: coin, account: account, change: change, address: address)
83 + }
84 +}
85 +
86 +extension DerivationPathIndex: Equatable, Hashable, CustomStringConvertible {
87 + public static func == (lhs: DerivationPathIndex, rhs: DerivationPathIndex) -> Bool {
88 + return lhs.value == rhs.value && lhs.hardened == rhs.hardened
89 + }
90 +
91 + public convenience init(_ value: UInt32, hardened: Bool) {
92 + self.init(value: value, hardened: hardened)
93 + }
94 +
95 + public func hash(into hasher: inout Hasher) {
96 + hasher.combine(value)
97 + hasher.combine(hardened)
98 + }
99 +}
100 +
101 +extension DerivationPathIndex: Codable {
102 + private enum CodingKeys: String, CodingKey {
103 + case value
104 + case hardened
105 + }
106 +
107 + public func encode(to encoder: Encoder) throws {
108 + var container = encoder.container(keyedBy: CodingKeys.self)
109 + try container.encode(value, forKey: .value)
110 + try container.encode(hardened, forKey: .hardened)
111 + }
112 +
113 + public convenience init(from decoder: Decoder) throws {
114 + let container = try decoder.container(keyedBy: CodingKeys.self)
115 + let value = try container.decode(UInt32.self, forKey: .value)
116 + let hardened = try container.decode(Bool.self, forKey: .hardened)
117 + self.init(value: value, hardened: hardened)
118 + }
119 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/Mnemonic+Extension.swift +26 −0
@@ -0,0 +1,26 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +import Foundation
8 +
9 +public extension Mnemonic {
10 + typealias ValidationResult = (word: String, index: Int)
11 +
12 + /// Returns mnemonic validation result, an array of wrong word and index tuple
13 + static func validate(mnemonic: [String]) -> [ValidationResult] {
14 + mnemonic.enumerated().compactMap { (index, word) -> ValidationResult? in
15 + if isValidWord(word: word) {
16 + return nil
17 + }
18 + return (word, index)
19 + }
20 + }
21 +
22 + /// Returns matched suggestion in a native array
23 + static func search(prefix: String) -> [String] {
24 + return suggest(prefix: prefix).split(separator: " ").map { String($0) }
25 + }
26 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Extensions/PublicKey+Bitcoin.swift +12 −0
@@ -0,0 +1,12 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public extension PublicKey {
8 + /// Returns the ripemd160 hash of the sha2 hash of the compressed public key data.
9 + var bitcoinKeyHash: Data {
10 + return Hash.sha256RIPEMD(data: compressed.data)
11 + }
12 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/AES.swift +122 −0
@@ -0,0 +1,122 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// AES encryption/decryption methods.
13 +public struct AES {
14 +
15 + /// Encrypts a block of Data using AES in Cipher Block Chaining (CBC) mode.
16 + ///
17 + /// - Parameter key: encryption key Data, must be 16, 24, or 32 bytes long.
18 + /// - Parameter data: Data to encrypt.
19 + /// - Parameter iv: initialization vector.
20 + /// - Parameter mode: padding mode.
21 + /// - Returns: encrypted Data.
22 + public static func encryptCBC(key: Data, data: Data, iv: Data, mode: AESPaddingMode) -> Data? {
23 + let keyData = TWDataCreateWithNSData(key)
24 + defer {
25 + TWDataDelete(keyData)
26 + }
27 + let dataData = TWDataCreateWithNSData(data)
28 + defer {
29 + TWDataDelete(dataData)
30 + }
31 + let ivData = TWDataCreateWithNSData(iv)
32 + defer {
33 + TWDataDelete(ivData)
34 + }
35 + guard let result = TWAESEncryptCBC(keyData, dataData, ivData, TWAESPaddingMode(rawValue: mode.rawValue)) else {
36 + return nil
37 + }
38 + return TWDataNSData(result)
39 + }
40 +
41 + /// Decrypts a block of data using AES in Cipher Block Chaining (CBC) mode.
42 + ///
43 + /// - Parameter key: decryption key Data, must be 16, 24, or 32 bytes long.
44 + /// - Parameter data: Data to decrypt.
45 + /// - Parameter iv: initialization vector Data.
46 + /// - Parameter mode: padding mode.
47 + /// - Returns: decrypted Data.
48 + public static func decryptCBC(key: Data, data: Data, iv: Data, mode: AESPaddingMode) -> Data? {
49 + let keyData = TWDataCreateWithNSData(key)
50 + defer {
51 + TWDataDelete(keyData)
52 + }
53 + let dataData = TWDataCreateWithNSData(data)
54 + defer {
55 + TWDataDelete(dataData)
56 + }
57 + let ivData = TWDataCreateWithNSData(iv)
58 + defer {
59 + TWDataDelete(ivData)
60 + }
61 + guard let result = TWAESDecryptCBC(keyData, dataData, ivData, TWAESPaddingMode(rawValue: mode.rawValue)) else {
62 + return nil
63 + }
64 + return TWDataNSData(result)
65 + }
66 +
67 + /// Encrypts a block of data using AES in Counter (CTR) mode.
68 + ///
69 + /// - Parameter key: encryption key Data, must be 16, 24, or 32 bytes long.
70 + /// - Parameter data: Data to encrypt.
71 + /// - Parameter iv: initialization vector Data.
72 + /// - Returns: encrypted Data.
73 + public static func encryptCTR(key: Data, data: Data, iv: Data) -> Data? {
74 + let keyData = TWDataCreateWithNSData(key)
75 + defer {
76 + TWDataDelete(keyData)
77 + }
78 + let dataData = TWDataCreateWithNSData(data)
79 + defer {
80 + TWDataDelete(dataData)
81 + }
82 + let ivData = TWDataCreateWithNSData(iv)
83 + defer {
84 + TWDataDelete(ivData)
85 + }
86 + guard let result = TWAESEncryptCTR(keyData, dataData, ivData) else {
87 + return nil
88 + }
89 + return TWDataNSData(result)
90 + }
91 +
92 + /// Decrypts a block of data using AES in Counter (CTR) mode.
93 + ///
94 + /// - Parameter key: decryption key Data, must be 16, 24, or 32 bytes long.
95 + /// - Parameter data: Data to decrypt.
96 + /// - Parameter iv: initialization vector Data.
97 + /// - Returns: decrypted Data.
98 + public static func decryptCTR(key: Data, data: Data, iv: Data) -> Data? {
99 + let keyData = TWDataCreateWithNSData(key)
100 + defer {
101 + TWDataDelete(keyData)
102 + }
103 + let dataData = TWDataCreateWithNSData(data)
104 + defer {
105 + TWDataDelete(dataData)
106 + }
107 + let ivData = TWDataCreateWithNSData(iv)
108 + defer {
109 + TWDataDelete(ivData)
110 + }
111 + guard let result = TWAESDecryptCTR(keyData, dataData, ivData) else {
112 + return nil
113 + }
114 + return TWDataNSData(result)
115 + }
116 +
117 +
118 + init() {
119 + }
120 +
121 +
122 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Account.swift +90 −0
@@ -0,0 +1,90 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents an Account in C++ with address, coin type and public key info, an item within a keystore.
13 +public final class Account {
14 +
15 + /// Returns the address of an account.
16 + ///
17 + /// - Parameter account: Account to get the address of.
18 + public var address: String {
19 + return TWStringNSString(TWAccountAddress(rawValue))
20 + }
21 +
22 + /// Return CoinType enum of an account.
23 + ///
24 + /// - Parameter account: Account to get the coin type of.
25 + public var coin: CoinType {
26 + return CoinType(rawValue: TWAccountCoin(rawValue).rawValue)!
27 + }
28 +
29 + /// Returns the derivation enum of an account.
30 + ///
31 + /// - Parameter account: Account to get the derivation enum of.
32 + public var derivation: Derivation {
33 + return Derivation(rawValue: TWAccountDerivation(rawValue).rawValue)!
34 + }
35 +
36 + /// Returns derivationPath of an account.
37 + ///
38 + /// - Parameter account: Account to get the derivation path of.
39 + public var derivationPath: String {
40 + return TWStringNSString(TWAccountDerivationPath(rawValue))
41 + }
42 +
43 + /// Returns hex encoded publicKey of an account.
44 + ///
45 + /// - Parameter account: Account to get the public key of.
46 + public var publicKey: String {
47 + return TWStringNSString(TWAccountPublicKey(rawValue))
48 + }
49 +
50 + /// Returns Base58 encoded extendedPublicKey of an account.
51 + ///
52 + /// - Parameter account: Account to get the extended public key of.
53 + public var extendedPublicKey: String {
54 + return TWStringNSString(TWAccountExtendedPublicKey(rawValue))
55 + }
56 +
57 + let rawValue: OpaquePointer
58 +
59 + init(rawValue: OpaquePointer) {
60 + self.rawValue = rawValue
61 + }
62 +
63 + public init?(address: String, coin: CoinType, derivation: Derivation, derivationPath: String, publicKey: String, extendedPublicKey: String) {
64 + let addressString = TWStringCreateWithNSString(address)
65 + defer {
66 + TWStringDelete(addressString)
67 + }
68 + let derivationPathString = TWStringCreateWithNSString(derivationPath)
69 + defer {
70 + TWStringDelete(derivationPathString)
71 + }
72 + let publicKeyString = TWStringCreateWithNSString(publicKey)
73 + defer {
74 + TWStringDelete(publicKeyString)
75 + }
76 + let extendedPublicKeyString = TWStringCreateWithNSString(extendedPublicKey)
77 + defer {
78 + TWStringDelete(extendedPublicKeyString)
79 + }
80 + guard let rawValue = TWAccountCreate(addressString, TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue), derivationPathString, publicKeyString, extendedPublicKeyString) else {
81 + return nil
82 + }
83 + self.rawValue = rawValue
84 + }
85 +
86 + deinit {
87 + TWAccountDelete(rawValue)
88 + }
89 +
90 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/AnyAddress.swift +165 −0
@@ -0,0 +1,165 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents an address in C++ for almost any blockchain.
13 +public final class AnyAddress: Address {
14 +
15 + /// Compares two addresses for equality.
16 + ///
17 + /// - Parameter lhs: The first address to compare.
18 + /// - Parameter rhs: The second address to compare.
19 + /// - Returns: bool indicating the addresses are equal.
20 + public static func == (lhs: AnyAddress, rhs: AnyAddress) -> Bool {
21 + return TWAnyAddressEqual(lhs.rawValue, rhs.rawValue)
22 + }
23 +
24 + /// Determines if the string is a valid Any address.
25 + ///
26 + /// - Parameter string: address to validate.
27 + /// - Parameter coin: coin type of the address.
28 + /// - Returns: bool indicating if the address is valid.
29 + public static func isValid(string: String, coin: CoinType) -> Bool {
30 + let stringString = TWStringCreateWithNSString(string)
31 + defer {
32 + TWStringDelete(stringString)
33 + }
34 + return TWAnyAddressIsValid(stringString, TWCoinType(rawValue: coin.rawValue))
35 + }
36 +
37 + /// Determines if the string is a valid Any address with the given hrp.
38 + ///
39 + /// - Parameter string: address to validate.
40 + /// - Parameter coin: coin type of the address.
41 + /// - Parameter hrp: explicit given hrp of the given address.
42 + /// - Returns: bool indicating if the address is valid.
43 + public static func isValidBech32(string: String, coin: CoinType, hrp: String) -> Bool {
44 + let stringString = TWStringCreateWithNSString(string)
45 + defer {
46 + TWStringDelete(stringString)
47 + }
48 + let hrpString = TWStringCreateWithNSString(hrp)
49 + defer {
50 + TWStringDelete(hrpString)
51 + }
52 + return TWAnyAddressIsValidBech32(stringString, TWCoinType(rawValue: coin.rawValue), hrpString)
53 + }
54 +
55 + /// Determines if the string is a valid Any address with the given SS58 network prefix.
56 + ///
57 + /// - Parameter string: address to validate.
58 + /// - Parameter coin: coin type of the address.
59 + /// - Parameter ss58Prefix: ss58Prefix of the given address.
60 + /// - Returns: bool indicating if the address is valid.
61 + public static func isValidSS58(string: String, coin: CoinType, ss58Prefix: UInt32) -> Bool {
62 + let stringString = TWStringCreateWithNSString(string)
63 + defer {
64 + TWStringDelete(stringString)
65 + }
66 + return TWAnyAddressIsValidSS58(stringString, TWCoinType(rawValue: coin.rawValue), ss58Prefix)
67 + }
68 +
69 + /// Returns the address string representation.
70 + ///
71 + /// - Parameter address: address to get the string representation of.
72 + public var description: String {
73 + return TWStringNSString(TWAnyAddressDescription(rawValue))
74 + }
75 +
76 + /// Returns coin type of address.
77 + ///
78 + /// - Parameter address: address to get the coin type of.
79 + public var coin: CoinType {
80 + return CoinType(rawValue: TWAnyAddressCoin(rawValue).rawValue)!
81 + }
82 +
83 + /// Returns underlaying data (public key or key hash)
84 + ///
85 + /// - Parameter address: address to get the data of.
86 + public var data: Data {
87 + return TWDataNSData(TWAnyAddressData(rawValue))
88 + }
89 +
90 + let rawValue: OpaquePointer
91 +
92 + init(rawValue: OpaquePointer) {
93 + self.rawValue = rawValue
94 + }
95 +
96 + public init?(string: String, coin: CoinType) {
97 + let stringString = TWStringCreateWithNSString(string)
98 + defer {
99 + TWStringDelete(stringString)
100 + }
101 + guard let rawValue = TWAnyAddressCreateWithString(stringString, TWCoinType(rawValue: coin.rawValue)) else {
102 + return nil
103 + }
104 + self.rawValue = rawValue
105 + }
106 +
107 + public init?(string: String, coin: CoinType, hrp: String) {
108 + let stringString = TWStringCreateWithNSString(string)
109 + defer {
110 + TWStringDelete(stringString)
111 + }
112 + let hrpString = TWStringCreateWithNSString(hrp)
113 + defer {
114 + TWStringDelete(hrpString)
115 + }
116 + guard let rawValue = TWAnyAddressCreateBech32(stringString, TWCoinType(rawValue: coin.rawValue), hrpString) else {
117 + return nil
118 + }
119 + self.rawValue = rawValue
120 + }
121 +
122 + public init?(string: String, coin: CoinType, ss58Prefix: UInt32) {
123 + let stringString = TWStringCreateWithNSString(string)
124 + defer {
125 + TWStringDelete(stringString)
126 + }
127 + guard let rawValue = TWAnyAddressCreateSS58(stringString, TWCoinType(rawValue: coin.rawValue), ss58Prefix) else {
128 + return nil
129 + }
130 + self.rawValue = rawValue
131 + }
132 +
133 + public init(publicKey: PublicKey, coin: CoinType) {
134 + rawValue = TWAnyAddressCreateWithPublicKey(publicKey.rawValue, TWCoinType(rawValue: coin.rawValue))
135 + }
136 +
137 + public init(publicKey: PublicKey, coin: CoinType, derivation: Derivation) {
138 + rawValue = TWAnyAddressCreateWithPublicKeyDerivation(publicKey.rawValue, TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue))
139 + }
140 +
141 + public init(publicKey: PublicKey, coin: CoinType, hrp: String) {
142 + let hrpString = TWStringCreateWithNSString(hrp)
143 + defer {
144 + TWStringDelete(hrpString)
145 + }
146 + rawValue = TWAnyAddressCreateBech32WithPublicKey(publicKey.rawValue, TWCoinType(rawValue: coin.rawValue), hrpString)
147 + }
148 +
149 + public init(publicKey: PublicKey, coin: CoinType, ss58Prefix: UInt32) {
150 + rawValue = TWAnyAddressCreateSS58WithPublicKey(publicKey.rawValue, TWCoinType(rawValue: coin.rawValue), ss58Prefix)
151 + }
152 +
153 + public init(publicKey: PublicKey, filecoinAddressType: FilecoinAddressType) {
154 + rawValue = TWAnyAddressCreateWithPublicKeyFilecoinAddressType(publicKey.rawValue, TWFilecoinAddressType(rawValue: filecoinAddressType.rawValue))
155 + }
156 +
157 + public init(publicKey: PublicKey, firoAddressType: FiroAddressType) {
158 + rawValue = TWAnyAddressCreateWithPublicKeyFiroAddressType(publicKey.rawValue, TWFiroAddressType(rawValue: firoAddressType.rawValue))
159 + }
160 +
161 + deinit {
162 + TWAnyAddressDelete(rawValue)
163 + }
164 +
165 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/AsnParser.swift +35 −0
@@ -0,0 +1,35 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents an ASN.1 DER parser.
13 +public struct AsnParser {
14 +
15 + /// Parses the given ECDSA signature from ASN.1 DER encoded bytes.
16 + ///
17 + /// - Parameter encoded: The ASN.1 DER encoded signature.
18 + /// - Returns: The ECDSA signature standard binary representation: RS, where R - 32 byte array, S - 32 byte array.
19 + public static func ecdsaSignatureFromDer(encoded: Data) -> Data? {
20 + let encodedData = TWDataCreateWithNSData(encoded)
21 + defer {
22 + TWDataDelete(encodedData)
23 + }
24 + guard let result = TWAsnParserEcdsaSignatureFromDer(encodedData) else {
25 + return nil
26 + }
27 + return TWDataNSData(result)
28 + }
29 +
30 +
31 + init() {
32 + }
33 +
34 +
35 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Barz.swift +125 −0
@@ -0,0 +1,125 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class Barz {
14 +
15 + /// Calculate a counterfactual address for the smart contract wallet
16 + ///
17 + /// - Parameter input: The serialized data of ContractAddressInput.
18 + /// - Returns: The address.
19 + public static func getCounterfactualAddress(input: Data) -> String? {
20 + let inputData = TWDataCreateWithNSData(input)
21 + defer {
22 + TWDataDelete(inputData)
23 + }
24 + guard let result = TWBarzGetCounterfactualAddress(inputData) else {
25 + return nil
26 + }
27 + return TWStringNSString(result)
28 + }
29 +
30 + /// Returns the init code parameter of ERC-4337 User Operation
31 + ///
32 + /// - Parameter factory: The address of the factory contract
33 + /// - Parameter public_key: Public key for the verification facet
34 + /// - Parameter verification_facet: The address of the verification facet
35 + /// - Parameter salt: The salt of the init code; Must be non-negative
36 + /// - Returns: The init code.
37 + public static func getInitCode(factory: String, publicKey: PublicKey, verificationFacet: String, salt: Int32) -> Data? {
38 + let factoryString = TWStringCreateWithNSString(factory)
39 + defer {
40 + TWStringDelete(factoryString)
41 + }
42 + let verificationFacetString = TWStringCreateWithNSString(verificationFacet)
43 + defer {
44 + TWStringDelete(verificationFacetString)
45 + }
46 + guard let result = TWBarzGetInitCode(factoryString, publicKey.rawValue, verificationFacetString, salt) else {
47 + return nil
48 + }
49 + return TWDataNSData(result)
50 + }
51 +
52 + /// Converts the original ASN-encoded signature from webauthn to the format accepted by Barz
53 + ///
54 + /// - Parameter signature: Original signature
55 + /// - Parameter challenge: The original challenge that was signed
56 + /// - Parameter authenticator_data: Returned from Webauthn API
57 + /// - Parameter client_data_json: Returned from Webauthn API
58 + /// - Returns: Bytes of the formatted signature
59 + public static func getFormattedSignature(signature: Data, challenge: Data, authenticatorData: Data, clientDataJson: String) -> Data? {
60 + let signatureData = TWDataCreateWithNSData(signature)
61 + defer {
62 + TWDataDelete(signatureData)
63 + }
64 + let challengeData = TWDataCreateWithNSData(challenge)
65 + defer {
66 + TWDataDelete(challengeData)
67 + }
68 + let authenticatorDataData = TWDataCreateWithNSData(authenticatorData)
69 + defer {
70 + TWDataDelete(authenticatorDataData)
71 + }
72 + let clientDataJsonString = TWStringCreateWithNSString(clientDataJson)
73 + defer {
74 + TWStringDelete(clientDataJsonString)
75 + }
76 + guard let result = TWBarzGetFormattedSignature(signatureData, challengeData, authenticatorDataData, clientDataJsonString) else {
77 + return nil
78 + }
79 + return TWDataNSData(result)
80 + }
81 +
82 + /// Returns the final hash to be signed by Barz for signing messages & typed data
83 + ///
84 + /// - Parameter msg_hash: Original msgHash
85 + /// - Parameter barzAddress: The address of Barz wallet signing the message
86 + /// - Parameter chainId: The chainId of the network the verification will happen; Must be non-negative
87 + /// - Returns: The final hash to be signed.
88 + public static func getPrefixedMsgHash(msgHash: Data, barzAddress: String, chainId: Int32) -> Data? {
89 + let msgHashData = TWDataCreateWithNSData(msgHash)
90 + defer {
91 + TWDataDelete(msgHashData)
92 + }
93 + let barzAddressString = TWStringCreateWithNSString(barzAddress)
94 + defer {
95 + TWStringDelete(barzAddressString)
96 + }
97 + guard let result = TWBarzGetPrefixedMsgHash(msgHashData, barzAddressString, chainId) else {
98 + return nil
99 + }
100 + return TWDataNSData(result)
101 + }
102 +
103 + /// Returns the encoded diamondCut function call for Barz contract upgrades
104 + ///
105 + /// - Parameter input: The serialized data of DiamondCutInput.
106 + /// - Returns: The diamond cut code.
107 + public static func getDiamondCutCode(input: Data) -> Data? {
108 + let inputData = TWDataCreateWithNSData(input)
109 + defer {
110 + TWDataDelete(inputData)
111 + }
112 + guard let result = TWBarzGetDiamondCutCode(inputData) else {
113 + return nil
114 + }
115 + return TWDataNSData(result)
116 + }
117 +
118 + let rawValue: OpaquePointer
119 +
120 + init(rawValue: OpaquePointer) {
121 + self.rawValue = rawValue
122 + }
123 +
124 +
125 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Base32.swift +102 −0
@@ -0,0 +1,102 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Base32 encode / decode functions
13 +public struct Base32 {
14 +
15 + /// Decode a Base32 input with the given alphabet
16 + ///
17 + /// - Parameter string: Encoded base32 input to be decoded
18 + /// - Parameter alphabet: Decode with the given alphabet, if nullptr ALPHABET_RFC4648 is used by default
19 + /// - Returns: The decoded data, can be null.
20 + /// - Note: ALPHABET_RFC4648 doesn't support padding in the default alphabet
21 + public static func decodeWithAlphabet(string: String, alphabet: String?) -> Data? {
22 + let stringString = TWStringCreateWithNSString(string)
23 + defer {
24 + TWStringDelete(stringString)
25 + }
26 + let alphabetString: UnsafeRawPointer?
27 + if let s = alphabet {
28 + alphabetString = TWStringCreateWithNSString(s)
29 + } else {
30 + alphabetString = nil
31 + }
32 + defer {
33 + if let s = alphabetString {
34 + TWStringDelete(s)
35 + }
36 + }
37 + guard let result = TWBase32DecodeWithAlphabet(stringString, alphabetString) else {
38 + return nil
39 + }
40 + return TWDataNSData(result)
41 + }
42 +
43 + /// Decode a Base32 input with the default alphabet (ALPHABET_RFC4648)
44 + ///
45 + /// - Parameter string: Encoded input to be decoded
46 + /// - Returns: The decoded data
47 + /// - Note: Call TWBase32DecodeWithAlphabet with nullptr.
48 + public static func decode(string: String) -> Data? {
49 + let stringString = TWStringCreateWithNSString(string)
50 + defer {
51 + TWStringDelete(stringString)
52 + }
53 + guard let result = TWBase32Decode(stringString) else {
54 + return nil
55 + }
56 + return TWDataNSData(result)
57 + }
58 +
59 + /// Encode an input to Base32 with the given alphabet
60 + ///
61 + /// - Parameter data: Data to be encoded (raw bytes)
62 + /// - Parameter alphabet: Encode with the given alphabet, if nullptr ALPHABET_RFC4648 is used by default
63 + /// - Returns: The encoded data
64 + /// - Note: ALPHABET_RFC4648 doesn't support padding in the default alphabet
65 + public static func encodeWithAlphabet(data: Data, alphabet: String?) -> String {
66 + let dataData = TWDataCreateWithNSData(data)
67 + defer {
68 + TWDataDelete(dataData)
69 + }
70 + let alphabetString: UnsafeRawPointer?
71 + if let s = alphabet {
72 + alphabetString = TWStringCreateWithNSString(s)
73 + } else {
74 + alphabetString = nil
75 + }
76 + defer {
77 + if let s = alphabetString {
78 + TWStringDelete(s)
79 + }
80 + }
81 + return TWStringNSString(TWBase32EncodeWithAlphabet(dataData, alphabetString))
82 + }
83 +
84 + /// Encode an input to Base32 with the default alphabet (ALPHABET_RFC4648)
85 + ///
86 + /// - Parameter data: Data to be encoded (raw bytes)
87 + /// - Returns: The encoded data
88 + /// - Note: Call TWBase32EncodeWithAlphabet with nullptr.
89 + public static func encode(data: Data) -> String {
90 + let dataData = TWDataCreateWithNSData(data)
91 + defer {
92 + TWDataDelete(dataData)
93 + }
94 + return TWStringNSString(TWBase32Encode(dataData))
95 + }
96 +
97 +
98 + init() {
99 + }
100 +
101 +
102 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Base58.swift +74 −0
@@ -0,0 +1,74 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Base58 encode / decode functions
13 +public struct Base58 {
14 +
15 + /// Encodes data as a Base58 string, including the checksum.
16 + ///
17 + /// - Parameter data: The data to encode.
18 + /// - Returns: the encoded Base58 string with checksum.
19 + public static func encode(data: Data) -> String {
20 + let dataData = TWDataCreateWithNSData(data)
21 + defer {
22 + TWDataDelete(dataData)
23 + }
24 + return TWStringNSString(TWBase58Encode(dataData))
25 + }
26 +
27 + /// Encodes data as a Base58 string, not including the checksum.
28 + ///
29 + /// - Parameter data: The data to encode.
30 + /// - Returns: then encoded Base58 string without checksum.
31 + public static func encodeNoCheck(data: Data) -> String {
32 + let dataData = TWDataCreateWithNSData(data)
33 + defer {
34 + TWDataDelete(dataData)
35 + }
36 + return TWStringNSString(TWBase58EncodeNoCheck(dataData))
37 + }
38 +
39 + /// Decodes a Base58 string, checking the checksum. Returns null if the string is not a valid Base58 string.
40 + ///
41 + /// - Parameter string: The Base58 string to decode.
42 + /// - Returns: the decoded data, null if the string is not a valid Base58 string with checksum.
43 + public static func decode(string: String) -> Data? {
44 + let stringString = TWStringCreateWithNSString(string)
45 + defer {
46 + TWStringDelete(stringString)
47 + }
48 + guard let result = TWBase58Decode(stringString) else {
49 + return nil
50 + }
51 + return TWDataNSData(result)
52 + }
53 +
54 + /// Decodes a Base58 string, w/o checking the checksum. Returns null if the string is not a valid Base58 string.
55 + ///
56 + /// - Parameter string: The Base58 string to decode.
57 + /// - Returns: the decoded data, null if the string is not a valid Base58 string without checksum.
58 + public static func decodeNoCheck(string: String) -> Data? {
59 + let stringString = TWStringCreateWithNSString(string)
60 + defer {
61 + TWStringDelete(stringString)
62 + }
63 + guard let result = TWBase58DecodeNoCheck(stringString) else {
64 + return nil
65 + }
66 + return TWDataNSData(result)
67 + }
68 +
69 +
70 + init() {
71 + }
72 +
73 +
74 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Base64.swift +74 −0
@@ -0,0 +1,74 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Base64 encode / decode functions
13 +public struct Base64 {
14 +
15 + /// Decode a Base64 input with the default alphabet (RFC4648 with '+', '/')
16 + ///
17 + /// - Parameter string: Encoded input to be decoded
18 + /// - Returns: The decoded data, empty if decoding failed.
19 + public static func decode(string: String) -> Data? {
20 + let stringString = TWStringCreateWithNSString(string)
21 + defer {
22 + TWStringDelete(stringString)
23 + }
24 + guard let result = TWBase64Decode(stringString) else {
25 + return nil
26 + }
27 + return TWDataNSData(result)
28 + }
29 +
30 + /// Decode a Base64 input with the alphabet safe for URL-s and filenames (RFC4648 with '-', '_')
31 + ///
32 + /// - Parameter string: Encoded base64 input to be decoded
33 + /// - Returns: The decoded data, empty if decoding failed.
34 + public static func decodeUrl(string: String) -> Data? {
35 + let stringString = TWStringCreateWithNSString(string)
36 + defer {
37 + TWStringDelete(stringString)
38 + }
39 + guard let result = TWBase64DecodeUrl(stringString) else {
40 + return nil
41 + }
42 + return TWDataNSData(result)
43 + }
44 +
45 + /// Encode an input to Base64 with the default alphabet (RFC4648 with '+', '/')
46 + ///
47 + /// - Parameter data: Data to be encoded (raw bytes)
48 + /// - Returns: The encoded data
49 + public static func encode(data: Data) -> String {
50 + let dataData = TWDataCreateWithNSData(data)
51 + defer {
52 + TWDataDelete(dataData)
53 + }
54 + return TWStringNSString(TWBase64Encode(dataData))
55 + }
56 +
57 + /// Encode an input to Base64 with the alphabet safe for URL-s and filenames (RFC4648 with '-', '_')
58 + ///
59 + /// - Parameter data: Data to be encoded (raw bytes)
60 + /// - Returns: The encoded data
61 + public static func encodeUrl(data: Data) -> String {
62 + let dataData = TWDataCreateWithNSData(data)
63 + defer {
64 + TWDataDelete(dataData)
65 + }
66 + return TWStringNSString(TWBase64EncodeUrl(dataData))
67 + }
68 +
69 +
70 + init() {
71 + }
72 +
73 +
74 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Bech32.swift +84 −0
@@ -0,0 +1,84 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Bech32 encode / decode functions
13 +public struct Bech32 {
14 +
15 + /// Encodes data as a Bech32 string.
16 + ///
17 + /// - Parameter hrp: The human-readable part.
18 + /// - Parameter data: The data part.
19 + /// - Returns: the encoded Bech32 string.
20 + public static func encode(hrp: String, data: Data) -> String {
21 + let hrpString = TWStringCreateWithNSString(hrp)
22 + defer {
23 + TWStringDelete(hrpString)
24 + }
25 + let dataData = TWDataCreateWithNSData(data)
26 + defer {
27 + TWDataDelete(dataData)
28 + }
29 + return TWStringNSString(TWBech32Encode(hrpString, dataData))
30 + }
31 +
32 + /// Decodes a Bech32 string. Returns null if the string is not a valid Bech32 string.
33 + ///
34 + /// - Parameter string: The Bech32 string to decode.
35 + /// - Returns: the decoded data, null if the string is not a valid Bech32 string. Note that the human-readable part is not returned.
36 + public static func decode(string: String) -> Data? {
37 + let stringString = TWStringCreateWithNSString(string)
38 + defer {
39 + TWStringDelete(stringString)
40 + }
41 + guard let result = TWBech32Decode(stringString) else {
42 + return nil
43 + }
44 + return TWDataNSData(result)
45 + }
46 +
47 + /// Encodes data as a Bech32m string.
48 + ///
49 + /// - Parameter hrp: The human-readable part.
50 + /// - Parameter data: The data part.
51 + /// - Returns: the encoded Bech32m string.
52 + public static func encodeM(hrp: String, data: Data) -> String {
53 + let hrpString = TWStringCreateWithNSString(hrp)
54 + defer {
55 + TWStringDelete(hrpString)
56 + }
57 + let dataData = TWDataCreateWithNSData(data)
58 + defer {
59 + TWDataDelete(dataData)
60 + }
61 + return TWStringNSString(TWBech32EncodeM(hrpString, dataData))
62 + }
63 +
64 + /// Decodes a Bech32m string. Returns null if the string is not a valid Bech32m string.
65 + ///
66 + /// - Parameter string: The Bech32m string to decode.
67 + /// - Returns: the decoded data, null if the string is not a valid Bech32m string. Note that the human-readable part is not returned.
68 + public static func decodeM(string: String) -> Data? {
69 + let stringString = TWStringCreateWithNSString(string)
70 + defer {
71 + TWStringDelete(stringString)
72 + }
73 + guard let result = TWBech32DecodeM(stringString) else {
74 + return nil
75 + }
76 + return TWDataNSData(result)
77 + }
78 +
79 +
80 + init() {
81 + }
82 +
83 +
84 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/BitcoinAddress.swift +108 −0
@@ -0,0 +1,108 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a legacy Bitcoin address in C++.
13 +public final class BitcoinAddress: Address {
14 +
15 + /// Compares two addresses for equality.
16 + ///
17 + /// - Parameter lhs: The first address to compare.
18 + /// - Parameter rhs: The second address to compare.
19 + /// - Returns: bool indicating the addresses are equal.
20 + public static func == (lhs: BitcoinAddress, rhs: BitcoinAddress) -> Bool {
21 + return TWBitcoinAddressEqual(lhs.rawValue, rhs.rawValue)
22 + }
23 +
24 + /// Determines if the data is a valid Bitcoin address.
25 + ///
26 + /// - Parameter data: data to validate.
27 + /// - Returns: bool indicating if the address data is valid.
28 + public static func isValid(data: Data) -> Bool {
29 + let dataData = TWDataCreateWithNSData(data)
30 + defer {
31 + TWDataDelete(dataData)
32 + }
33 + return TWBitcoinAddressIsValid(dataData)
34 + }
35 +
36 + /// Determines if the string is a valid Bitcoin address.
37 + ///
38 + /// - Parameter string: string to validate.
39 + /// - Returns: bool indicating if the address string is valid.
40 + public static func isValidString(string: String) -> Bool {
41 + let stringString = TWStringCreateWithNSString(string)
42 + defer {
43 + TWStringDelete(stringString)
44 + }
45 + return TWBitcoinAddressIsValidString(stringString)
46 + }
47 +
48 + /// Returns the address in Base58 string representation.
49 + ///
50 + /// - Parameter address: Address to get the string representation of.
51 + public var description: String {
52 + return TWStringNSString(TWBitcoinAddressDescription(rawValue))
53 + }
54 +
55 + /// Returns the address prefix.
56 + ///
57 + /// - Parameter address: Address to get the prefix of.
58 + public var prefix: UInt8 {
59 + return TWBitcoinAddressPrefix(rawValue)
60 + }
61 +
62 + /// Returns the key hash data.
63 + ///
64 + /// - Parameter address: Address to get the keyhash data of.
65 + public var keyhash: Data {
66 + return TWDataNSData(TWBitcoinAddressKeyhash(rawValue))
67 + }
68 +
69 + let rawValue: OpaquePointer
70 +
71 + init(rawValue: OpaquePointer) {
72 + self.rawValue = rawValue
73 + }
74 +
75 + public init?(string: String) {
76 + let stringString = TWStringCreateWithNSString(string)
77 + defer {
78 + TWStringDelete(stringString)
79 + }
80 + guard let rawValue = TWBitcoinAddressCreateWithString(stringString) else {
81 + return nil
82 + }
83 + self.rawValue = rawValue
84 + }
85 +
86 + public init?(data: Data) {
87 + let dataData = TWDataCreateWithNSData(data)
88 + defer {
89 + TWDataDelete(dataData)
90 + }
91 + guard let rawValue = TWBitcoinAddressCreateWithData(dataData) else {
92 + return nil
93 + }
94 + self.rawValue = rawValue
95 + }
96 +
97 + public init?(publicKey: PublicKey, prefix: UInt8) {
98 + guard let rawValue = TWBitcoinAddressCreateWithPublicKey(publicKey.rawValue, prefix) else {
99 + return nil
100 + }
101 + self.rawValue = rawValue
102 + }
103 +
104 + deinit {
105 + TWBitcoinAddressDelete(rawValue)
106 + }
107 +
108 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/BitcoinMessageSigner.swift +65 −0
@@ -0,0 +1,65 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Bitcoin message signing and verification.
13 +///
14 +/// Bitcoin Core and some other wallets support a message signing & verification format, to create a proof (a signature)
15 +/// that someone has access to the private keys of a specific address.
16 +/// This feature currently works on old legacy addresses only.
17 +public struct BitcoinMessageSigner {
18 +
19 + /// Sign a message.
20 + ///
21 + /// - Parameter privateKey:: the private key used for signing
22 + /// - Parameter address:: the address that matches the privateKey, must be a legacy address (P2PKH)
23 + /// - Parameter message:: A custom message which is input to the signing.
24 + /// - Note: Address is derived assuming compressed public key format.
25 + /// - Returns:s the signature, Base64-encoded. On invalid input empty string is returned. Returned object needs to be deleteed after use.
26 + public static func signMessage(privateKey: PrivateKey, address: String, message: String) -> String {
27 + let addressString = TWStringCreateWithNSString(address)
28 + defer {
29 + TWStringDelete(addressString)
30 + }
31 + let messageString = TWStringCreateWithNSString(message)
32 + defer {
33 + TWStringDelete(messageString)
34 + }
35 + return TWStringNSString(TWBitcoinMessageSignerSignMessage(privateKey.rawValue, addressString, messageString))
36 + }
37 +
38 + /// Verify signature for a message.
39 + ///
40 + /// - Parameter address:: address to use, only legacy is supported
41 + /// - Parameter message:: the message signed (without prefix)
42 + /// - Parameter signature:: in Base64-encoded form.
43 + /// - Returns:s false on any invalid input (does not throw).
44 + public static func verifyMessage(address: String, message: String, signature: String) -> Bool {
45 + let addressString = TWStringCreateWithNSString(address)
46 + defer {
47 + TWStringDelete(addressString)
48 + }
49 + let messageString = TWStringCreateWithNSString(message)
50 + defer {
51 + TWStringDelete(messageString)
52 + }
53 + let signatureString = TWStringCreateWithNSString(signature)
54 + defer {
55 + TWStringDelete(signatureString)
56 + }
57 + return TWBitcoinMessageSignerVerifyMessage(addressString, messageString, signatureString)
58 + }
59 +
60 +
61 + init() {
62 + }
63 +
64 +
65 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/BitcoinScript.swift +269 −0
@@ -0,0 +1,269 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Bitcoin script manipulating functions
13 +public final class BitcoinScript {
14 +
15 + /// Determines whether 2 scripts have the same content
16 + ///
17 + /// - Parameter lhs: Non-null pointer to the first script
18 + /// - Parameter rhs: Non-null pointer to the second script
19 + /// - Returns: true if both script have the same content
20 + public static func == (lhs: BitcoinScript, rhs: BitcoinScript) -> Bool {
21 + return TWBitcoinScriptEqual(lhs.rawValue, rhs.rawValue)
22 + }
23 +
24 + /// Builds a standard 'pay to public key' script.
25 + ///
26 + /// - Parameter pubkey: Non-null pointer to a pubkey
27 + /// - Note: Must be deleted with \TWBitcoinScriptDelete
28 + /// - Returns: A pointer to the built script
29 + public static func buildPayToPublicKey(pubkey: Data) -> BitcoinScript {
30 + let pubkeyData = TWDataCreateWithNSData(pubkey)
31 + defer {
32 + TWDataDelete(pubkeyData)
33 + }
34 + return BitcoinScript(rawValue: TWBitcoinScriptBuildPayToPublicKey(pubkeyData))
35 + }
36 +
37 + /// Builds a standard 'pay to public key hash' script.
38 + ///
39 + /// - Parameter hash: Non-null pointer to a PublicKey hash
40 + /// - Note: Must be deleted with \TWBitcoinScriptDelete
41 + /// - Returns: A pointer to the built script
42 + public static func buildPayToPublicKeyHash(hash: Data) -> BitcoinScript {
43 + let hashData = TWDataCreateWithNSData(hash)
44 + defer {
45 + TWDataDelete(hashData)
46 + }
47 + return BitcoinScript(rawValue: TWBitcoinScriptBuildPayToPublicKeyHash(hashData))
48 + }
49 +
50 + /// Builds a standard 'pay to script hash' script.
51 + ///
52 + /// - Parameter scriptHash: Non-null pointer to a script hash
53 + /// - Note: Must be deleted with \TWBitcoinScriptDelete
54 + /// - Returns: A pointer to the built script
55 + public static func buildPayToScriptHash(scriptHash: Data) -> BitcoinScript {
56 + let scriptHashData = TWDataCreateWithNSData(scriptHash)
57 + defer {
58 + TWDataDelete(scriptHashData)
59 + }
60 + return BitcoinScript(rawValue: TWBitcoinScriptBuildPayToScriptHash(scriptHashData))
61 + }
62 +
63 + /// Builds a pay-to-witness-public-key-hash (P2WPKH) script..
64 + ///
65 + /// - Parameter hash: Non-null pointer to a witness public key hash
66 + /// - Note: Must be deleted with \TWBitcoinScriptDelete
67 + /// - Returns: A pointer to the built script
68 + public static func buildPayToWitnessPubkeyHash(hash: Data) -> BitcoinScript {
69 + let hashData = TWDataCreateWithNSData(hash)
70 + defer {
71 + TWDataDelete(hashData)
72 + }
73 + return BitcoinScript(rawValue: TWBitcoinScriptBuildPayToWitnessPubkeyHash(hashData))
74 + }
75 +
76 + /// Builds a pay-to-witness-script-hash (P2WSH) script.
77 + ///
78 + /// - Parameter scriptHash: Non-null pointer to a script hash
79 + /// - Note: Must be deleted with \TWBitcoinScriptDelete
80 + /// - Returns: A pointer to the built script
81 + public static func buildPayToWitnessScriptHash(scriptHash: Data) -> BitcoinScript {
82 + let scriptHashData = TWDataCreateWithNSData(scriptHash)
83 + defer {
84 + TWDataDelete(scriptHashData)
85 + }
86 + return BitcoinScript(rawValue: TWBitcoinScriptBuildPayToWitnessScriptHash(scriptHashData))
87 + }
88 +
89 + /// Builds a appropriate lock script for the given address..
90 + ///
91 + /// - Parameter address: Non-null pointer to an address
92 + /// - Parameter coin: coin type
93 + /// - Note: Must be deleted with \TWBitcoinScriptDelete
94 + /// - Returns: A pointer to the built script
95 + public static func lockScriptForAddress(address: String, coin: CoinType) -> BitcoinScript {
96 + let addressString = TWStringCreateWithNSString(address)
97 + defer {
98 + TWStringDelete(addressString)
99 + }
100 + return BitcoinScript(rawValue: TWBitcoinScriptLockScriptForAddress(addressString, TWCoinType(rawValue: coin.rawValue)))
101 + }
102 +
103 + /// Builds a appropriate lock script for the given address with replay.
104 + public static func lockScriptForAddressReplay(address: String, coin: CoinType, blockHash: Data, blockHeight: Int64) -> BitcoinScript {
105 + let addressString = TWStringCreateWithNSString(address)
106 + defer {
107 + TWStringDelete(addressString)
108 + }
109 + let blockHashData = TWDataCreateWithNSData(blockHash)
110 + defer {
111 + TWDataDelete(blockHashData)
112 + }
113 + return BitcoinScript(rawValue: TWBitcoinScriptLockScriptForAddressReplay(addressString, TWCoinType(rawValue: coin.rawValue), blockHashData, blockHeight))
114 + }
115 +
116 + /// Return the default HashType for the given coin, such as TWBitcoinSigHashTypeAll.
117 + ///
118 + /// - Parameter coinType: coin type
119 + /// - Returns: default HashType for the given coin
120 + public static func hashTypeForCoin(coinType: CoinType) -> UInt32 {
121 + return TWBitcoinScriptHashTypeForCoin(TWCoinType(rawValue: coinType.rawValue))
122 + }
123 +
124 + /// Get size of a script
125 + ///
126 + /// - Parameter script: Non-null pointer to a script
127 + /// - Returns: size of the script
128 + public var size: Int {
129 + return TWBitcoinScriptSize(rawValue)
130 + }
131 +
132 + /// Get data of a script
133 + ///
134 + /// - Parameter script: Non-null pointer to a script
135 + /// - Returns: data of the given script
136 + public var data: Data {
137 + return TWDataNSData(TWBitcoinScriptData(rawValue))
138 + }
139 +
140 + /// Return script hash of a script
141 + ///
142 + /// - Parameter script: Non-null pointer to a script
143 + /// - Returns: script hash of the given script
144 + public var scriptHash: Data {
145 + return TWDataNSData(TWBitcoinScriptScriptHash(rawValue))
146 + }
147 +
148 + /// Determines whether this is a pay-to-script-hash (P2SH) script.
149 + ///
150 + /// - Parameter script: Non-null pointer to a script
151 + /// - Returns: true if this is a pay-to-script-hash (P2SH) script, false otherwise
152 + public var isPayToScriptHash: Bool {
153 + return TWBitcoinScriptIsPayToScriptHash(rawValue)
154 + }
155 +
156 + /// Determines whether this is a pay-to-witness-script-hash (P2WSH) script.
157 + ///
158 + /// - Parameter script: Non-null pointer to a script
159 + /// - Returns: true if this is a pay-to-witness-script-hash (P2WSH) script, false otherwise
160 + public var isPayToWitnessScriptHash: Bool {
161 + return TWBitcoinScriptIsPayToWitnessScriptHash(rawValue)
162 + }
163 +
164 + /// Determines whether this is a pay-to-witness-public-key-hash (P2WPKH) script.
165 + ///
166 + /// - Parameter script: Non-null pointer to a script
167 + /// - Returns: true if this is a pay-to-witness-public-key-hash (P2WPKH) script, false otherwise
168 + public var isPayToWitnessPublicKeyHash: Bool {
169 + return TWBitcoinScriptIsPayToWitnessPublicKeyHash(rawValue)
170 + }
171 +
172 + /// Determines whether this is a witness program script.
173 + ///
174 + /// - Parameter script: Non-null pointer to a script
175 + /// - Returns: true if this is a witness program script, false otherwise
176 + public var isWitnessProgram: Bool {
177 + return TWBitcoinScriptIsWitnessProgram(rawValue)
178 + }
179 +
180 + let rawValue: OpaquePointer
181 +
182 + init(rawValue: OpaquePointer) {
183 + self.rawValue = rawValue
184 + }
185 +
186 + public init() {
187 + rawValue = TWBitcoinScriptCreate()
188 + }
189 +
190 + public init(data: Data) {
191 + let dataData = TWDataCreateWithNSData(data)
192 + defer {
193 + TWDataDelete(dataData)
194 + }
195 + rawValue = TWBitcoinScriptCreateWithData(dataData)
196 + }
197 +
198 + public init(script: BitcoinScript) {
199 + rawValue = TWBitcoinScriptCreateCopy(script.rawValue)
200 + }
201 +
202 + deinit {
203 + TWBitcoinScriptDelete(rawValue)
204 + }
205 +
206 + /// Matches the script to a pay-to-public-key (P2PK) script.
207 + ///
208 + /// - Parameter script: Non-null pointer to a script
209 + /// - Returns: The public key.
210 + public func matchPayToPubkey() -> Data? {
211 + guard let result = TWBitcoinScriptMatchPayToPubkey(rawValue) else {
212 + return nil
213 + }
214 + return TWDataNSData(result)
215 + }
216 +
217 + /// Matches the script to a pay-to-public-key-hash (P2PKH).
218 + ///
219 + /// - Parameter script: Non-null pointer to a script
220 + /// - Returns: the key hash.
221 + public func matchPayToPubkeyHash() -> Data? {
222 + guard let result = TWBitcoinScriptMatchPayToPubkeyHash(rawValue) else {
223 + return nil
224 + }
225 + return TWDataNSData(result)
226 + }
227 +
228 + /// Matches the script to a pay-to-script-hash (P2SH).
229 + ///
230 + /// - Parameter script: Non-null pointer to a script
231 + /// - Returns: the script hash.
232 + public func matchPayToScriptHash() -> Data? {
233 + guard let result = TWBitcoinScriptMatchPayToScriptHash(rawValue) else {
234 + return nil
235 + }
236 + return TWDataNSData(result)
237 + }
238 +
239 + /// Matches the script to a pay-to-witness-public-key-hash (P2WPKH).
240 + ///
241 + /// - Parameter script: Non-null pointer to a script
242 + /// - Returns: the key hash.
243 + public func matchPayToWitnessPublicKeyHash() -> Data? {
244 + guard let result = TWBitcoinScriptMatchPayToWitnessPublicKeyHash(rawValue) else {
245 + return nil
246 + }
247 + return TWDataNSData(result)
248 + }
249 +
250 + /// Matches the script to a pay-to-witness-script-hash (P2WSH).
251 + ///
252 + /// - Parameter script: Non-null pointer to a script
253 + /// - Returns: the script hash, a SHA256 of the witness script..
254 + public func matchPayToWitnessScriptHash() -> Data? {
255 + guard let result = TWBitcoinScriptMatchPayToWitnessScriptHash(rawValue) else {
256 + return nil
257 + }
258 + return TWDataNSData(result)
259 + }
260 +
261 + /// Encodes the script.
262 + ///
263 + /// - Parameter script: Non-null pointer to a script
264 + /// - Returns: The encoded script
265 + public func encode() -> Data {
266 + return TWDataNSData(TWBitcoinScriptEncode(rawValue))
267 + }
268 +
269 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/BitcoinSigHashType+Extension.swift +29 −0
@@ -0,0 +1,29 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +extension BitcoinSigHashType {
11 +
12 + /// Determines if the given sig hash is single
13 + ///
14 + /// - Parameter type: sig hash type
15 + /// - Returns: true if the sigh hash type is single, false otherwise
16 + public func isSingle() -> Bool {
17 + return TWBitcoinSigHashTypeIsSingle(TWBitcoinSigHashType(rawValue: rawValue))
18 + }
19 +
20 +
21 + /// Determines if the given sig hash is none
22 + ///
23 + /// - Parameter type: sig hash type
24 + /// - Returns: true if the sigh hash type is none, false otherwise
25 + public func isNone() -> Bool {
26 + return TWBitcoinSigHashTypeIsNone(TWBitcoinSigHashType(rawValue: rawValue))
27 + }
28 +
29 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Biz.swift +107 −0
@@ -0,0 +1,107 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class Biz {
14 +
15 + /// Returns the encoded hash of the user operation
16 + ///
17 + /// - Parameter chain_id: The chain ID of the user.
18 + /// - Parameter code_address: The address of the smart contract wallet.
19 + /// - Parameter code_name: The name of the smart contract wallet.
20 + /// - Parameter code_version: The version of the smart contract wallet.
21 + /// - Parameter type_hash: The type hash of the smart contract wallet.
22 + /// - Parameter domain_separator_hash: The domain separator hash of the smart contract wallet.
23 + /// - Parameter sender: The sender of the smart contract wallet.
24 + /// - Parameter user_op_hash: The user operation hash of the smart contract wallet.
25 + /// - Returns: The encoded hash.
26 + public static func getEncodedHash(chainId: Data, codeAddress: String, codeName: String, codeVersion: String, typeHash: String, domainSeparatorHash: String, sender: String, userOpHash: String) -> Data? {
27 + let chainIdData = TWDataCreateWithNSData(chainId)
28 + defer {
29 + TWDataDelete(chainIdData)
30 + }
31 + let codeAddressString = TWStringCreateWithNSString(codeAddress)
32 + defer {
33 + TWStringDelete(codeAddressString)
34 + }
35 + let codeNameString = TWStringCreateWithNSString(codeName)
36 + defer {
37 + TWStringDelete(codeNameString)
38 + }
39 + let codeVersionString = TWStringCreateWithNSString(codeVersion)
40 + defer {
41 + TWStringDelete(codeVersionString)
42 + }
43 + let typeHashString = TWStringCreateWithNSString(typeHash)
44 + defer {
45 + TWStringDelete(typeHashString)
46 + }
47 + let domainSeparatorHashString = TWStringCreateWithNSString(domainSeparatorHash)
48 + defer {
49 + TWStringDelete(domainSeparatorHashString)
50 + }
51 + let senderString = TWStringCreateWithNSString(sender)
52 + defer {
53 + TWStringDelete(senderString)
54 + }
55 + let userOpHashString = TWStringCreateWithNSString(userOpHash)
56 + defer {
57 + TWStringDelete(userOpHashString)
58 + }
59 + guard let result = TWBizGetEncodedHash(chainIdData, codeAddressString, codeNameString, codeVersionString, typeHashString, domainSeparatorHashString, senderString, userOpHashString) else {
60 + return nil
61 + }
62 + return TWDataNSData(result)
63 + }
64 +
65 + /// Signs a message using the private key
66 + ///
67 + /// - Parameter hash: The hash of the user.
68 + /// - Parameter private_key: The private key of the user.
69 + /// - Returns: The signed hash.
70 + public static func getSignedHash(hash: String, privateKey: String) -> Data? {
71 + let hashString = TWStringCreateWithNSString(hash)
72 + defer {
73 + TWStringDelete(hashString)
74 + }
75 + let privateKeyString = TWStringCreateWithNSString(privateKey)
76 + defer {
77 + TWStringDelete(privateKeyString)
78 + }
79 + guard let result = TWBizGetSignedHash(hashString, privateKeyString) else {
80 + return nil
81 + }
82 + return TWDataNSData(result)
83 + }
84 +
85 + /// Signs and encodes `Biz.executeWithPasskeySession` function call to execute a batch of transactions.
86 + ///
87 + /// - Parameter input: The serialized data of `Biz.ExecuteWithSignatureInput` protobuf message.
88 + /// - Returns: ABI-encoded function call.
89 + public static func signExecuteWithSignatureCall(input: Data) -> Data? {
90 + let inputData = TWDataCreateWithNSData(input)
91 + defer {
92 + TWDataDelete(inputData)
93 + }
94 + guard let result = TWBizSignExecuteWithSignatureCall(inputData) else {
95 + return nil
96 + }
97 + return TWDataNSData(result)
98 + }
99 +
100 + let rawValue: OpaquePointer
101 +
102 + init(rawValue: OpaquePointer) {
103 + self.rawValue = rawValue
104 + }
105 +
106 +
107 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/BizPasskeySession.swift +94 −0
@@ -0,0 +1,94 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class BizPasskeySession {
14 +
15 + /// Encodes `BizPasskeySession.registerSession` function call to register a session passkey public key.
16 + ///
17 + /// - Parameter session_passkey_public_key: The nist256p1 (aka secp256p1) public key of the session passkey.
18 + /// - Parameter valid_until_timestamp: The timestamp until which the session is valid. Big endian uint64.
19 + /// - Returns: ABI-encoded function call.
20 + public static func encodeRegisterSessionCall(sessionPasskeyPublicKey: PublicKey, validUntilTimestamp: Data) -> Data? {
21 + let validUntilTimestampData = TWDataCreateWithNSData(validUntilTimestamp)
22 + defer {
23 + TWDataDelete(validUntilTimestampData)
24 + }
25 + guard let result = TWBizPasskeySessionEncodeRegisterSessionCall(sessionPasskeyPublicKey.rawValue, validUntilTimestampData) else {
26 + return nil
27 + }
28 + return TWDataNSData(result)
29 + }
30 +
31 + /// Encodes `BizPasskeySession.removeSession` function call to deregister a session passkey public key.
32 + ///
33 + /// - Parameter session_passkey_public_key: The nist256p1 (aka secp256p1) public key of the session passkey.
34 + /// - Returns: ABI-encoded function call.
35 + public static func encodeRemoveSessionCall(sessionPasskeyPublicKey: PublicKey) -> Data? {
36 + guard let result = TWBizPasskeySessionEncodeRemoveSessionCall(sessionPasskeyPublicKey.rawValue) else {
37 + return nil
38 + }
39 + return TWDataNSData(result)
40 + }
41 +
42 + /// Encodes `BizPasskeySession` nonce.
43 + ///
44 + /// - Parameter nonce: The nonce of the Biz Passkey Session account.
45 + /// - Returns: uint256 represented as [passkey_nonce_key_192, nonce_64].
46 + public static func encodePasskeySessionNonce(nonce: Data) -> Data? {
47 + let nonceData = TWDataCreateWithNSData(nonce)
48 + defer {
49 + TWDataDelete(nonceData)
50 + }
51 + guard let result = TWBizPasskeySessionEncodePasskeySessionNonce(nonceData) else {
52 + return nil
53 + }
54 + return TWDataNSData(result)
55 + }
56 +
57 + /// Signs and encodes `BizPasskeySession.executeWithPasskeySession` function call to execute a batch of transactions.
58 + ///
59 + /// - Parameter input: The serialized data of `BizPasskeySession.ExecuteWithSignatureInput` protobuf message.
60 + /// - Returns: ABI-encoded function call.
61 + public static func signExecuteWithSignatureCall(input: Data) -> Data? {
62 + let inputData = TWDataCreateWithNSData(input)
63 + defer {
64 + TWDataDelete(inputData)
65 + }
66 + guard let result = TWBizPasskeySessionSignExecuteWithSignatureCall(inputData) else {
67 + return nil
68 + }
69 + return TWDataNSData(result)
70 + }
71 +
72 + /// Encodes `BizPasskeySession.executeWithPasskeySession` function call to execute a batch of transactions.
73 + ///
74 + /// - Parameter input: The serialized data of `BizPasskeySession.ExecuteWithPasskeySessionInput` protobuf message.
75 + /// - Returns: ABI-encoded function call.
76 + public static func encodeExecuteWithPasskeySessionCall(input: Data) -> Data? {
77 + let inputData = TWDataCreateWithNSData(input)
78 + defer {
79 + TWDataDelete(inputData)
80 + }
81 + guard let result = TWBizPasskeySessionEncodeExecuteWithPasskeySessionCall(inputData) else {
82 + return nil
83 + }
84 + return TWDataNSData(result)
85 + }
86 +
87 + let rawValue: OpaquePointer
88 +
89 + init(rawValue: OpaquePointer) {
90 + self.rawValue = rawValue
91 + }
92 +
93 +
94 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Cardano.swift +79 −0
@@ -0,0 +1,79 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Cardano helper functions
13 +public struct Cardano {
14 +
15 + /// Calculates the minimum ADA amount needed for a UTXO.
16 + ///
17 + /// \deprecated consider using `TWCardanoOutputMinAdaAmount` instead.
18 + /// - SeeAlso: reference https://docs.cardano.org/native-tokens/minimum-ada-value-requirement
19 + /// - Parameter tokenBundle: serialized data of TW.Cardano.Proto.TokenBundle.
20 + /// - Returns: the minimum ADA amount.
21 + public static func minAdaAmount(tokenBundle: Data) -> UInt64 {
22 + let tokenBundleData = TWDataCreateWithNSData(tokenBundle)
23 + defer {
24 + TWDataDelete(tokenBundleData)
25 + }
26 + return TWCardanoMinAdaAmount(tokenBundleData)
27 + }
28 +
29 + /// Calculates the minimum ADA amount needed for an output.
30 + ///
31 + /// - SeeAlso: reference https://docs.cardano.org/native-tokens/minimum-ada-value-requirement
32 + /// - Parameter toAddress: valid destination address, as string.
33 + /// - Parameter tokenBundle: serialized data of TW.Cardano.Proto.TokenBundle.
34 + /// - Parameter coinsPerUtxoByte: cost per one byte of a serialized UTXO (Base-10 decimal string).
35 + /// - Returns: the minimum ADA amount (Base-10 decimal string).
36 + public static func outputMinAdaAmount(toAddress: String, tokenBundle: Data, coinsPerUtxoByte: String) -> String? {
37 + let toAddressString = TWStringCreateWithNSString(toAddress)
38 + defer {
39 + TWStringDelete(toAddressString)
40 + }
41 + let tokenBundleData = TWDataCreateWithNSData(tokenBundle)
42 + defer {
43 + TWDataDelete(tokenBundleData)
44 + }
45 + let coinsPerUtxoByteString = TWStringCreateWithNSString(coinsPerUtxoByte)
46 + defer {
47 + TWStringDelete(coinsPerUtxoByteString)
48 + }
49 + guard let result = TWCardanoOutputMinAdaAmount(toAddressString, tokenBundleData, coinsPerUtxoByteString) else {
50 + return nil
51 + }
52 + return TWStringNSString(result)
53 + }
54 +
55 + /// Return the staking address associated to (contained in) this address. Must be a Base address.
56 + /// Empty string is returned on error. Result must be freed.
57 + /// - Parameter baseAddress: A valid base address, as string.
58 + /// - Returns: the associated staking (reward) address, as string, or empty string on error.
59 + public static func getStakingAddress(baseAddress: String) -> String {
60 + let baseAddressString = TWStringCreateWithNSString(baseAddress)
61 + defer {
62 + TWStringDelete(baseAddressString)
63 + }
64 + return TWStringNSString(TWCardanoGetStakingAddress(baseAddressString))
65 + }
66 +
67 + /// Return the legacy(byron) address.
68 + /// - Parameter publicKey: A valid public key with TWPublicKeyTypeED25519Cardano type.
69 + /// - Returns: the legacy(byron) address, as string, or empty string on error.
70 + public static func getByronAddress(publicKey: PublicKey) -> String {
71 + return TWStringNSString(TWCardanoGetByronAddress(publicKey.rawValue))
72 + }
73 +
74 +
75 + init() {
76 + }
77 +
78 +
79 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/CoinType+Extension.swift +162 −0
@@ -0,0 +1,162 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +extension CoinType {
11 + /// Returns the blockchain for a coin type.
12 + ///
13 + /// - Parameter coin: A coin type
14 + /// - Returns: blockchain associated to the given coin type
15 + public var blockchain: Blockchain {
16 + return Blockchain(rawValue: TWCoinTypeBlockchain(TWCoinType(rawValue: rawValue)).rawValue)!
17 + }
18 + /// Returns the purpose for a coin type.
19 + ///
20 + /// - Parameter coin: A coin type
21 + /// - Returns: purpose associated to the given coin type
22 + public var purpose: Purpose {
23 + return Purpose(rawValue: TWCoinTypePurpose(TWCoinType(rawValue: rawValue)).rawValue)!
24 + }
25 + /// Returns the curve that should be used for a coin type.
26 + ///
27 + /// - Parameter coin: A coin type
28 + /// - Returns: curve that should be used for the given coin type
29 + public var curve: Curve {
30 + return Curve(rawValue: TWCoinTypeCurve(TWCoinType(rawValue: rawValue)).rawValue)!
31 + }
32 + /// Returns the xpub HD version that should be used for a coin type.
33 + ///
34 + /// - Parameter coin: A coin type
35 + /// - Returns: xpub HD version that should be used for the given coin type
36 + public var xpubVersion: HDVersion {
37 + return HDVersion(rawValue: TWCoinTypeXpubVersion(TWCoinType(rawValue: rawValue)).rawValue)!
38 + }
39 + /// Returns the xprv HD version that should be used for a coin type.
40 + ///
41 + /// - Parameter coin: A coin type
42 + /// - Returns: the xprv HD version that should be used for the given coin type.
43 + public var xprvVersion: HDVersion {
44 + return HDVersion(rawValue: TWCoinTypeXprvVersion(TWCoinType(rawValue: rawValue)).rawValue)!
45 + }
46 + /// HRP for this coin type
47 + ///
48 + /// - Parameter coin: A coin type
49 + /// - Returns: HRP of the given coin type.
50 + public var hrp: HRP {
51 + return HRP(rawValue: TWCoinTypeHRP(TWCoinType(rawValue: rawValue)).rawValue)!
52 + }
53 + /// P2PKH prefix for this coin type
54 + ///
55 + /// - Parameter coin: A coin type
56 + /// - Returns: P2PKH prefix for the given coin type
57 + public var p2pkhPrefix: UInt8 {
58 + return TWCoinTypeP2pkhPrefix(TWCoinType(rawValue: rawValue))
59 + }
60 + /// P2SH prefix for this coin type
61 + ///
62 + /// - Parameter coin: A coin type
63 + /// - Returns: P2SH prefix for the given coin type
64 + public var p2shPrefix: UInt8 {
65 + return TWCoinTypeP2shPrefix(TWCoinType(rawValue: rawValue))
66 + }
67 + /// Static prefix for this coin type
68 + ///
69 + /// - Parameter coin: A coin type
70 + /// - Returns: Static prefix for the given coin type
71 + public var staticPrefix: UInt8 {
72 + return TWCoinTypeStaticPrefix(TWCoinType(rawValue: rawValue))
73 + }
74 + /// ChainID for this coin type.
75 + ///
76 + /// - Parameter coin: A coin type
77 + /// - Returns: ChainID for the given coin type.
78 + /// - Note: Caller must free returned object.
79 + public var chainId: String {
80 + return TWStringNSString(TWCoinTypeChainId(TWCoinType(rawValue: rawValue)))
81 + }
82 + /// SLIP-0044 id for this coin type
83 + ///
84 + /// - Parameter coin: A coin type
85 + /// - Returns: SLIP-0044 id for the given coin type
86 + public var slip44Id: UInt32 {
87 + return TWCoinTypeSlip44Id(TWCoinType(rawValue: rawValue))
88 + }
89 + /// SS58Prefix for this coin type
90 + ///
91 + /// - Parameter coin: A coin type
92 + /// - Returns: SS58Prefix for the given coin type
93 + public var ss58Prefix: UInt32 {
94 + return TWCoinTypeSS58Prefix(TWCoinType(rawValue: rawValue))
95 + }
96 + /// public key type for this coin type
97 + ///
98 + /// - Parameter coin: A coin type
99 + /// - Returns: public key type for the given coin type
100 + public var publicKeyType: PublicKeyType {
101 + return PublicKeyType(rawValue: TWCoinTypePublicKeyType(TWCoinType(rawValue: rawValue)).rawValue)!
102 + }
103 +
104 + /// Validates an address string.
105 + ///
106 + /// - Parameter coin: A coin type
107 + /// - Parameter address: A public address
108 + /// - Returns: true if the address is a valid public address of the given coin, false otherwise.
109 + public func validate(address: String) -> Bool {
110 + let addressString = TWStringCreateWithNSString(address)
111 + defer {
112 + TWStringDelete(addressString)
113 + }
114 + return TWCoinTypeValidate(TWCoinType(rawValue: rawValue), addressString)
115 + }
116 +
117 +
118 + /// Returns the default derivation path for a particular coin.
119 + ///
120 + /// - Parameter coin: A coin type
121 + /// - Returns: the default derivation path for the given coin type.
122 + public func derivationPath() -> String {
123 + return TWStringNSString(TWCoinTypeDerivationPath(TWCoinType(rawValue: rawValue)))
124 + }
125 +
126 +
127 + /// Returns the derivation path for a particular coin with the explicit given derivation.
128 + ///
129 + /// - Parameter coin: A coin type
130 + /// - Parameter derivation: A derivation type
131 + /// - Returns: the derivation path for the given coin with the explicit given derivation
132 + public func derivationPathWithDerivation(derivation: Derivation) -> String {
133 + return TWStringNSString(TWCoinTypeDerivationPathWithDerivation(TWCoinType(rawValue: rawValue), TWDerivation(rawValue: derivation.rawValue)))
134 + }
135 +
136 +
137 + /// Derives the address for a particular coin from the private key.
138 + ///
139 + /// - Parameter coin: A coin type
140 + /// - Parameter privateKey: A valid private key
141 + /// - Returns: Derived address for the given coin from the private key.
142 + public func deriveAddress(privateKey: PrivateKey) -> String {
143 + return TWStringNSString(TWCoinTypeDeriveAddress(TWCoinType(rawValue: rawValue), privateKey.rawValue))
144 + }
145 +
146 +
147 + /// Derives the address for a particular coin from the public key.
148 + ///
149 + /// - Parameter coin: A coin type
150 + /// - Parameter publicKey: A valid public key
151 + /// - Returns: Derived address for the given coin from the public key.
152 + public func deriveAddressFromPublicKey(publicKey: PublicKey) -> String {
153 + return TWStringNSString(TWCoinTypeDeriveAddressFromPublicKey(TWCoinType(rawValue: rawValue), publicKey.rawValue))
154 + }
155 +
156 +
157 + /// Derives the address for a particular coin from the public key with the derivation.
158 + public func deriveAddressFromPublicKeyAndDerivation(publicKey: PublicKey, derivation: Derivation) -> String {
159 + return TWStringNSString(TWCoinTypeDeriveAddressFromPublicKeyAndDerivation(TWCoinType(rawValue: rawValue), publicKey.rawValue, TWDerivation(rawValue: derivation.rawValue)))
160 + }
161 +
162 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/CoinTypeConfiguration.swift +87 −0
@@ -0,0 +1,87 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// CoinTypeConfiguration functions
13 +public struct CoinTypeConfiguration {
14 +
15 + /// Returns stock symbol of coin
16 + ///
17 + /// - Parameter type: A coin type
18 + /// - Returns: A non-null TWString stock symbol of coin
19 + /// - Note: Caller must free returned object
20 + public static func getSymbol(type: CoinType) -> String {
21 + return TWStringNSString(TWCoinTypeConfigurationGetSymbol(TWCoinType(rawValue: type.rawValue)))
22 + }
23 +
24 + /// Returns max count decimal places for minimal coin unit
25 + ///
26 + /// - Parameter type: A coin type
27 + /// - Returns: Returns max count decimal places for minimal coin unit
28 + public static func getDecimals(type: CoinType) -> Int32 {
29 + return TWCoinTypeConfigurationGetDecimals(TWCoinType(rawValue: type.rawValue))
30 + }
31 +
32 + /// Returns transaction url in blockchain explorer
33 + ///
34 + /// - Parameter type: A coin type
35 + /// - Parameter transactionID: A transaction identifier
36 + /// - Returns: Returns a non-null TWString transaction url in blockchain explorer
37 + public static func getTransactionURL(type: CoinType, transactionID: String) -> String {
38 + let transactionIDString = TWStringCreateWithNSString(transactionID)
39 + defer {
40 + TWStringDelete(transactionIDString)
41 + }
42 + return TWStringNSString(TWCoinTypeConfigurationGetTransactionURL(TWCoinType(rawValue: type.rawValue), transactionIDString))
43 + }
44 +
45 + /// Returns account url in blockchain explorer
46 + ///
47 + /// - Parameter type: A coin type
48 + /// - Parameter accountID: an Account identifier
49 + /// - Returns: Returns a non-null TWString account url in blockchain explorer
50 + public static func getAccountURL(type: CoinType, accountID: String) -> String {
51 + let accountIDString = TWStringCreateWithNSString(accountID)
52 + defer {
53 + TWStringDelete(accountIDString)
54 + }
55 + return TWStringNSString(TWCoinTypeConfigurationGetAccountURL(TWCoinType(rawValue: type.rawValue), accountIDString))
56 + }
57 +
58 + /// Returns full name of coin in lower case
59 + ///
60 + /// - Parameter type: A coin type
61 + /// - Returns: Returns a non-null TWString, full name of coin in lower case
62 + public static func getID(type: CoinType) -> String {
63 + return TWStringNSString(TWCoinTypeConfigurationGetID(TWCoinType(rawValue: type.rawValue)))
64 + }
65 +
66 + /// Returns full name of coin
67 + ///
68 + /// - Parameter type: A coin type
69 + /// - Returns: Returns a non-null TWString, full name of coin
70 + public static func getName(type: CoinType) -> String {
71 + return TWStringNSString(TWCoinTypeConfigurationGetName(TWCoinType(rawValue: type.rawValue)))
72 + }
73 +
74 + /// Returns native token name of coin
75 + ///
76 + /// - Parameter type: A coin type
77 + /// - Returns: Returns a non-null TWString, native token name of coin
78 + public static func getNativeTokenName(type: CoinType) -> String {
79 + return TWStringNSString(TWCoinTypeConfigurationGetNativeTokenName(TWCoinType(rawValue: type.rawValue)))
80 + }
81 +
82 +
83 + init() {
84 + }
85 +
86 +
87 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/CryptoBox.swift +54 −0
@@ -0,0 +1,54 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// `crypto_box` encryption algorithms.
13 +public struct CryptoBox {
14 +
15 + /// Encrypts message using `my_secret` and `other_pubkey`.
16 + /// The output will have a randomly generated nonce prepended to it.
17 + /// The output will be Overhead + 24 bytes longer than the original.
18 + ///
19 + /// - Parameter mySecret: *non-null* pointer to my secret key.
20 + /// - Parameter otherPubkey: *non-null* pointer to other's public key.
21 + /// - Parameter message: *non-null* pointer to the message to be encrypted.
22 + /// - Returns: *nullable* pointer to the encrypted message with randomly generated nonce prepended to it.
23 + public static func encryptEasy(mySecret: CryptoBoxSecretKey, otherPubkey: CryptoBoxPublicKey, message: Data) -> Data {
24 + let messageData = TWDataCreateWithNSData(message)
25 + defer {
26 + TWDataDelete(messageData)
27 + }
28 + return TWDataNSData(TWCryptoBoxEncryptEasy(mySecret.rawValue, otherPubkey.rawValue, messageData))
29 + }
30 +
31 + /// Decrypts box produced by `TWCryptoBoxEncryptEasy`.
32 + /// We assume a 24-byte nonce is prepended to the encrypted text in box.
33 + ///
34 + /// - Parameter mySecret: *non-null* pointer to my secret key.
35 + /// - Parameter otherPubkey: *non-null* pointer to other's public key.
36 + /// - Parameter encrypted: *non-null* pointer to the encrypted message with nonce prepended to it.
37 + /// - Returns: *nullable* pointer to the decrypted message.
38 + public static func decryptEasy(mySecret: CryptoBoxSecretKey, otherPubkey: CryptoBoxPublicKey, encrypted: Data) -> Data? {
39 + let encryptedData = TWDataCreateWithNSData(encrypted)
40 + defer {
41 + TWDataDelete(encryptedData)
42 + }
43 + guard let result = TWCryptoBoxDecryptEasy(mySecret.rawValue, otherPubkey.rawValue, encryptedData) else {
44 + return nil
45 + }
46 + return TWDataNSData(result)
47 + }
48 +
49 +
50 + init() {
51 + }
52 +
53 +
54 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/CryptoBoxPublicKey.swift +56 −0
@@ -0,0 +1,56 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class CryptoBoxPublicKey {
14 +
15 + /// Determines if the given public key is valid or not.
16 + ///
17 + /// - Parameter data: *non-null* byte array.
18 + /// - Returns: true if the public key is valid, false otherwise.
19 + public static func isValid(data: Data) -> Bool {
20 + let dataData = TWDataCreateWithNSData(data)
21 + defer {
22 + TWDataDelete(dataData)
23 + }
24 + return TWCryptoBoxPublicKeyIsValid(dataData)
25 + }
26 +
27 + /// Returns the raw data of a given public-key.
28 + ///
29 + /// - Parameter public_key: *non-null* pointer to a public key.
30 + /// - Returns: C-compatible result with a C-compatible byte array.
31 + public var data: Data {
32 + return TWDataNSData(TWCryptoBoxPublicKeyData(rawValue))
33 + }
34 +
35 + let rawValue: OpaquePointer
36 +
37 + init(rawValue: OpaquePointer) {
38 + self.rawValue = rawValue
39 + }
40 +
41 + public init?(data: Data) {
42 + let dataData = TWDataCreateWithNSData(data)
43 + defer {
44 + TWDataDelete(dataData)
45 + }
46 + guard let rawValue = TWCryptoBoxPublicKeyCreateWithData(dataData) else {
47 + return nil
48 + }
49 + self.rawValue = rawValue
50 + }
51 +
52 + deinit {
53 + TWCryptoBoxPublicKeyDelete(rawValue)
54 + }
55 +
56 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/CryptoBoxSecretKey.swift +68 −0
@@ -0,0 +1,68 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class CryptoBoxSecretKey {
14 +
15 + /// Determines if the given secret key is valid or not.
16 + ///
17 + /// - Parameter data: *non-null* byte array.
18 + /// - Returns: true if the secret key is valid, false otherwise.
19 + public static func isValid(data: Data) -> Bool {
20 + let dataData = TWDataCreateWithNSData(data)
21 + defer {
22 + TWDataDelete(dataData)
23 + }
24 + return TWCryptoBoxSecretKeyIsValid(dataData)
25 + }
26 +
27 + /// Returns the raw data of a given secret-key.
28 + ///
29 + /// - Parameter secret_key: *non-null* pointer to a secret key.
30 + /// - Returns: C-compatible result with a C-compatible byte array.
31 + public var data: Data {
32 + return TWDataNSData(TWCryptoBoxSecretKeyData(rawValue))
33 + }
34 +
35 + let rawValue: OpaquePointer
36 +
37 + init(rawValue: OpaquePointer) {
38 + self.rawValue = rawValue
39 + }
40 +
41 + public init() {
42 + rawValue = TWCryptoBoxSecretKeyCreate()
43 + }
44 +
45 + public init?(data: Data) {
46 + let dataData = TWDataCreateWithNSData(data)
47 + defer {
48 + TWDataDelete(dataData)
49 + }
50 + guard let rawValue = TWCryptoBoxSecretKeyCreateWithData(dataData) else {
51 + return nil
52 + }
53 + self.rawValue = rawValue
54 + }
55 +
56 + deinit {
57 + TWCryptoBoxSecretKeyDelete(rawValue)
58 + }
59 +
60 + /// Returns the public key associated with the given `key`.
61 + ///
62 + /// - Parameter key: *non-null* pointer to the private key.
63 + /// - Returns: *non-null* pointer to the corresponding public key.
64 + public func getPublicKey() -> CryptoBoxPublicKey {
65 + return CryptoBoxPublicKey(rawValue: TWCryptoBoxSecretKeyGetPublicKey(rawValue))
66 + }
67 +
68 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/DataVector.swift +71 −0
@@ -0,0 +1,71 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// A vector of TWData byte arrays
13 +public final class DataVector {
14 +
15 + /// Retrieve the number of elements
16 + ///
17 + /// - Parameter dataVector: A non-null Vector of data
18 + /// - Returns: the size of the given vector.
19 + public var size: Int {
20 + return TWDataVectorSize(rawValue)
21 + }
22 +
23 + let rawValue: OpaquePointer
24 +
25 + init(rawValue: OpaquePointer) {
26 + self.rawValue = rawValue
27 + }
28 +
29 + public init() {
30 + rawValue = TWDataVectorCreate()
31 + }
32 +
33 + public init(data: Data) {
34 + let dataData = TWDataCreateWithNSData(data)
35 + defer {
36 + TWDataDelete(dataData)
37 + }
38 + rawValue = TWDataVectorCreateWithData(dataData)
39 + }
40 +
41 + deinit {
42 + TWDataVectorDelete(rawValue)
43 + }
44 +
45 + /// Add an element to a Vector of Data. Element is cloned
46 + ///
47 + /// - Parameter dataVector: A non-null Vector of data
48 + /// - Parameter data: A non-null valid block of data
49 + /// - Note: data input parameter must be deleted on its own
50 + public func add(data: Data) -> Void {
51 + let dataData = TWDataCreateWithNSData(data)
52 + defer {
53 + TWDataDelete(dataData)
54 + }
55 + return TWDataVectorAdd(rawValue, dataData)
56 + }
57 +
58 + /// Retrieve the n-th element.
59 + ///
60 + /// - Parameter dataVector: A non-null Vector of data
61 + /// - Parameter index: index element of the vector to be retrieved, need to be < TWDataVectorSize
62 + /// - Note: Returned element must be freed with \TWDataDelete
63 + /// - Returns: A non-null block of data
64 + public func get(index: Int) -> Data? {
65 + guard let result = TWDataVectorGet(rawValue, index) else {
66 + return nil
67 + }
68 + return TWDataNSData(result)
69 + }
70 +
71 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/DerivationPath.swift +108 −0
@@ -0,0 +1,108 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a BIP44 DerivationPath in C++.
13 +public final class DerivationPath {
14 +
15 + /// Returns the purpose enum of a DerivationPath.
16 + ///
17 + /// - Parameter path: DerivationPath to get the purpose of.
18 + /// - Returns: DerivationPathPurpose.
19 + public var purpose: Purpose {
20 + return Purpose(rawValue: TWDerivationPathPurpose(rawValue).rawValue)!
21 + }
22 +
23 + /// Returns the coin value of a derivation path.
24 + ///
25 + /// - Parameter path: DerivationPath to get the coin of.
26 + /// - Returns: The coin part of the DerivationPath.
27 + public var coin: UInt32 {
28 + return TWDerivationPathCoin(rawValue)
29 + }
30 +
31 + /// Returns the account value of a derivation path.
32 + ///
33 + /// - Parameter path: DerivationPath to get the account of.
34 + /// - Returns: the account part of a derivation path.
35 + public var account: UInt32 {
36 + return TWDerivationPathAccount(rawValue)
37 + }
38 +
39 + /// Returns the change value of a derivation path.
40 + ///
41 + /// - Parameter path: DerivationPath to get the change of.
42 + /// - Returns: The change part of a derivation path.
43 + public var change: UInt32 {
44 + return TWDerivationPathChange(rawValue)
45 + }
46 +
47 + /// Returns the address value of a derivation path.
48 + ///
49 + /// - Parameter path: DerivationPath to get the address of.
50 + /// - Returns: The address part of the derivation path.
51 + public var address: UInt32 {
52 + return TWDerivationPathAddress(rawValue)
53 + }
54 +
55 + /// Returns the string description of a derivation path.
56 + ///
57 + /// - Parameter path: DerivationPath to get the address of.
58 + /// - Returns: The string description of the derivation path.
59 + public var description: String {
60 + return TWStringNSString(TWDerivationPathDescription(rawValue))
61 + }
62 +
63 + let rawValue: OpaquePointer
64 +
65 + init(rawValue: OpaquePointer) {
66 + self.rawValue = rawValue
67 + }
68 +
69 + public init(purpose: Purpose, coin: UInt32, account: UInt32, change: UInt32, address: UInt32) {
70 + rawValue = TWDerivationPathCreate(TWPurpose(rawValue: purpose.rawValue), coin, account, change, address)
71 + }
72 +
73 + public init?(string: String) {
74 + let stringString = TWStringCreateWithNSString(string)
75 + defer {
76 + TWStringDelete(stringString)
77 + }
78 + guard let rawValue = TWDerivationPathCreateWithString(stringString) else {
79 + return nil
80 + }
81 + self.rawValue = rawValue
82 + }
83 +
84 + deinit {
85 + TWDerivationPathDelete(rawValue)
86 + }
87 +
88 + /// Returns the index component of a DerivationPath.
89 + ///
90 + /// - Parameter path: DerivationPath to get the index of.
91 + /// - Parameter index: The index component of the DerivationPath.
92 + /// - Returns: DerivationPathIndex or null if index is invalid.
93 + public func indexAt(index: UInt32) -> DerivationPathIndex? {
94 + guard let value = TWDerivationPathIndexAt(rawValue, index) else {
95 + return nil
96 + }
97 + return DerivationPathIndex(rawValue: value)
98 + }
99 +
100 + /// Returns the indices count of a DerivationPath.
101 + ///
102 + /// - Parameter path: DerivationPath to get the indices count of.
103 + /// - Returns: The indices count of the DerivationPath.
104 + public func indicesCount() -> UInt32 {
105 + return TWDerivationPathIndicesCount(rawValue)
106 + }
107 +
108 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/DerivationPathIndex.swift +52 −0
@@ -0,0 +1,52 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a derivation path index in C++ with value and hardened flag.
13 +public final class DerivationPathIndex {
14 +
15 + /// Returns numeric value of an Index.
16 + ///
17 + /// - Parameter index: Index to get the numeric value of.
18 + public var value: UInt32 {
19 + return TWDerivationPathIndexValue(rawValue)
20 + }
21 +
22 + /// Returns hardened flag of an Index.
23 + ///
24 + /// - Parameter index: Index to get hardened flag.
25 + /// - Returns: true if hardened, false otherwise.
26 + public var hardened: Bool {
27 + return TWDerivationPathIndexHardened(rawValue)
28 + }
29 +
30 + /// Returns the string description of a derivation path index.
31 + ///
32 + /// - Parameter path: Index to get the address of.
33 + /// - Returns: The string description of the derivation path index.
34 + public var description: String {
35 + return TWStringNSString(TWDerivationPathIndexDescription(rawValue))
36 + }
37 +
38 + let rawValue: OpaquePointer
39 +
40 + init(rawValue: OpaquePointer) {
41 + self.rawValue = rawValue
42 + }
43 +
44 + public init(value: UInt32, hardened: Bool) {
45 + rawValue = TWDerivationPathIndexCreate(value, hardened)
46 + }
47 +
48 + deinit {
49 + TWDerivationPathIndexDelete(rawValue)
50 + }
51 +
52 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Eip7702.swift +78 −0
@@ -0,0 +1,78 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class Eip7702 {
14 +
15 + /// Signs an Authorization hash in [EIP-7702 format](https://eips.ethereum.org/EIPS/eip-7702)
16 + ///
17 + /// - Parameter chain_id: The chain ID of the user.
18 + /// - Parameter contract_address: The address of the smart contract wallet.
19 + /// - Parameter nonce: The nonce of the user.
20 + /// - Parameter private_key: The private key of the user.
21 + /// - Returns: The signed authorization.
22 + public static func signAuthorization(chainId: Data, contractAddress: String, nonce: Data, privateKey: String) -> String? {
23 + let chainIdData = TWDataCreateWithNSData(chainId)
24 + defer {
25 + TWDataDelete(chainIdData)
26 + }
27 + let contractAddressString = TWStringCreateWithNSString(contractAddress)
28 + defer {
29 + TWStringDelete(contractAddressString)
30 + }
31 + let nonceData = TWDataCreateWithNSData(nonce)
32 + defer {
33 + TWDataDelete(nonceData)
34 + }
35 + let privateKeyString = TWStringCreateWithNSString(privateKey)
36 + defer {
37 + TWStringDelete(privateKeyString)
38 + }
39 + guard let result = TWEip7702SignAuthorization(chainIdData, contractAddressString, nonceData, privateKeyString) else {
40 + return nil
41 + }
42 + return TWStringNSString(result)
43 + }
44 +
45 + /// Computes an Authorization hash in [EIP-7702 format](https://eips.ethereum.org/EIPS/eip-7702)
46 + /// `keccak256('0x05' || rlp([chain_id, address, nonce]))`.
47 + ///
48 + /// - Parameter chain_id: The chain ID of the user.
49 + /// - Parameter contract_address: The address of the smart contract wallet.
50 + /// - Parameter nonce: The nonce of the user.
51 + /// - Returns: The authorization hash.
52 + public static func getAuthorizationHash(chainId: Data, contractAddress: String, nonce: Data) -> Data? {
53 + let chainIdData = TWDataCreateWithNSData(chainId)
54 + defer {
55 + TWDataDelete(chainIdData)
56 + }
57 + let contractAddressString = TWStringCreateWithNSString(contractAddress)
58 + defer {
59 + TWStringDelete(contractAddressString)
60 + }
61 + let nonceData = TWDataCreateWithNSData(nonce)
62 + defer {
63 + TWDataDelete(nonceData)
64 + }
65 + guard let result = TWEip7702GetAuthorizationHash(chainIdData, contractAddressString, nonceData) else {
66 + return nil
67 + }
68 + return TWDataNSData(result)
69 + }
70 +
71 + let rawValue: OpaquePointer
72 +
73 + init(rawValue: OpaquePointer) {
74 + self.rawValue = rawValue
75 + }
76 +
77 +
78 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/AESPaddingMode.swift +14 −0
@@ -0,0 +1,14 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Padding mode used in AES encryption.
11 +public enum AESPaddingMode: UInt32, CaseIterable {
12 + case zero = 0
13 + case pkcs7 = 1
14 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/BitcoinSigHashType.swift +17 −0
@@ -0,0 +1,17 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Bitcoin SIGHASH type.
11 +public enum BitcoinSigHashType: UInt32, CaseIterable {
12 + case all = 0x01
13 + case none = 0x02
14 + case single = 0x03
15 + case fork = 0x40
16 + case forkBTG = 0x4f40
17 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/Blockchain.swift +70 −0
@@ -0,0 +1,70 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Blockchain enum type
11 +public enum Blockchain: UInt32, CaseIterable {
12 + case bitcoin = 0
13 + case ethereum = 1
14 + case vechain = 3
15 + case tron = 4
16 + case icon = 5
17 + case binance = 6
18 + case ripple = 7
19 + case tezos = 8
20 + case nimiq = 9
21 + case stellar = 10
22 + case aion = 11
23 + case cosmos = 12
24 + case theta = 13
25 + case ontology = 14
26 + case zilliqa = 15
27 + case ioTeX = 16
28 + case eos = 17
29 + case nano = 18
30 + case nuls = 19
31 + case waves = 20
32 + case aeternity = 21
33 + case nebulas = 22
34 + case fio = 23
35 + case solana = 24
36 + case harmony = 25
37 + case near = 26
38 + case algorand = 27
39 + case iost = 28
40 + case polkadot = 29
41 + case cardano = 30
42 + case neo = 31
43 + case filecoin = 32
44 + case multiversX = 33
45 + case oasisNetwork = 34
46 + case decred = 35
47 + case zcash = 36
48 + case groestlcoin = 37
49 + case thorchain = 38
50 + case ronin = 39
51 + case kusama = 40
52 + case zen = 41
53 + case bitcoinDiamond = 42
54 + case verge = 43
55 + case nervos = 44
56 + case everscale = 45
57 + case aptos = 46
58 + case nebl = 47
59 + case hedera = 48
60 + case theOpenNetwork = 49
61 + case sui = 50
62 + case greenfield = 51
63 + case internetComputer = 52
64 + case nativeEvmos = 53
65 + case nativeInjective = 54
66 + case bitcoinCash = 55
67 + case pactus = 56
68 + case komodo = 57
69 + case polymesh = 58
70 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/CoinType.swift +181 −0
@@ -0,0 +1,181 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Represents a private key./// Represents a public key./// Coin type for Level 2 of BIP44.
11 +///
12 +/// \see https://github.com/satoshilabs/slips/blob/master/slip-0044.md
13 +public enum CoinType: UInt32, CaseIterable {
14 + case aeternity = 457
15 + case aion = 425
16 + case binance = 714
17 + case bitcoin = 0
18 + case bitcoinCash = 145
19 + case bitcoinGold = 156
20 + case callisto = 820
21 + case cardano = 1815
22 + case cosmos = 118
23 + case pivx = 119
24 + case dash = 5
25 + case decred = 42
26 + case digiByte = 20
27 + case dogecoin = 3
28 + case eos = 194
29 + case wax = 14001
30 + case ethereum = 60
31 + case ethereumClassic = 61
32 + case fio = 235
33 + case goChain = 6060
34 + case groestlcoin = 17
35 + case icon = 74
36 + case ioTeX = 304
37 + case kava = 459
38 + case kin = 2017
39 + case litecoin = 2
40 + case monacoin = 22
41 + case nebulas = 2718
42 + case nuls = 8964
43 + case nano = 165
44 + case near = 397
45 + case nimiq = 242
46 + case ontology = 1024
47 + case poanetwork = 178
48 + case qtum = 2301
49 + case xrp = 144
50 + case solana = 501
51 + case stellar = 148
52 + case tezos = 1729
53 + case theta = 500
54 + case thunderCore = 1001
55 + case neo = 888
56 + case viction = 889
57 + case tron = 195
58 + case veChain = 818
59 + case viacoin = 14
60 + case wanchain = 5718350
61 + case zcash = 133
62 + case firo = 136
63 + case zilliqa = 313
64 + case zelcash = 19167
65 + case ravencoin = 175
66 + case waves = 5741564
67 + case terra = 330
68 + case terraV2 = 10000330
69 + case harmony = 1023
70 + case algorand = 283
71 + case kusama = 434
72 + case polkadot = 354
73 + case filecoin = 461
74 + case multiversX = 508
75 + case bandChain = 494
76 + case smartChainLegacy = 10000714
77 + case smartChain = 20000714
78 + case tbinance = 30000714
79 + case oasis = 474
80 + case polygon = 966
81 + case thorchain = 931
82 + case bluzelle = 483
83 + case optimism = 10000070
84 + case zksync = 10000324
85 + case arbitrum = 10042221
86 + case ecochain = 10000553
87 + case avalancheCChain = 10009000
88 + case xdai = 10000100
89 + case fantom = 10000250
90 + case cryptoOrg = 394
91 + case celo = 52752
92 + case ronin = 10002020
93 + case osmosis = 10000118
94 + case ecash = 899
95 + case iost = 291
96 + case cronosChain = 10000025
97 + case smartBitcoinCash = 10000145
98 + case kuCoinCommunityChain = 10000321
99 + case bitcoinDiamond = 999
100 + case boba = 10000288
101 + case syscoin = 57
102 + case verge = 77
103 + case zen = 121
104 + case metis = 10001088
105 + case aurora = 1323161554
106 + case evmos = 10009001
107 + case nativeEvmos = 20009001
108 + case moonriver = 10001285
109 + case moonbeam = 10001284
110 + case kavaEvm = 10002222
111 + case kaia = 10008217
112 + case meter = 18000
113 + case okxchain = 996
114 + case stratis = 105105
115 + case komodo = 141
116 + case nervos = 309
117 + case everscale = 396
118 + case aptos = 637
119 + case nebl = 146
120 + case hedera = 3030
121 + case secret = 529
122 + case nativeInjective = 10000060
123 + case agoric = 564
124 + case ton = 607
125 + case sui = 784
126 + case stargaze = 20000118
127 + case polygonzkEVM = 10001101
128 + case juno = 30000118
129 + case stride = 40000118
130 + case axelar = 50000118
131 + case crescent = 60000118
132 + case kujira = 70000118
133 + case ioTeXEVM = 10004689
134 + case nativeCanto = 10007700
135 + case comdex = 80000118
136 + case neutron = 90000118
137 + case sommelier = 11000118
138 + case fetchAI = 12000118
139 + case mars = 13000118
140 + case umee = 14000118
141 + case coreum = 10000990
142 + case quasar = 15000118
143 + case persistence = 16000118
144 + case akash = 17000118
145 + case noble = 18000118
146 + case scroll = 534352
147 + case rootstock = 137
148 + case thetaFuel = 361
149 + case confluxeSpace = 1030
150 + case acala = 787
151 + case acalaEVM = 10000787
152 + case opBNB = 204
153 + case neon = 245022934
154 + case base = 8453
155 + case sei = 19000118
156 + case arbitrumNova = 10042170
157 + case linea = 59144
158 + case greenfield = 5600
159 + case mantle = 5000
160 + case zenEON = 7332
161 + case internetComputer = 223
162 + case tia = 21000118
163 + case mantaPacific = 169
164 + case nativeZetaChain = 10007000
165 + case zetaEVM = 20007000
166 + case dydx = 22000118
167 + case merlin = 4200
168 + case lightlink = 1890
169 + case blast = 81457
170 + case bounceBit = 6001
171 + case zkLinkNova = 810180
172 + case pactus = 21888
173 + case sonic = 10000146
174 + case polymesh = 595
175 + case plasma = 9745
176 + case monad = 10143
177 + case megaETH = 4326
178 + case seiEVM = 1329
179 + case hyperEVM = 10000999
180 + case robinhoodChain = 10004663
181 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/Curve.swift +31 −0
@@ -0,0 +1,31 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Elliptic cruves
11 +public enum Curve: UInt32, CaseIterable, CustomStringConvertible {
12 + case secp256k1 = 0
13 + case ed25519 = 1
14 + case ed25519Blake2bNano = 2
15 + case curve25519 = 3
16 + case nist256p1 = 4
17 + case ed25519ExtendedCardano = 5
18 + case starkex = 6
19 +
20 + public var description: String {
21 + switch self {
22 + case .secp256k1: return "secp256k1"
23 + case .ed25519: return "ed25519"
24 + case .ed25519Blake2bNano: return "ed25519-blake2b-nano"
25 + case .curve25519: return "curve25519"
26 + case .nist256p1: return "nist256p1"
27 + case .ed25519ExtendedCardano: return "ed25519-cardano-seed"
28 + case .starkex: return "starkex"
29 + }
30 + }
31 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/Derivation.swift +26 −0
@@ -0,0 +1,26 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Non-default coin address derivation names (default, unnamed derivations are not included).
11 +/// Note the enum variant must be sync with `TWDerivation` enum in Rust:
12 +/// https://github.com/trustwallet/wallet-core/blob/master/rust/tw_coin_registry/src/tw_derivation.rs
13 +public enum Derivation: UInt32, CaseIterable {
14 + case `default` = 0
15 + case custom = 1
16 + case bitcoinSegwit = 2
17 + case bitcoinLegacy = 3
18 + case bitcoinTestnet = 4
19 + case litecoinLegacy = 5
20 + case solanaSolana = 6
21 + case stratisSegwit = 7
22 + case bitcoinTaproot = 8
23 + case pactusMainnet = 9
24 + case pactusTestnet = 10
25 + case smartChainStableAccount = 11
26 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/EthereumChainID.swift +74 −0
@@ -0,0 +1,74 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Chain identifiers for Ethereum-based blockchains, for convenience. Recommended to use the dynamic CoinType.ChainId() instead.
11 +/// See also TWChainId.
12 +public enum EthereumChainID: UInt32, CaseIterable {
13 + case ethereum = 1
14 + case classic = 61
15 + case rootstock = 30
16 + case manta = 169
17 + case poa = 99
18 + case opbnb = 204
19 + case tfuelevm = 361
20 + case vechain = 74
21 + case callisto = 820
22 + case viction = 88
23 + case polygon = 137
24 + case okc = 66
25 + case thundertoken = 108
26 + case cfxevm = 1030
27 + case seievm = 1329
28 + case lightlink = 1890
29 + case merlin = 4200
30 + case megaeth = 4326
31 + case mantle = 5000
32 + case bouncebit = 6001
33 + case gochain = 60
34 + case zeneon = 7332
35 + case base = 8453
36 + case plasma = 9745
37 + case monad = 143
38 + case meter = 82
39 + case celo = 42220
40 + case linea = 59144
41 + case blast = 81457
42 + case scroll = 534352
43 + case zklinknova = 810180
44 + case wanchain = 888
45 + case cronos = 25
46 + case optimism = 10
47 + case xdai = 100
48 + case smartbch = 10000
49 + case sonic = 146
50 + case fantom = 250
51 + case boba = 288
52 + case kcc = 321
53 + case zksync = 324
54 + case heco = 128
55 + case acalaevm = 787
56 + case hyperevm = 999
57 + case metis = 1088
58 + case polygonzkevm = 1101
59 + case moonbeam = 1284
60 + case moonriver = 1285
61 + case ronin = 2020
62 + case kavaevm = 2222
63 + case robinhoodchain = 4663
64 + case iotexevm = 4689
65 + case kaia = 8217
66 + case avalanchec = 43114
67 + case evmos = 9001
68 + case arbitrumnova = 42170
69 + case arbitrum = 42161
70 + case smartchain = 56
71 + case zetaevm = 7000
72 + case neon = 245022934
73 + case aurora = 1313161554
74 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/FilecoinAddressType.swift +14 −0
@@ -0,0 +1,14 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Filecoin address type.
11 +public enum FilecoinAddressType: UInt32, CaseIterable {
12 + case `default` = 0
13 + case delegated = 1
14 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/FiroAddressType.swift +14 −0
@@ -0,0 +1,14 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Firo address type.
11 +public enum FiroAddressType: UInt32, CaseIterable {
12 + case `default` = 0
13 + case exchange = 1
14 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/HDVersion.swift +35 −0
@@ -0,0 +1,35 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Registered HD version bytes
11 +///
12 +/// \see https://github.com/satoshilabs/slips/blob/master/slip-0132.md
13 +public enum HDVersion: UInt32, CaseIterable {
14 + case none = 0
15 + case xpub = 0x0488b21e
16 + case xprv = 0x0488ade4
17 + case ypub = 0x049d7cb2
18 + case yprv = 0x049d7878
19 + case zpub = 0x04b24746
20 + case zprv = 0x04b2430c
21 + case vpub = 0x045f1cf6
22 + case vprv = 0x045f18bc
23 + case tpub = 0x043587cf
24 + case tprv = 0x04358394
25 + case ltub = 0x019da462
26 + case ltpv = 0x019d9cfe
27 + case mtub = 0x01b26ef6
28 + case mtpv = 0x01b26792
29 + case ttub = 0x0436f6e1
30 + case ttpv = 0x0436ef7d
31 + case dpub = 0x2fda926
32 + case dprv = 0x2fda4e8
33 + case dgub = 0x02facafd
34 + case dgpv = 0x02fac398
35 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/HRP.swift +141 −0
@@ -0,0 +1,141 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Registered human-readable parts for BIP-0173
11 +///
12 +/// - SeeAlso: https://github.com/satoshilabs/slips/blob/master/slip-0173.md
13 +public enum HRP: UInt32, CaseIterable, CustomStringConvertible {
14 + case unknown = 0
15 + case bitcoin = 1
16 + case litecoin = 2
17 + case viacoin = 3
18 + case groestlcoin = 4
19 + case digiByte = 5
20 + case monacoin = 6
21 + case syscoin = 7
22 + case verge = 8
23 + case cosmos = 9
24 + case zcash = 10
25 + case bitcoinCash = 11
26 + case bitcoinGold = 12
27 + case ioTeX = 13
28 + case nervos = 14
29 + case zilliqa = 15
30 + case terra = 16
31 + case cryptoOrg = 17
32 + case kava = 18
33 + case oasis = 19
34 + case bluzelle = 20
35 + case bandChain = 21
36 + case multiversX = 22
37 + case secret = 23
38 + case agoric = 24
39 + case binance = 25
40 + case ecash = 26
41 + case thorchain = 27
42 + case bitcoinDiamond = 28
43 + case harmony = 29
44 + case cardano = 30
45 + case qtum = 31
46 + case pactus = 32
47 + case stratis = 33
48 + case nativeInjective = 34
49 + case osmosis = 35
50 + case terraV2 = 36
51 + case coreum = 37
52 + case nativeZetaChain = 38
53 + case nativeCanto = 39
54 + case sommelier = 40
55 + case fetchAI = 41
56 + case mars = 42
57 + case umee = 43
58 + case quasar = 44
59 + case persistence = 45
60 + case akash = 46
61 + case noble = 47
62 + case sei = 48
63 + case stargaze = 49
64 + case nativeEvmos = 50
65 + case tia = 51
66 + case dydx = 52
67 + case juno = 53
68 + case tbinance = 54
69 + case stride = 55
70 + case axelar = 56
71 + case crescent = 57
72 + case kujira = 58
73 + case comdex = 59
74 + case neutron = 60
75 +
76 + public var description: String {
77 + switch self {
78 + case .unknown: return ""
79 + case .bitcoin: return "bc"
80 + case .litecoin: return "ltc"
81 + case .viacoin: return "via"
82 + case .groestlcoin: return "grs"
83 + case .digiByte: return "dgb"
84 + case .monacoin: return "mona"
85 + case .syscoin: return "sys"
86 + case .verge: return "vg"
87 + case .cosmos: return "cosmos"
88 + case .zcash: return "tex"
89 + case .bitcoinCash: return "bitcoincash"
90 + case .bitcoinGold: return "btg"
91 + case .ioTeX: return "io"
92 + case .nervos: return "ckb"
93 + case .zilliqa: return "zil"
94 + case .terra: return "terra"
95 + case .cryptoOrg: return "cro"
96 + case .kava: return "kava"
97 + case .oasis: return "oasis"
98 + case .bluzelle: return "bluzelle"
99 + case .bandChain: return "band"
100 + case .multiversX: return "erd"
101 + case .secret: return "secret"
102 + case .agoric: return "agoric"
103 + case .binance: return "bnb"
104 + case .ecash: return "ecash"
105 + case .thorchain: return "thor"
106 + case .bitcoinDiamond: return "bcd"
107 + case .harmony: return "one"
108 + case .cardano: return "addr"
109 + case .qtum: return "qc"
110 + case .pactus: return "pc"
111 + case .stratis: return "strax"
112 + case .nativeInjective: return "inj"
113 + case .osmosis: return "osmo"
114 + case .terraV2: return "terra"
115 + case .coreum: return "core"
116 + case .nativeZetaChain: return "zeta"
117 + case .nativeCanto: return "canto"
118 + case .sommelier: return "somm"
119 + case .fetchAI: return "fetch"
120 + case .mars: return "mars"
121 + case .umee: return "umee"
122 + case .quasar: return "quasar"
123 + case .persistence: return "persistence"
124 + case .akash: return "akash"
125 + case .noble: return "noble"
126 + case .sei: return "sei"
127 + case .stargaze: return "stars"
128 + case .nativeEvmos: return "evmos"
129 + case .tia: return "celestia"
130 + case .dydx: return "dydx"
131 + case .juno: return "juno"
132 + case .tbinance: return "tbnb"
133 + case .stride: return "stride"
134 + case .axelar: return "axelar"
135 + case .crescent: return "cre"
136 + case .kujira: return "kujira"
137 + case .comdex: return "comdex"
138 + case .neutron: return "neutron"
139 + }
140 + }
141 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/PrivateKeyType.swift +14 −0
@@ -0,0 +1,14 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Private key types, the vast majority of chains use the default, 32-byte key.
11 +public enum PrivateKeyType: UInt32, CaseIterable {
12 + case `default` = 0
13 + case cardano = 1
14 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/PublicKeyType.swift +21 −0
@@ -0,0 +1,21 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Public key types
11 +public enum PublicKeyType: UInt32, CaseIterable {
12 + case secp256k1 = 0
13 + case secp256k1Extended = 1
14 + case nist256p1 = 2
15 + case nist256p1Extended = 3
16 + case ed25519 = 4
17 + case ed25519Blake2b = 5
18 + case curve25519 = 6
19 + case ed25519Cardano = 7
20 + case starkex = 8
21 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/Purpose.swift +21 −0
@@ -0,0 +1,21 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// HD wallet purpose
11 +///
12 +/// \see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
13 +/// \see https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
14 +/// \see https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki
15 +public enum Purpose: UInt32, CaseIterable {
16 + case bip44 = 44
17 + case bip49 = 49
18 + case bip84 = 84
19 + case bip86 = 86
20 + case bip1852 = 1852
21 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/StellarMemoType.swift +17 −0
@@ -0,0 +1,17 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Stellar memo type.
11 +public enum StellarMemoType: UInt32, CaseIterable {
12 + case none = 0
13 + case text = 1
14 + case id = 2
15 + case hash = 3
16 + case `return` = 4
17 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/StellarPassphrase.swift +21 −0
@@ -0,0 +1,21 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Stellar network passphrase string.
11 +public enum StellarPassphrase: UInt32, CaseIterable, CustomStringConvertible {
12 + case stellar = 0
13 + case kin = 1
14 +
15 + public var description: String {
16 + switch self {
17 + case .stellar: return "Public Global Stellar Network ; September 2015"
18 + case .kin: return "Kin Mainnet ; December 2018"
19 + }
20 + }
21 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/StellarVersionByte.swift +16 −0
@@ -0,0 +1,16 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Stellar address version byte.
11 +public enum StellarVersionByte: UInt16, CaseIterable {
12 + case accountID = 0x30
13 + case seed = 0xc0
14 + case preAuthTX = 0xc8
15 + case sha256Hash = 0x118
16 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/StoredKeyEncryption.swift +15 −0
@@ -0,0 +1,15 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Preset encryption kind
11 +public enum StoredKeyEncryption: UInt32, CaseIterable {
12 + case aes128Ctr = 0
13 + case aes192Ctr = 2
14 + case aes256Ctr = 3
15 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Enums/StoredKeyEncryptionLevel.swift +16 −0
@@ -0,0 +1,16 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +/// Preset encryption parameter with different security strength, for key store
11 +public enum StoredKeyEncryptionLevel: UInt32, CaseIterable {
12 + case `default` = 0
13 + case minimal = 1
14 + case weak = 2
15 + case standard = 3
16 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Ethereum.swift +112 −0
@@ -0,0 +1,112 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class Ethereum {
14 +
15 + /// Returns the checksummed address.
16 + ///
17 + /// - Parameter address: *non-null* string.
18 + /// - Returns: the checksummed address.
19 + public static func addressChecksummed(address: String) -> String? {
20 + let addressString = TWStringCreateWithNSString(address)
21 + defer {
22 + TWStringDelete(addressString)
23 + }
24 + guard let result = TWEthereumAddressChecksummed(addressString) else {
25 + return nil
26 + }
27 + return TWStringNSString(result)
28 + }
29 +
30 + /// Returns the account path from address.
31 + ///
32 + /// - Parameter eth_address: *non-null* string.
33 + /// - Parameter layer: *non-null* string.
34 + /// - Parameter application: *non-null* string.
35 + /// - Parameter index: *non-null* string.
36 + /// - Returns: the account path.
37 + public static func eip2645GetPath(ethAddress: String, layer: String, application: String, index: String) -> String? {
38 + let ethAddressString = TWStringCreateWithNSString(ethAddress)
39 + defer {
40 + TWStringDelete(ethAddressString)
41 + }
42 + let layerString = TWStringCreateWithNSString(layer)
43 + defer {
44 + TWStringDelete(layerString)
45 + }
46 + let applicationString = TWStringCreateWithNSString(application)
47 + defer {
48 + TWStringDelete(applicationString)
49 + }
50 + let indexString = TWStringCreateWithNSString(index)
51 + defer {
52 + TWStringDelete(indexString)
53 + }
54 + guard let result = TWEthereumEip2645GetPath(ethAddressString, layerString, applicationString, indexString) else {
55 + return nil
56 + }
57 + return TWStringNSString(result)
58 + }
59 +
60 + /// Returns EIP-1014 Create2 address
61 + ///
62 + /// - Parameter from: *non-null* string.
63 + /// - Parameter salt: *non-null* data.
64 + /// - Parameter init_code_hash: *non-null* data.
65 + /// - Returns: the EIP-1014 Create2 address.
66 + public static func eip1014Create2Address(from: String, salt: Data, initCodeHash: Data) -> String? {
67 + let fromString = TWStringCreateWithNSString(from)
68 + defer {
69 + TWStringDelete(fromString)
70 + }
71 + let saltData = TWDataCreateWithNSData(salt)
72 + defer {
73 + TWDataDelete(saltData)
74 + }
75 + let initCodeHashData = TWDataCreateWithNSData(initCodeHash)
76 + defer {
77 + TWDataDelete(initCodeHashData)
78 + }
79 + guard let result = TWEthereumEip1014Create2Address(fromString, saltData, initCodeHashData) else {
80 + return nil
81 + }
82 + return TWStringNSString(result)
83 + }
84 +
85 + /// Returns EIP-1967 proxy init code
86 + ///
87 + /// - Parameter logic_address: *non-null* string.
88 + /// - Parameter data: *non-null* data.
89 + /// - Returns: the EIP-1967 proxy init code.
90 + public static func eip1967ProxyInitCode(logicAddress: String, data: Data) -> Data? {
91 + let logicAddressString = TWStringCreateWithNSString(logicAddress)
92 + defer {
93 + TWStringDelete(logicAddressString)
94 + }
95 + let dataData = TWDataCreateWithNSData(data)
96 + defer {
97 + TWDataDelete(dataData)
98 + }
99 + guard let result = TWEthereumEip1967ProxyInitCode(logicAddressString, dataData) else {
100 + return nil
101 + }
102 + return TWDataNSData(result)
103 + }
104 +
105 + let rawValue: OpaquePointer
106 +
107 + init(rawValue: OpaquePointer) {
108 + self.rawValue = rawValue
109 + }
110 +
111 +
112 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/EthereumAbi.swift +174 −0
@@ -0,0 +1,174 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Wrapper class for Ethereum ABI encoding & decoding.
13 +public struct EthereumAbi {
14 +
15 + /// Decode a contract call (function input) according to an ABI json.
16 + ///
17 + /// - Parameter coin: EVM-compatible coin type.
18 + /// - Parameter input: The serialized data of `TW.EthereumAbi.Proto.ContractCallDecodingInput`.
19 + /// - Returns: The serialized data of a `TW.EthereumAbi.Proto.ContractCallDecodingOutput` proto object.
20 + public static func decodeContractCall(coin: CoinType, input: Data) -> Data {
21 + let inputData = TWDataCreateWithNSData(input)
22 + defer {
23 + TWDataDelete(inputData)
24 + }
25 + return TWDataNSData(TWEthereumAbiDecodeContractCall(TWCoinType(rawValue: coin.rawValue), inputData))
26 + }
27 +
28 + /// Decode a function input or output data according to a given ABI.
29 + ///
30 + /// - Parameter coin: EVM-compatible coin type.
31 + /// - Parameter input: The serialized data of `TW.EthereumAbi.Proto.ParamsDecodingInput`.
32 + /// - Returns: The serialized data of a `TW.EthereumAbi.Proto.ParamsDecodingOutput` proto object.
33 + public static func decodeParams(coin: CoinType, input: Data) -> Data {
34 + let inputData = TWDataCreateWithNSData(input)
35 + defer {
36 + TWDataDelete(inputData)
37 + }
38 + return TWDataNSData(TWEthereumAbiDecodeParams(TWCoinType(rawValue: coin.rawValue), inputData))
39 + }
40 +
41 + /// /// Decodes an Eth ABI value according to a given type.
42 + ///
43 + /// - Parameter coin: EVM-compatible coin type.
44 + /// - Parameter input: The serialized data of `TW.EthereumAbi.Proto.ValueDecodingInput`.
45 + /// - Returns: The serialized data of a `TW.EthereumAbi.Proto.ValueDecodingOutput` proto object.
46 + public static func decodeValue(coin: CoinType, input: Data) -> Data {
47 + let inputData = TWDataCreateWithNSData(input)
48 + defer {
49 + TWDataDelete(inputData)
50 + }
51 + return TWDataNSData(TWEthereumAbiDecodeValue(TWCoinType(rawValue: coin.rawValue), inputData))
52 + }
53 +
54 + /// Encode function to Eth ABI binary.
55 + ///
56 + /// - Parameter coin: EVM-compatible coin type.
57 + /// - Parameter input: The serialized data of `TW.EthereumAbi.Proto.FunctionEncodingInput`.
58 + /// - Returns: The serialized data of a `TW.EthereumAbi.Proto.FunctionEncodingOutput` proto object.
59 + public static func encodeFunction(coin: CoinType, input: Data) -> Data {
60 + let inputData = TWDataCreateWithNSData(input)
61 + defer {
62 + TWDataDelete(inputData)
63 + }
64 + return TWDataNSData(TWEthereumAbiEncodeFunction(TWCoinType(rawValue: coin.rawValue), inputData))
65 + }
66 +
67 + /// Encode function to Eth ABI binary
68 + ///
69 + /// - Parameter fn: Non-null Eth abi function
70 + /// - Returns: Non-null encoded block of data
71 + public static func encode(fn: EthereumAbiFunction) -> Data {
72 + return TWDataNSData(TWEthereumAbiEncode(fn.rawValue))
73 + }
74 +
75 + /// Decode function output from Eth ABI binary, fill output parameters
76 + ///
77 + /// \param[in] fn Non-null Eth abi function
78 + /// \param[out] encoded Non-null block of data
79 + /// - Returns: true if encoded have been filled correctly, false otherwise
80 + public static func decodeOutput(fn: EthereumAbiFunction, encoded: Data) -> Bool {
81 + let encodedData = TWDataCreateWithNSData(encoded)
82 + defer {
83 + TWDataDelete(encodedData)
84 + }
85 + return TWEthereumAbiDecodeOutput(fn.rawValue, encodedData)
86 + }
87 +
88 + /// Decode function call data to human readable json format, according to input abi json
89 + ///
90 + /// - Parameter data: Non-null block of data
91 + /// - Parameter abi: Non-null string
92 + /// - Returns: Non-null json string function call data
93 + public static func decodeCall(data: Data, abi: String) -> String? {
94 + let dataData = TWDataCreateWithNSData(data)
95 + defer {
96 + TWDataDelete(dataData)
97 + }
98 + let abiString = TWStringCreateWithNSString(abi)
99 + defer {
100 + TWStringDelete(abiString)
101 + }
102 + guard let result = TWEthereumAbiDecodeCall(dataData, abiString) else {
103 + return nil
104 + }
105 + return TWStringNSString(result)
106 + }
107 +
108 + /// Compute the hash of a struct, used for signing, according to EIP712 ("v4").
109 + /// Input is a Json object (as string), with following fields:
110 + /// - types: map of used struct types (see makeTypes())
111 + /// - primaryType: the type of the message (string)
112 + /// - domain: EIP712 domain specifier values
113 + /// - message: the message (object).
114 + /// Throws on error.
115 + /// Example input:
116 + /// R"({
117 + /// "types": {
118 + /// "EIP712Domain": [
119 + /// {"name": "name", "type": "string"},
120 + /// {"name": "version", "type": "string"},
121 + /// {"name": "chainId", "type": "uint256"},
122 + /// {"name": "verifyingContract", "type": "address"}
123 + /// ],
124 + /// "Person": [
125 + /// {"name": "name", "type": "string"},
126 + /// {"name": "wallet", "type": "address"}
127 + /// ]
128 + /// },
129 + /// "primaryType": "Person",
130 + /// "domain": {
131 + /// "name": "Ether Person",
132 + /// "version": "1",
133 + /// "chainId": 1,
134 + /// "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
135 + /// },
136 + /// "message": {
137 + /// "name": "Cow",
138 + /// "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
139 + /// }
140 + /// })");
141 + /// On error, empty Data is returned.
142 + /// Returned data must be deleted (hint: use WRAPD() macro).
143 + ///
144 + /// - Parameter messageJson: Non-null json abi input
145 + /// - Returns: Non-null block of data, encoded abi input
146 + public static func encodeTyped(messageJson: String) -> Data {
147 + let messageJsonString = TWStringCreateWithNSString(messageJson)
148 + defer {
149 + TWStringDelete(messageJsonString)
150 + }
151 + return TWDataNSData(TWEthereumAbiEncodeTyped(messageJsonString))
152 + }
153 +
154 + /// Get function signature from Ethereum ABI json
155 + ///
156 + /// - Parameter abi: The function ABI json string, for example: {"inputs":[{"internalType":"bool","name":"arg1","type":"bool"}],"name":"fun1","outputs":[],"stateMutability":"nonpayable","type":"function"}
157 + /// - Returns: the function type signature, of the form "baz(int32,uint256)", null if the abi is invalid.
158 + public static func getFunctionSignature(abi: String) -> String? {
159 + let abiString = TWStringCreateWithNSString(abi)
160 + defer {
161 + TWStringDelete(abiString)
162 + }
163 + guard let result = TWEthereumAbiGetFunctionSignature(abiString) else {
164 + return nil
165 + }
166 + return TWStringNSString(result)
167 + }
168 +
169 +
170 + init() {
171 + }
172 +
173 +
174 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/EthereumAbiFunction.swift +560 −0
@@ -0,0 +1,560 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents Ethereum ABI function
13 +public final class EthereumAbiFunction {
14 +
15 + let rawValue: OpaquePointer
16 +
17 + init(rawValue: OpaquePointer) {
18 + self.rawValue = rawValue
19 + }
20 +
21 + public init(name: String) {
22 + let nameString = TWStringCreateWithNSString(name)
23 + defer {
24 + TWStringDelete(nameString)
25 + }
26 + rawValue = TWEthereumAbiFunctionCreateWithString(nameString)
27 + }
28 +
29 + deinit {
30 + TWEthereumAbiFunctionDelete(rawValue)
31 + }
32 +
33 + /// Return the function type signature, of the form "baz(int32,uint256)"
34 + ///
35 + /// - Parameter fn: A Non-null eth abi function
36 + /// - Returns: function type signature as a Non-null string.
37 + public func getType() -> String {
38 + return TWStringNSString(TWEthereumAbiFunctionGetType(rawValue))
39 + }
40 +
41 + /// Methods for adding parameters of the given type (input or output).
42 + /// For output parameters (isOutput=true) a value has to be specified, although usually not need;
43 + /// Add a uint8 type parameter
44 + ///
45 + /// - Parameter fn: A Non-null eth abi function
46 + /// - Parameter val: for output parameters, value has to be specified
47 + /// - Parameter isOutput: determines if the parameter is an input or output
48 + /// - Returns: the index of the parameter (0-based).
49 + @discardableResult
50 + public func addParamUInt8(val: UInt8, isOutput: Bool) -> Int32 {
51 + return TWEthereumAbiFunctionAddParamUInt8(rawValue, val, isOutput)
52 + }
53 +
54 + /// Add a uint16 type parameter
55 + ///
56 + /// - Parameter fn: A Non-null eth abi function
57 + /// - Parameter val: for output parameters, value has to be specified
58 + /// - Parameter isOutput: determines if the parameter is an input or output
59 + /// - Returns: the index of the parameter (0-based).
60 + @discardableResult
61 + public func addParamUInt16(val: UInt16, isOutput: Bool) -> Int32 {
62 + return TWEthereumAbiFunctionAddParamUInt16(rawValue, val, isOutput)
63 + }
64 +
65 + /// Add a uint32 type parameter
66 + ///
67 + /// - Parameter fn: A Non-null eth abi function
68 + /// - Parameter val: for output parameters, value has to be specified
69 + /// - Parameter isOutput: determines if the parameter is an input or output
70 + /// - Returns: the index of the parameter (0-based).
71 + @discardableResult
72 + public func addParamUInt32(val: UInt32, isOutput: Bool) -> Int32 {
73 + return TWEthereumAbiFunctionAddParamUInt32(rawValue, val, isOutput)
74 + }
75 +
76 + /// Add a uint64 type parameter
77 + ///
78 + /// - Parameter fn: A Non-null eth abi function
79 + /// - Parameter val: for output parameters, value has to be specified
80 + /// - Parameter isOutput: determines if the parameter is an input or output
81 + /// - Returns: the index of the parameter (0-based).
82 + @discardableResult
83 + public func addParamUInt64(val: UInt64, isOutput: Bool) -> Int32 {
84 + return TWEthereumAbiFunctionAddParamUInt64(rawValue, val, isOutput)
85 + }
86 +
87 + /// Add a uint256 type parameter
88 + ///
89 + /// - Parameter fn: A Non-null eth abi function
90 + /// - Parameter val: for output parameters, value has to be specified
91 + /// - Parameter isOutput: determines if the parameter is an input or output
92 + /// - Returns: the index of the parameter (0-based).
93 + @discardableResult
94 + public func addParamUInt256(val: Data, isOutput: Bool) -> Int32 {
95 + let valData = TWDataCreateWithNSData(val)
96 + defer {
97 + TWDataDelete(valData)
98 + }
99 + return TWEthereumAbiFunctionAddParamUInt256(rawValue, valData, isOutput)
100 + }
101 +
102 + /// Add a uint(bits) type parameter
103 + ///
104 + /// - Parameter fn: A Non-null eth abi function
105 + /// - Parameter val: for output parameters, value has to be specified
106 + /// - Parameter isOutput: determines if the parameter is an input or output
107 + /// - Returns: the index of the parameter (0-based).
108 + @discardableResult
109 + public func addParamUIntN(bits: Int32, val: Data, isOutput: Bool) -> Int32 {
110 + let valData = TWDataCreateWithNSData(val)
111 + defer {
112 + TWDataDelete(valData)
113 + }
114 + return TWEthereumAbiFunctionAddParamUIntN(rawValue, Int32(bits), valData, isOutput)
115 + }
116 +
117 + /// Add a int8 type parameter
118 + ///
119 + /// - Parameter fn: A Non-null eth abi function
120 + /// - Parameter val: for output parameters, value has to be specified
121 + /// - Parameter isOutput: determines if the parameter is an input or output
122 + /// - Returns: the index of the parameter (0-based).
123 + @discardableResult
124 + public func addParamInt8(val: Int8, isOutput: Bool) -> Int32 {
125 + return TWEthereumAbiFunctionAddParamInt8(rawValue, val, isOutput)
126 + }
127 +
128 + /// Add a int16 type parameter
129 + ///
130 + /// - Parameter fn: A Non-null eth abi function
131 + /// - Parameter val: for output parameters, value has to be specified
132 + /// - Parameter isOutput: determines if the parameter is an input or output
133 + /// - Returns: the index of the parameter (0-based).
134 + @discardableResult
135 + public func addParamInt16(val: Int16, isOutput: Bool) -> Int32 {
136 + return TWEthereumAbiFunctionAddParamInt16(rawValue, val, isOutput)
137 + }
138 +
139 + /// Add a int32 type parameter
140 + ///
141 + /// - Parameter fn: A Non-null eth abi function
142 + /// - Parameter val: for output parameters, value has to be specified
143 + /// - Parameter isOutput: determines if the parameter is an input or output
144 + /// - Returns: the index of the parameter (0-based).
145 + @discardableResult
146 + public func addParamInt32(val: Int32, isOutput: Bool) -> Int32 {
147 + return TWEthereumAbiFunctionAddParamInt32(rawValue, val, isOutput)
148 + }
149 +
150 + /// Add a int64 type parameter
151 + ///
152 + /// - Parameter fn: A Non-null eth abi function
153 + /// - Parameter val: for output parameters, value has to be specified
154 + /// - Parameter isOutput: determines if the parameter is an input or output
155 + /// - Returns: the index of the parameter (0-based).
156 + @discardableResult
157 + public func addParamInt64(val: Int64, isOutput: Bool) -> Int32 {
158 + return TWEthereumAbiFunctionAddParamInt64(rawValue, val, isOutput)
159 + }
160 +
161 + /// Add a int256 type parameter
162 + ///
163 + /// - Parameter fn: A Non-null eth abi function
164 + /// - Parameter val: for output parameters, value has to be specified (stored in a block of data)
165 + /// - Parameter isOutput: determines if the parameter is an input or output
166 + /// - Returns: the index of the parameter (0-based).
167 + @discardableResult
168 + public func addParamInt256(val: Data, isOutput: Bool) -> Int32 {
169 + let valData = TWDataCreateWithNSData(val)
170 + defer {
171 + TWDataDelete(valData)
172 + }
173 + return TWEthereumAbiFunctionAddParamInt256(rawValue, valData, isOutput)
174 + }
175 +
176 + /// Add a int(bits) type parameter
177 + ///
178 + /// - Parameter fn: A Non-null eth abi function
179 + /// - Parameter bits: Number of bits of the integer parameter
180 + /// - Parameter val: for output parameters, value has to be specified
181 + /// - Parameter isOutput: determines if the parameter is an input or output
182 + /// - Returns: the index of the parameter (0-based).
183 + @discardableResult
184 + public func addParamIntN(bits: Int32, val: Data, isOutput: Bool) -> Int32 {
185 + let valData = TWDataCreateWithNSData(val)
186 + defer {
187 + TWDataDelete(valData)
188 + }
189 + return TWEthereumAbiFunctionAddParamIntN(rawValue, Int32(bits), valData, isOutput)
190 + }
191 +
192 + /// Add a bool type parameter
193 + ///
194 + /// - Parameter fn: A Non-null eth abi function
195 + /// - Parameter val: for output parameters, value has to be specified
196 + /// - Parameter isOutput: determines if the parameter is an input or output
197 + /// - Returns: the index of the parameter (0-based).
198 + @discardableResult
199 + public func addParamBool(val: Bool, isOutput: Bool) -> Int32 {
200 + return TWEthereumAbiFunctionAddParamBool(rawValue, val, isOutput)
201 + }
202 +
203 + /// Add a string type parameter
204 + ///
205 + /// - Parameter fn: A Non-null eth abi function
206 + /// - Parameter val: for output parameters, value has to be specified
207 + /// - Parameter isOutput: determines if the parameter is an input or output
208 + /// - Returns: the index of the parameter (0-based).
209 + @discardableResult
210 + public func addParamString(val: String, isOutput: Bool) -> Int32 {
211 + let valString = TWStringCreateWithNSString(val)
212 + defer {
213 + TWStringDelete(valString)
214 + }
215 + return TWEthereumAbiFunctionAddParamString(rawValue, valString, isOutput)
216 + }
217 +
218 + /// Add an address type parameter
219 + ///
220 + /// - Parameter fn: A Non-null eth abi function
221 + /// - Parameter val: for output parameters, value has to be specified
222 + /// - Parameter isOutput: determines if the parameter is an input or output
223 + /// - Returns: the index of the parameter (0-based).
224 + @discardableResult
225 + public func addParamAddress(val: Data, isOutput: Bool) -> Int32 {
226 + let valData = TWDataCreateWithNSData(val)
227 + defer {
228 + TWDataDelete(valData)
229 + }
230 + return TWEthereumAbiFunctionAddParamAddress(rawValue, valData, isOutput)
231 + }
232 +
233 + /// Add a bytes type parameter
234 + ///
235 + /// - Parameter fn: A Non-null eth abi function
236 + /// - Parameter val: for output parameters, value has to be specified
237 + /// - Parameter isOutput: determines if the parameter is an input or output
238 + /// - Returns: the index of the parameter (0-based).
239 + @discardableResult
240 + public func addParamBytes(val: Data, isOutput: Bool) -> Int32 {
241 + let valData = TWDataCreateWithNSData(val)
242 + defer {
243 + TWDataDelete(valData)
244 + }
245 + return TWEthereumAbiFunctionAddParamBytes(rawValue, valData, isOutput)
246 + }
247 +
248 + /// Add a bytes[N] type parameter
249 + ///
250 + /// - Parameter fn: A Non-null eth abi function
251 + /// - Parameter size: fixed size of the bytes array parameter (val).
252 + /// - Parameter val: for output parameters, value has to be specified
253 + /// - Parameter isOutput: determines if the parameter is an input or output
254 + /// - Returns: the index of the parameter (0-based).
255 + @discardableResult
256 + public func addParamBytesFix(size: Int, val: Data, isOutput: Bool) -> Int32 {
257 + let valData = TWDataCreateWithNSData(val)
258 + defer {
259 + TWDataDelete(valData)
260 + }
261 + return TWEthereumAbiFunctionAddParamBytesFix(rawValue, size, valData, isOutput)
262 + }
263 +
264 + /// Add a type[] type parameter
265 + ///
266 + /// - Parameter fn: A Non-null eth abi function
267 + /// - Parameter val: for output parameters, value has to be specified
268 + /// - Parameter isOutput: determines if the parameter is an input or output
269 + /// - Returns: the index of the parameter (0-based).
270 + @discardableResult
271 + public func addParamArray(isOutput: Bool) -> Int32 {
272 + return TWEthereumAbiFunctionAddParamArray(rawValue, isOutput)
273 + }
274 +
275 + /// Methods for accessing the value of an output or input parameter, of different types.
276 + /// Get a uint8 type parameter at the given index
277 + ///
278 + /// - Parameter fn: A Non-null eth abi function
279 + /// - Parameter idx: index for the parameter (0-based).
280 + /// - Parameter isOutput: determines if the parameter is an input or output
281 + /// - Returns: the value of the parameter.
282 + public func getParamUInt8(idx: Int32, isOutput: Bool) -> UInt8 {
283 + return TWEthereumAbiFunctionGetParamUInt8(rawValue, Int32(idx), isOutput)
284 + }
285 +
286 + /// Get a uint64 type parameter at the given index
287 + ///
288 + /// - Parameter fn: A Non-null eth abi function
289 + /// - Parameter idx: index for the parameter (0-based).
290 + /// - Parameter isOutput: determines if the parameter is an input or output
291 + /// - Returns: the value of the parameter.
292 + public func getParamUInt64(idx: Int32, isOutput: Bool) -> UInt64 {
293 + return TWEthereumAbiFunctionGetParamUInt64(rawValue, Int32(idx), isOutput)
294 + }
295 +
296 + /// Get a uint256 type parameter at the given index
297 + ///
298 + /// - Parameter fn: A Non-null eth abi function
299 + /// - Parameter idx: index for the parameter (0-based).
300 + /// - Parameter isOutput: determines if the parameter is an input or output
301 + /// - Returns: the value of the parameter stored in a block of data.
302 + public func getParamUInt256(idx: Int32, isOutput: Bool) -> Data {
303 + return TWDataNSData(TWEthereumAbiFunctionGetParamUInt256(rawValue, Int32(idx), isOutput))
304 + }
305 +
306 + /// Get a bool type parameter at the given index
307 + ///
308 + /// - Parameter fn: A Non-null eth abi function
309 + /// - Parameter idx: index for the parameter (0-based).
310 + /// - Parameter isOutput: determines if the parameter is an input or output
311 + /// - Returns: the value of the parameter.
312 + public func getParamBool(idx: Int32, isOutput: Bool) -> Bool {
313 + return TWEthereumAbiFunctionGetParamBool(rawValue, Int32(idx), isOutput)
314 + }
315 +
316 + /// Get a string type parameter at the given index
317 + ///
318 + /// - Parameter fn: A Non-null eth abi function
319 + /// - Parameter idx: index for the parameter (0-based).
320 + /// - Parameter isOutput: determines if the parameter is an input or output
321 + /// - Returns: the value of the parameter.
322 + public func getParamString(idx: Int32, isOutput: Bool) -> String {
323 + return TWStringNSString(TWEthereumAbiFunctionGetParamString(rawValue, Int32(idx), isOutput))
324 + }
325 +
326 + /// Get an address type parameter at the given index
327 + ///
328 + /// - Parameter fn: A Non-null eth abi function
329 + /// - Parameter idx: index for the parameter (0-based).
330 + /// - Parameter isOutput: determines if the parameter is an input or output
331 + /// - Returns: the value of the parameter.
332 + public func getParamAddress(idx: Int32, isOutput: Bool) -> Data {
333 + return TWDataNSData(TWEthereumAbiFunctionGetParamAddress(rawValue, Int32(idx), isOutput))
334 + }
335 +
336 + /// Methods for adding a parameter of the given type to a top-level input parameter array. Returns the index of the parameter (0-based).
337 + /// Note that nested ParamArrays are not possible through this API, could be done by using index paths like "1/0"
338 + /// Adding a uint8 type parameter of to the top-level input parameter array
339 + ///
340 + /// - Parameter fn: A Non-null eth abi function
341 + /// - Parameter arrayIdx: array index for the abi function (0-based).
342 + /// - Parameter val: the value of the parameter
343 + /// - Returns: the index of the added parameter (0-based).
344 + @discardableResult
345 + public func addInArrayParamUInt8(arrayIdx: Int32, val: UInt8) -> Int32 {
346 + return TWEthereumAbiFunctionAddInArrayParamUInt8(rawValue, Int32(arrayIdx), val)
347 + }
348 +
349 + /// Adding a uint16 type parameter of to the top-level input parameter array
350 + ///
351 + /// - Parameter fn: A Non-null eth abi function
352 + /// - Parameter arrayIdx: array index for the abi function (0-based).
353 + /// - Parameter val: the value of the parameter
354 + /// - Returns: the index of the added parameter (0-based).
355 + @discardableResult
356 + public func addInArrayParamUInt16(arrayIdx: Int32, val: UInt16) -> Int32 {
357 + return TWEthereumAbiFunctionAddInArrayParamUInt16(rawValue, Int32(arrayIdx), val)
358 + }
359 +
360 + /// Adding a uint32 type parameter of to the top-level input parameter array
361 + ///
362 + /// - Parameter fn: A Non-null eth abi function
363 + /// - Parameter arrayIdx: array index for the abi function (0-based).
364 + /// - Parameter val: the value of the parameter
365 + /// - Returns: the index of the added parameter (0-based).
366 + @discardableResult
367 + public func addInArrayParamUInt32(arrayIdx: Int32, val: UInt32) -> Int32 {
368 + return TWEthereumAbiFunctionAddInArrayParamUInt32(rawValue, Int32(arrayIdx), val)
369 + }
370 +
371 + /// Adding a uint64 type parameter of to the top-level input parameter array
372 + ///
373 + /// - Parameter fn: A Non-null eth abi function
374 + /// - Parameter arrayIdx: array index for the abi function (0-based).
375 + /// - Parameter val: the value of the parameter
376 + /// - Returns: the index of the added parameter (0-based).
377 + @discardableResult
378 + public func addInArrayParamUInt64(arrayIdx: Int32, val: UInt64) -> Int32 {
379 + return TWEthereumAbiFunctionAddInArrayParamUInt64(rawValue, Int32(arrayIdx), val)
380 + }
381 +
382 + /// Adding a uint256 type parameter of to the top-level input parameter array
383 + ///
384 + /// - Parameter fn: A Non-null eth abi function
385 + /// - Parameter arrayIdx: array index for the abi function (0-based).
386 + /// - Parameter val: the value of the parameter stored in a block of data
387 + /// - Returns: the index of the added parameter (0-based).
388 + @discardableResult
389 + public func addInArrayParamUInt256(arrayIdx: Int32, val: Data) -> Int32 {
390 + let valData = TWDataCreateWithNSData(val)
391 + defer {
392 + TWDataDelete(valData)
393 + }
394 + return TWEthereumAbiFunctionAddInArrayParamUInt256(rawValue, Int32(arrayIdx), valData)
395 + }
396 +
397 + /// Adding a uint[N] type parameter of to the top-level input parameter array
398 + ///
399 + /// - Parameter fn: A Non-null eth abi function
400 + /// - Parameter bits: Number of bits of the integer parameter
401 + /// - Parameter arrayIdx: array index for the abi function (0-based).
402 + /// - Parameter val: the value of the parameter stored in a block of data
403 + /// - Returns: the index of the added parameter (0-based).
404 + @discardableResult
405 + public func addInArrayParamUIntN(arrayIdx: Int32, bits: Int32, val: Data) -> Int32 {
406 + let valData = TWDataCreateWithNSData(val)
407 + defer {
408 + TWDataDelete(valData)
409 + }
410 + return TWEthereumAbiFunctionAddInArrayParamUIntN(rawValue, Int32(arrayIdx), Int32(bits), valData)
411 + }
412 +
413 + /// Adding a int8 type parameter of to the top-level input parameter array
414 + ///
415 + /// - Parameter fn: A Non-null eth abi function
416 + /// - Parameter arrayIdx: array index for the abi function (0-based).
417 + /// - Parameter val: the value of the parameter
418 + /// - Returns: the index of the added parameter (0-based).
419 + @discardableResult
420 + public func addInArrayParamInt8(arrayIdx: Int32, val: Int8) -> Int32 {
421 + return TWEthereumAbiFunctionAddInArrayParamInt8(rawValue, Int32(arrayIdx), val)
422 + }
423 +
424 + /// Adding a int16 type parameter of to the top-level input parameter array
425 + ///
426 + /// - Parameter fn: A Non-null eth abi function
427 + /// - Parameter arrayIdx: array index for the abi function (0-based).
428 + /// - Parameter val: the value of the parameter
429 + /// - Returns: the index of the added parameter (0-based).
430 + @discardableResult
431 + public func addInArrayParamInt16(arrayIdx: Int32, val: Int16) -> Int32 {
432 + return TWEthereumAbiFunctionAddInArrayParamInt16(rawValue, Int32(arrayIdx), val)
433 + }
434 +
435 + /// Adding a int32 type parameter of to the top-level input parameter array
436 + ///
437 + /// - Parameter fn: A Non-null eth abi function
438 + /// - Parameter arrayIdx: array index for the abi function (0-based).
439 + /// - Parameter val: the value of the parameter
440 + /// - Returns: the index of the added parameter (0-based).
441 + @discardableResult
442 + public func addInArrayParamInt32(arrayIdx: Int32, val: Int32) -> Int32 {
443 + return TWEthereumAbiFunctionAddInArrayParamInt32(rawValue, Int32(arrayIdx), val)
444 + }
445 +
446 + /// Adding a int64 type parameter of to the top-level input parameter array
447 + ///
448 + /// - Parameter fn: A Non-null eth abi function
449 + /// - Parameter arrayIdx: array index for the abi function (0-based).
450 + /// - Parameter val: the value of the parameter
451 + /// - Returns: the index of the added parameter (0-based).
452 + @discardableResult
453 + public func addInArrayParamInt64(arrayIdx: Int32, val: Int64) -> Int32 {
454 + return TWEthereumAbiFunctionAddInArrayParamInt64(rawValue, Int32(arrayIdx), val)
455 + }
456 +
457 + /// Adding a int256 type parameter of to the top-level input parameter array
458 + ///
459 + /// - Parameter fn: A Non-null eth abi function
460 + /// - Parameter arrayIdx: array index for the abi function (0-based).
461 + /// - Parameter val: the value of the parameter stored in a block of data
462 + /// - Returns: the index of the added parameter (0-based).
463 + @discardableResult
464 + public func addInArrayParamInt256(arrayIdx: Int32, val: Data) -> Int32 {
465 + let valData = TWDataCreateWithNSData(val)
466 + defer {
467 + TWDataDelete(valData)
468 + }
469 + return TWEthereumAbiFunctionAddInArrayParamInt256(rawValue, Int32(arrayIdx), valData)
470 + }
471 +
472 + /// Adding a int[N] type parameter of to the top-level input parameter array
473 + ///
474 + /// - Parameter fn: A Non-null eth abi function
475 + /// - Parameter bits: Number of bits of the integer parameter
476 + /// - Parameter arrayIdx: array index for the abi function (0-based).
477 + /// - Parameter val: the value of the parameter stored in a block of data
478 + /// - Returns: the index of the added parameter (0-based).
479 + @discardableResult
480 + public func addInArrayParamIntN(arrayIdx: Int32, bits: Int32, val: Data) -> Int32 {
481 + let valData = TWDataCreateWithNSData(val)
482 + defer {
483 + TWDataDelete(valData)
484 + }
485 + return TWEthereumAbiFunctionAddInArrayParamIntN(rawValue, Int32(arrayIdx), Int32(bits), valData)
486 + }
487 +
488 + /// Adding a bool type parameter of to the top-level input parameter array
489 + ///
490 + /// - Parameter fn: A Non-null eth abi function
491 + /// - Parameter arrayIdx: array index for the abi function (0-based).
492 + /// - Parameter val: the value of the parameter
493 + /// - Returns: the index of the added parameter (0-based).
494 + @discardableResult
495 + public func addInArrayParamBool(arrayIdx: Int32, val: Bool) -> Int32 {
496 + return TWEthereumAbiFunctionAddInArrayParamBool(rawValue, Int32(arrayIdx), val)
497 + }
498 +
499 + /// Adding a string type parameter of to the top-level input parameter array
500 + ///
501 + /// - Parameter fn: A Non-null eth abi function
502 + /// - Parameter arrayIdx: array index for the abi function (0-based).
503 + /// - Parameter val: the value of the parameter
504 + /// - Returns: the index of the added parameter (0-based).
505 + @discardableResult
506 + public func addInArrayParamString(arrayIdx: Int32, val: String) -> Int32 {
507 + let valString = TWStringCreateWithNSString(val)
508 + defer {
509 + TWStringDelete(valString)
510 + }
511 + return TWEthereumAbiFunctionAddInArrayParamString(rawValue, Int32(arrayIdx), valString)
512 + }
513 +
514 + /// Adding an address type parameter of to the top-level input parameter array
515 + ///
516 + /// - Parameter fn: A Non-null eth abi function
517 + /// - Parameter arrayIdx: array index for the abi function (0-based).
518 + /// - Parameter val: the value of the parameter
519 + /// - Returns: the index of the added parameter (0-based).
520 + @discardableResult
521 + public func addInArrayParamAddress(arrayIdx: Int32, val: Data) -> Int32 {
522 + let valData = TWDataCreateWithNSData(val)
523 + defer {
524 + TWDataDelete(valData)
525 + }
526 + return TWEthereumAbiFunctionAddInArrayParamAddress(rawValue, Int32(arrayIdx), valData)
527 + }
528 +
529 + /// Adding a bytes type parameter of to the top-level input parameter array
530 + ///
531 + /// - Parameter fn: A Non-null eth abi function
532 + /// - Parameter arrayIdx: array index for the abi function (0-based).
533 + /// - Parameter val: the value of the parameter
534 + /// - Returns: the index of the added parameter (0-based).
535 + @discardableResult
536 + public func addInArrayParamBytes(arrayIdx: Int32, val: Data) -> Int32 {
537 + let valData = TWDataCreateWithNSData(val)
538 + defer {
539 + TWDataDelete(valData)
540 + }
541 + return TWEthereumAbiFunctionAddInArrayParamBytes(rawValue, Int32(arrayIdx), valData)
542 + }
543 +
544 + /// Adding a int64 type parameter of to the top-level input parameter array
545 + ///
546 + /// - Parameter fn: A Non-null eth abi function
547 + /// - Parameter arrayIdx: array index for the abi function (0-based).
548 + /// - Parameter size: fixed size of the bytes array parameter (val).
549 + /// - Parameter val: the value of the parameter
550 + /// - Returns: the index of the added parameter (0-based).
551 + @discardableResult
552 + public func addInArrayParamBytesFix(arrayIdx: Int32, size: Int, val: Data) -> Int32 {
553 + let valData = TWDataCreateWithNSData(val)
554 + defer {
555 + TWDataDelete(valData)
556 + }
557 + return TWEthereumAbiFunctionAddInArrayParamBytesFix(rawValue, Int32(arrayIdx), size, valData)
558 + }
559 +
560 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/EthereumAbiValue.swift +162 −0
@@ -0,0 +1,162 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents Ethereum ABI value
13 +public struct EthereumAbiValue {
14 +
15 + /// Encode a bool according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise
16 + ///
17 + /// - Parameter value: a boolean value
18 + /// - Returns: Encoded value stored in a block of data
19 + public static func encodeBool(value: Bool) -> Data {
20 + return TWDataNSData(TWEthereumAbiValueEncodeBool(value))
21 + }
22 +
23 + /// Encode a int32 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise
24 + ///
25 + /// - Parameter value: a int32 value
26 + /// - Returns: Encoded value stored in a block of data
27 + public static func encodeInt32(value: Int32) -> Data {
28 + return TWDataNSData(TWEthereumAbiValueEncodeInt32(value))
29 + }
30 +
31 + /// Encode a uint32 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise
32 + ///
33 + /// - Parameter value: a uint32 value
34 + /// - Returns: Encoded value stored in a block of data
35 + public static func encodeUInt32(value: UInt32) -> Data {
36 + return TWDataNSData(TWEthereumAbiValueEncodeUInt32(value))
37 + }
38 +
39 + /// Encode a int256 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise
40 + ///
41 + /// - Parameter value: a int256 value stored in a block of data
42 + /// - Returns: Encoded value stored in a block of data
43 + public static func encodeInt256(value: Data) -> Data {
44 + let valueData = TWDataCreateWithNSData(value)
45 + defer {
46 + TWDataDelete(valueData)
47 + }
48 + return TWDataNSData(TWEthereumAbiValueEncodeInt256(valueData))
49 + }
50 +
51 + /// Encode an int256 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise
52 + ///
53 + /// - Parameter value: a int256 value stored in a block of data
54 + /// - Returns: Encoded value stored in a block of data
55 + public static func encodeUInt256(value: Data) -> Data {
56 + let valueData = TWDataCreateWithNSData(value)
57 + defer {
58 + TWDataDelete(valueData)
59 + }
60 + return TWDataNSData(TWEthereumAbiValueEncodeUInt256(valueData))
61 + }
62 +
63 + /// Encode an address according to Ethereum ABI, 20 bytes of the address.
64 + ///
65 + /// - Parameter value: an address value stored in a block of data
66 + /// - Returns: Encoded value stored in a block of data
67 + public static func encodeAddress(value: Data) -> Data {
68 + let valueData = TWDataCreateWithNSData(value)
69 + defer {
70 + TWDataDelete(valueData)
71 + }
72 + return TWDataNSData(TWEthereumAbiValueEncodeAddress(valueData))
73 + }
74 +
75 + /// Encode a string according to Ethereum ABI by encoding its hash.
76 + ///
77 + /// - Parameter value: a string value
78 + /// - Returns: Encoded value stored in a block of data
79 + public static func encodeString(value: String) -> Data {
80 + let valueString = TWStringCreateWithNSString(value)
81 + defer {
82 + TWStringDelete(valueString)
83 + }
84 + return TWDataNSData(TWEthereumAbiValueEncodeString(valueString))
85 + }
86 +
87 + /// Encode a number of bytes, up to 32 bytes, padded on the right. Longer arrays are truncated.
88 + ///
89 + /// - Parameter value: bunch of bytes
90 + /// - Returns: Encoded value stored in a block of data
91 + public static func encodeBytes(value: Data) -> Data {
92 + let valueData = TWDataCreateWithNSData(value)
93 + defer {
94 + TWDataDelete(valueData)
95 + }
96 + return TWDataNSData(TWEthereumAbiValueEncodeBytes(valueData))
97 + }
98 +
99 + /// Encode a dynamic number of bytes by encoding its hash
100 + ///
101 + /// - Parameter value: bunch of bytes
102 + /// - Returns: Encoded value stored in a block of data
103 + public static func encodeBytesDyn(value: Data) -> Data {
104 + let valueData = TWDataCreateWithNSData(value)
105 + defer {
106 + TWDataDelete(valueData)
107 + }
108 + return TWDataNSData(TWEthereumAbiValueEncodeBytesDyn(valueData))
109 + }
110 +
111 + /// Decodes input data (bytes longer than 32 will be truncated) as uint256
112 + ///
113 + /// - Parameter input: Data to be decoded
114 + /// - Returns: Non-null decoded string value
115 + public static func decodeUInt256(input: Data) -> String {
116 + let inputData = TWDataCreateWithNSData(input)
117 + defer {
118 + TWDataDelete(inputData)
119 + }
120 + return TWStringNSString(TWEthereumAbiValueDecodeUInt256(inputData))
121 + }
122 +
123 + /// Decode an arbitrary type, return value as string
124 + ///
125 + /// - Parameter input: Data to be decoded
126 + /// - Parameter type: the underlying type that need to be decoded
127 + /// - Returns: Non-null decoded string value
128 + public static func decodeValue(input: Data, type: String) -> String {
129 + let inputData = TWDataCreateWithNSData(input)
130 + defer {
131 + TWDataDelete(inputData)
132 + }
133 + let typeString = TWStringCreateWithNSString(type)
134 + defer {
135 + TWStringDelete(typeString)
136 + }
137 + return TWStringNSString(TWEthereumAbiValueDecodeValue(inputData, typeString))
138 + }
139 +
140 + /// Decode an array of given simple types. Return a '\n'-separated string of elements
141 + ///
142 + /// - Parameter input: Data to be decoded
143 + /// - Parameter type: the underlying type that need to be decoded
144 + /// - Returns: Non-null decoded string value
145 + public static func decodeArray(input: Data, type: String) -> String {
146 + let inputData = TWDataCreateWithNSData(input)
147 + defer {
148 + TWDataDelete(inputData)
149 + }
150 + let typeString = TWStringCreateWithNSString(type)
151 + defer {
152 + TWStringDelete(typeString)
153 + }
154 + return TWStringNSString(TWEthereumAbiValueDecodeArray(inputData, typeString))
155 + }
156 +
157 +
158 + init() {
159 + }
160 +
161 +
162 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/EthereumMessageSigner.swift +108 −0
@@ -0,0 +1,108 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Ethereum message signing and verification.
13 +///
14 +/// Ethereum and some other wallets support a message signing & verification format, to create a proof (a signature)
15 +/// that someone has access to the private keys of a specific address.
16 +public struct EthereumMessageSigner {
17 +
18 + /// Sign a typed message EIP-712 V4.
19 + ///
20 + /// - Parameter privateKey:: the private key used for signing
21 + /// - Parameter messageJson:: A custom typed data message in json
22 + /// - Returns:s the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use.
23 + public static func signTypedMessage(privateKey: PrivateKey, messageJson: String) -> String {
24 + let messageJsonString = TWStringCreateWithNSString(messageJson)
25 + defer {
26 + TWStringDelete(messageJsonString)
27 + }
28 + return TWStringNSString(TWEthereumMessageSignerSignTypedMessage(privateKey.rawValue, messageJsonString))
29 + }
30 +
31 + /// Sign a typed message EIP-712 V4 with EIP-155 replay attack protection.
32 + ///
33 + /// - Parameter privateKey:: the private key used for signing
34 + /// - Parameter messageJson:: A custom typed data message in json
35 + /// - Parameter chainId:: chainId for eip-155 protection
36 + /// - Returns:s the signature, Hex-encoded. On invalid input empty string is returned or invalid chainId error message. Returned object needs to be deleted after use.
37 + public static func signTypedMessageEip155(privateKey: PrivateKey, messageJson: String, chainId: Int32) -> String {
38 + let messageJsonString = TWStringCreateWithNSString(messageJson)
39 + defer {
40 + TWStringDelete(messageJsonString)
41 + }
42 + return TWStringNSString(TWEthereumMessageSignerSignTypedMessageEip155(privateKey.rawValue, messageJsonString, Int32(chainId)))
43 + }
44 +
45 + /// Sign a message.
46 + ///
47 + /// - Parameter privateKey:: the private key used for signing
48 + /// - Parameter message:: A custom message which is input to the signing.
49 + /// - Returns:s the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use.
50 + public static func signMessage(privateKey: PrivateKey, message: String) -> String {
51 + let messageString = TWStringCreateWithNSString(message)
52 + defer {
53 + TWStringDelete(messageString)
54 + }
55 + return TWStringNSString(TWEthereumMessageSignerSignMessage(privateKey.rawValue, messageString))
56 + }
57 +
58 + /// Sign a message with Immutable X msg type.
59 + ///
60 + /// - Parameter privateKey:: the private key used for signing
61 + /// - Parameter message:: A custom message which is input to the signing.
62 + /// - Returns:s the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use.
63 + public static func signMessageImmutableX(privateKey: PrivateKey, message: String) -> String {
64 + let messageString = TWStringCreateWithNSString(message)
65 + defer {
66 + TWStringDelete(messageString)
67 + }
68 + return TWStringNSString(TWEthereumMessageSignerSignMessageImmutableX(privateKey.rawValue, messageString))
69 + }
70 +
71 + /// Sign a message with Eip-155 msg type.
72 + ///
73 + /// - Parameter privateKey:: the private key used for signing
74 + /// - Parameter message:: A custom message which is input to the signing.
75 + /// - Parameter chainId:: chainId for eip-155 protection
76 + /// - Returns:s the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use.
77 + public static func signMessageEip155(privateKey: PrivateKey, message: String, chainId: Int32) -> String {
78 + let messageString = TWStringCreateWithNSString(message)
79 + defer {
80 + TWStringDelete(messageString)
81 + }
82 + return TWStringNSString(TWEthereumMessageSignerSignMessageEip155(privateKey.rawValue, messageString, Int32(chainId)))
83 + }
84 +
85 + /// Verify signature for a message.
86 + ///
87 + /// - Parameter pubKey:: pubKey that will verify and recover the message from the signature
88 + /// - Parameter message:: the message signed (without prefix)
89 + /// - Parameter signature:: in Hex-encoded form.
90 + /// - Returns:s false on any invalid input (does not throw), true if the message can be recovered from the signature
91 + public static func verifyMessage(pubKey: PublicKey, message: String, signature: String) -> Bool {
92 + let messageString = TWStringCreateWithNSString(message)
93 + defer {
94 + TWStringDelete(messageString)
95 + }
96 + let signatureString = TWStringCreateWithNSString(signature)
97 + defer {
98 + TWStringDelete(signatureString)
99 + }
100 + return TWEthereumMessageSignerVerifyMessage(pubKey.rawValue, messageString, signatureString)
101 + }
102 +
103 +
104 + init() {
105 + }
106 +
107 +
108 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/EthereumRlp.swift +33 −0
@@ -0,0 +1,33 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public struct EthereumRlp {
14 +
15 + /// Encode an item or a list of items as Eth RLP binary format.
16 + ///
17 + /// - Parameter coin: EVM-compatible coin type.
18 + /// - Parameter input: Non-null serialized `EthereumRlp::Proto::EncodingInput`.
19 + /// - Returns: serialized `EthereumRlp::Proto::EncodingOutput`.
20 + public static func encode(coin: CoinType, input: Data) -> Data {
21 + let inputData = TWDataCreateWithNSData(input)
22 + defer {
23 + TWDataDelete(inputData)
24 + }
25 + return TWDataNSData(TWEthereumRlpEncode(TWCoinType(rawValue: coin.rawValue), inputData))
26 + }
27 +
28 +
29 + init() {
30 + }
31 +
32 +
33 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/FIOAccount.swift +44 −0
@@ -0,0 +1,44 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a FIO Account name
13 +public final class FIOAccount {
14 +
15 + /// Returns the short account string representation.
16 + ///
17 + /// - Parameter account: Pointer to a non-null FIO Account
18 + /// - Returns: Account non-null string representation
19 + public var description: String {
20 + return TWStringNSString(TWFIOAccountDescription(rawValue))
21 + }
22 +
23 + let rawValue: OpaquePointer
24 +
25 + init(rawValue: OpaquePointer) {
26 + self.rawValue = rawValue
27 + }
28 +
29 + public init?(string: String) {
30 + let stringString = TWStringCreateWithNSString(string)
31 + defer {
32 + TWStringDelete(stringString)
33 + }
34 + guard let rawValue = TWFIOAccountCreateWithString(stringString) else {
35 + return nil
36 + }
37 + self.rawValue = rawValue
38 + }
39 +
40 + deinit {
41 + TWFIOAccountDelete(rawValue)
42 + }
43 +
44 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/FilecoinAddressConverter.swift +44 −0
@@ -0,0 +1,44 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Filecoin-Ethereum address converter.
13 +public struct FilecoinAddressConverter {
14 +
15 + /// Converts a Filecoin address to Ethereum.
16 + ///
17 + /// - Parameter filecoinAddress:: a Filecoin address.
18 + /// - Returns:s the Ethereum address. On invalid input empty string is returned. Returned object needs to be deleted after use.
19 + public static func convertToEthereum(filecoinAddress: String) -> String {
20 + let filecoinAddressString = TWStringCreateWithNSString(filecoinAddress)
21 + defer {
22 + TWStringDelete(filecoinAddressString)
23 + }
24 + return TWStringNSString(TWFilecoinAddressConverterConvertToEthereum(filecoinAddressString))
25 + }
26 +
27 + /// Converts an Ethereum address to Filecoin.
28 + ///
29 + /// - Parameter ethAddress:: an Ethereum address.
30 + /// - Returns:s the Filecoin address. On invalid input empty string is returned. Returned object needs to be deleted after use.
31 + public static func convertFromEthereum(ethAddress: String) -> String {
32 + let ethAddressString = TWStringCreateWithNSString(ethAddress)
33 + defer {
34 + TWStringDelete(ethAddressString)
35 + }
36 + return TWStringNSString(TWFilecoinAddressConverterConvertFromEthereum(ethAddressString))
37 + }
38 +
39 +
40 + init() {
41 + }
42 +
43 +
44 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/GroestlcoinAddress.swift +69 −0
@@ -0,0 +1,69 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a legacy Groestlcoin address.
13 +public final class GroestlcoinAddress: Address {
14 +
15 + /// Compares two addresses for equality.
16 + ///
17 + /// - Parameter lhs: left Non-null GroestlCoin address to be compared
18 + /// - Parameter rhs: right Non-null GroestlCoin address to be compared
19 + /// - Returns: true if both address are equal, false otherwise
20 + public static func == (lhs: GroestlcoinAddress, rhs: GroestlcoinAddress) -> Bool {
21 + return TWGroestlcoinAddressEqual(lhs.rawValue, rhs.rawValue)
22 + }
23 +
24 + /// Determines if the string is a valid Groestlcoin address.
25 + ///
26 + /// - Parameter string: Non-null string.
27 + /// - Returns: true if it's a valid address, false otherwise
28 + public static func isValidString(string: String) -> Bool {
29 + let stringString = TWStringCreateWithNSString(string)
30 + defer {
31 + TWStringDelete(stringString)
32 + }
33 + return TWGroestlcoinAddressIsValidString(stringString)
34 + }
35 +
36 + /// Returns the address base58 string representation.
37 + ///
38 + /// - Parameter address: Non-null GroestlcoinAddress
39 + /// - Returns: Address description as a non-null string
40 + public var description: String {
41 + return TWStringNSString(TWGroestlcoinAddressDescription(rawValue))
42 + }
43 +
44 + let rawValue: OpaquePointer
45 +
46 + init(rawValue: OpaquePointer) {
47 + self.rawValue = rawValue
48 + }
49 +
50 + public init?(string: String) {
51 + let stringString = TWStringCreateWithNSString(string)
52 + defer {
53 + TWStringDelete(stringString)
54 + }
55 + guard let rawValue = TWGroestlcoinAddressCreateWithString(stringString) else {
56 + return nil
57 + }
58 + self.rawValue = rawValue
59 + }
60 +
61 + public init(publicKey: PublicKey, prefix: UInt8) {
62 + rawValue = TWGroestlcoinAddressCreateWithPublicKey(publicKey.rawValue, prefix)
63 + }
64 +
65 + deinit {
66 + TWGroestlcoinAddressDelete(rawValue)
67 + }
68 +
69 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/HDVersion+Extension.swift +25 −0
@@ -0,0 +1,25 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +extension HDVersion {
11 + /// Determine if the HD Version is public
12 + ///
13 + /// - Parameter version: HD version
14 + /// - Returns: true if the version is public, false otherwise
15 + public var isPublic: Bool {
16 + return TWHDVersionIsPublic(TWHDVersion(rawValue: rawValue))
17 + }
18 + /// Determine if the HD Version is private
19 + ///
20 + /// - Parameter version: HD version
21 + /// - Returns: true if the version is private, false otherwise
22 + public var isPrivate: Bool {
23 + return TWHDVersionIsPrivate(TWHDVersion(rawValue: rawValue))
24 + }
25 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/HDWallet.swift +314 −0
@@ -0,0 +1,314 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Hierarchical Deterministic (HD) Wallet
13 +public final class HDWallet {
14 +
15 + /// Computes the public key from an extended public key representation.
16 + ///
17 + /// - Parameter extended: extended public key
18 + /// - Parameter coin: a coin type
19 + /// - Parameter derivationPath: a derivation path
20 + /// - Note: Returned object needs to be deleted with \TWPublicKeyDelete
21 + /// - Returns: Nullable TWPublic key
22 + public static func getPublicKeyFromExtended(extended: String, coin: CoinType, derivationPath: String) -> PublicKey? {
23 + let extendedString = TWStringCreateWithNSString(extended)
24 + defer {
25 + TWStringDelete(extendedString)
26 + }
27 + let derivationPathString = TWStringCreateWithNSString(derivationPath)
28 + defer {
29 + TWStringDelete(derivationPathString)
30 + }
31 + guard let value = TWHDWalletGetPublicKeyFromExtended(extendedString, TWCoinType(rawValue: coin.rawValue), derivationPathString) else {
32 + return nil
33 + }
34 + return PublicKey(rawValue: value)
35 + }
36 +
37 + /// Wallet seed.
38 + ///
39 + /// - Parameter wallet: non-null TWHDWallet
40 + /// - Returns: The wallet seed as a Non-null block of data.
41 + public var seed: Data {
42 + return TWDataNSData(TWHDWalletSeed(rawValue))
43 + }
44 +
45 + /// Wallet Mnemonic
46 + ///
47 + /// - Parameter wallet: non-null TWHDWallet
48 + /// - Returns: The wallet mnemonic as a non-null TWString
49 + public var mnemonic: String {
50 + return TWStringNSString(TWHDWalletMnemonic(rawValue))
51 + }
52 +
53 + /// Wallet entropy
54 + ///
55 + /// - Parameter wallet: non-null TWHDWallet
56 + /// - Returns: The wallet entropy as a non-null block of data.
57 + public var entropy: Data {
58 + return TWDataNSData(TWHDWalletEntropy(rawValue))
59 + }
60 +
61 + let rawValue: OpaquePointer
62 +
63 + init(rawValue: OpaquePointer) {
64 + self.rawValue = rawValue
65 + }
66 +
67 + public init?(strength: Int32, passphrase: String) {
68 + let passphraseString = TWStringCreateWithNSString(passphrase)
69 + defer {
70 + TWStringDelete(passphraseString)
71 + }
72 + guard let rawValue = TWHDWalletCreate(Int32(strength), passphraseString) else {
73 + return nil
74 + }
75 + self.rawValue = rawValue
76 + }
77 +
78 + public init?(mnemonic: String, passphrase: String) {
79 + let mnemonicString = TWStringCreateWithNSString(mnemonic)
80 + defer {
81 + TWStringDelete(mnemonicString)
82 + }
83 + let passphraseString = TWStringCreateWithNSString(passphrase)
84 + defer {
85 + TWStringDelete(passphraseString)
86 + }
87 + guard let rawValue = TWHDWalletCreateWithMnemonic(mnemonicString, passphraseString) else {
88 + return nil
89 + }
90 + self.rawValue = rawValue
91 + }
92 +
93 + public init?(mnemonic: String, passphrase: String, check: Bool) {
94 + let mnemonicString = TWStringCreateWithNSString(mnemonic)
95 + defer {
96 + TWStringDelete(mnemonicString)
97 + }
98 + let passphraseString = TWStringCreateWithNSString(passphrase)
99 + defer {
100 + TWStringDelete(passphraseString)
101 + }
102 + guard let rawValue = TWHDWalletCreateWithMnemonicCheck(mnemonicString, passphraseString, check) else {
103 + return nil
104 + }
105 + self.rawValue = rawValue
106 + }
107 +
108 + public init?(entropy: Data, passphrase: String) {
109 + let entropyData = TWDataCreateWithNSData(entropy)
110 + defer {
111 + TWDataDelete(entropyData)
112 + }
113 + let passphraseString = TWStringCreateWithNSString(passphrase)
114 + defer {
115 + TWStringDelete(passphraseString)
116 + }
117 + guard let rawValue = TWHDWalletCreateWithEntropy(entropyData, passphraseString) else {
118 + return nil
119 + }
120 + self.rawValue = rawValue
121 + }
122 +
123 + deinit {
124 + TWHDWalletDelete(rawValue)
125 + }
126 +
127 + /// Returns master key.
128 + ///
129 + /// - Parameter wallet: non-null TWHDWallet
130 + /// - Parameter curve: a curve
131 + /// - Note: Returned object needs to be deleted with \TWPrivateKeyDelete
132 + /// - Returns: Non-null corresponding private key
133 + public func getMasterKey(curve: Curve) -> PrivateKey {
134 + return PrivateKey(rawValue: TWHDWalletGetMasterKey(rawValue, TWCurve(rawValue: curve.rawValue)))
135 + }
136 +
137 + /// Generates the default private key for the specified coin, using default derivation.
138 + ///
139 + /// - SeeAlso: TWHDWalletGetKey
140 + /// - SeeAlso: TWHDWalletGetKeyDerivation
141 + /// - Parameter wallet: non-null TWHDWallet
142 + /// - Parameter coin: a coin type
143 + /// - Note: Returned object needs to be deleted with \TWPrivateKeyDelete
144 + /// - Returns: return the default private key for the specified coin
145 + public func getKeyForCoin(coin: CoinType) -> PrivateKey {
146 + return PrivateKey(rawValue: TWHDWalletGetKeyForCoin(rawValue, TWCoinType(rawValue: coin.rawValue)))
147 + }
148 +
149 + /// Generates the default address for the specified coin (without exposing intermediary private key), default derivation.
150 + ///
151 + /// - SeeAlso: TWHDWalletGetAddressDerivation
152 + /// - Parameter wallet: non-null TWHDWallet
153 + /// - Parameter coin: a coin type
154 + /// - Returns: return the default address for the specified coin as a non-null TWString
155 + public func getAddressForCoin(coin: CoinType) -> String {
156 + return TWStringNSString(TWHDWalletGetAddressForCoin(rawValue, TWCoinType(rawValue: coin.rawValue)))
157 + }
158 +
159 + /// Generates the default address for the specified coin and derivation (without exposing intermediary private key).
160 + ///
161 + /// - SeeAlso: TWHDWalletGetAddressForCoin
162 + /// - Parameter wallet: non-null TWHDWallet
163 + /// - Parameter coin: a coin type
164 + /// - Parameter derivation: a (custom) derivation to use
165 + /// - Returns: return the default address for the specified coin as a non-null TWString
166 + public func getAddressDerivation(coin: CoinType, derivation: Derivation) -> String {
167 + return TWStringNSString(TWHDWalletGetAddressDerivation(rawValue, TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue)))
168 + }
169 +
170 + /// Generates the private key for the specified derivation path.
171 + ///
172 + /// - SeeAlso: TWHDWalletGetKeyForCoin
173 + /// - SeeAlso: TWHDWalletGetKeyDerivation
174 + /// - Parameter wallet: non-null TWHDWallet
175 + /// - Parameter coin: a coin type
176 + /// - Parameter derivationPath: a non-null derivation path
177 + /// - Note: Returned object needs to be deleted with \TWPrivateKeyDelete
178 + /// - Returns: The private key for the specified derivation path/coin, or null if the path is invalid
179 + public func getKey(coin: CoinType, derivationPath: String) -> PrivateKey? {
180 + let derivationPathString = TWStringCreateWithNSString(derivationPath)
181 + defer {
182 + TWStringDelete(derivationPathString)
183 + }
184 + guard let value = TWHDWalletGetKey(rawValue, TWCoinType(rawValue: coin.rawValue), derivationPathString) else {
185 + return nil
186 + }
187 + return PrivateKey(rawValue: value)
188 + }
189 +
190 + /// Generates the private key for the specified derivation.
191 + ///
192 + /// - SeeAlso: TWHDWalletGetKey
193 + /// - SeeAlso: TWHDWalletGetKeyForCoin
194 + /// - Parameter wallet: non-null TWHDWallet
195 + /// - Parameter coin: a coin type
196 + /// - Parameter derivation: a (custom) derivation to use
197 + /// - Note: Returned object needs to be deleted with \TWPrivateKeyDelete
198 + /// - Returns: The private key for the specified derivation path/coin
199 + public func getKeyDerivation(coin: CoinType, derivation: Derivation) -> PrivateKey {
200 + return PrivateKey(rawValue: TWHDWalletGetKeyDerivation(rawValue, TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue)))
201 + }
202 +
203 + /// Generates the private key for the specified derivation path and curve.
204 + ///
205 + /// - Parameter wallet: non-null TWHDWallet
206 + /// - Parameter curve: a curve
207 + /// - Parameter derivationPath: a non-null derivation path
208 + /// - Note: Returned object needs to be deleted with \TWPrivateKeyDelete
209 + /// - Returns: The private key for the specified derivation path/curve, or null if the path is invalid
210 + public func getKeyByCurve(curve: Curve, derivationPath: String) -> PrivateKey? {
211 + let derivationPathString = TWStringCreateWithNSString(derivationPath)
212 + defer {
213 + TWStringDelete(derivationPathString)
214 + }
215 + guard let value = TWHDWalletGetKeyByCurve(rawValue, TWCurve(rawValue: curve.rawValue), derivationPathString) else {
216 + return nil
217 + }
218 + return PrivateKey(rawValue: value)
219 + }
220 +
221 + /// Shortcut method to generate private key with the specified account/change/address (bip44 standard).
222 + ///
223 + /// - SeeAlso: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
224 + ///
225 + /// - Parameter wallet: non-null TWHDWallet
226 + /// - Parameter coin: a coin type
227 + /// - Parameter account: valid bip44 account
228 + /// - Parameter change: valid bip44 change
229 + /// - Parameter address: valid bip44 address
230 + /// - Note: Returned object needs to be deleted with \TWPrivateKeyDelete
231 + /// - Returns: The private key for the specified bip44 parameters
232 + public func getDerivedKey(coin: CoinType, account: UInt32, change: UInt32, address: UInt32) -> PrivateKey {
233 + return PrivateKey(rawValue: TWHDWalletGetDerivedKey(rawValue, TWCoinType(rawValue: coin.rawValue), account, change, address))
234 + }
235 +
236 + /// Returns the extended private key (for default 0 account).
237 + ///
238 + /// - Parameter wallet: non-null TWHDWallet
239 + /// - Parameter purpose: a purpose
240 + /// - Parameter coin: a coin type
241 + /// - Parameter version: hd version
242 + /// - Note: Returned object needs to be deleted with \TWStringDelete
243 + /// - Returns: Extended private key as a non-null TWString
244 + public func getExtendedPrivateKey(purpose: Purpose, coin: CoinType, version: HDVersion) -> String {
245 + return TWStringNSString(TWHDWalletGetExtendedPrivateKey(rawValue, TWPurpose(rawValue: purpose.rawValue), TWCoinType(rawValue: coin.rawValue), TWHDVersion(rawValue: version.rawValue)))
246 + }
247 +
248 + /// Returns the extended public key (for default 0 account).
249 + ///
250 + /// - Parameter wallet: non-null TWHDWallet
251 + /// - Parameter purpose: a purpose
252 + /// - Parameter coin: a coin type
253 + /// - Parameter version: hd version
254 + /// - Note: Returned object needs to be deleted with \TWStringDelete
255 + /// - Returns: Extended public key as a non-null TWString
256 + public func getExtendedPublicKey(purpose: Purpose, coin: CoinType, version: HDVersion) -> String {
257 + return TWStringNSString(TWHDWalletGetExtendedPublicKey(rawValue, TWPurpose(rawValue: purpose.rawValue), TWCoinType(rawValue: coin.rawValue), TWHDVersion(rawValue: version.rawValue)))
258 + }
259 +
260 + /// Returns the extended private key, for custom account.
261 + ///
262 + /// - Parameter wallet: non-null TWHDWallet
263 + /// - Parameter purpose: a purpose
264 + /// - Parameter coin: a coin type
265 + /// - Parameter derivation: a derivation
266 + /// - Parameter version: an hd version
267 + /// - Parameter account: valid bip44 account
268 + /// - Note: Returned object needs to be deleted with \TWStringDelete
269 + /// - Returns: Extended private key as a non-null TWString
270 + public func getExtendedPrivateKeyAccount(purpose: Purpose, coin: CoinType, derivation: Derivation, version: HDVersion, account: UInt32) -> String {
271 + return TWStringNSString(TWHDWalletGetExtendedPrivateKeyAccount(rawValue, TWPurpose(rawValue: purpose.rawValue), TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue), TWHDVersion(rawValue: version.rawValue), account))
272 + }
273 +
274 + /// Returns the extended public key, for custom account.
275 + ///
276 + /// - Parameter wallet: non-null TWHDWallet
277 + /// - Parameter purpose: a purpose
278 + /// - Parameter coin: a coin type
279 + /// - Parameter derivation: a derivation
280 + /// - Parameter version: an hd version
281 + /// - Parameter account: valid bip44 account
282 + /// - Note: Returned object needs to be deleted with \TWStringDelete
283 + /// - Returns: Extended public key as a non-null TWString
284 + public func getExtendedPublicKeyAccount(purpose: Purpose, coin: CoinType, derivation: Derivation, version: HDVersion, account: UInt32) -> String {
285 + return TWStringNSString(TWHDWalletGetExtendedPublicKeyAccount(rawValue, TWPurpose(rawValue: purpose.rawValue), TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue), TWHDVersion(rawValue: version.rawValue), account))
286 + }
287 +
288 + /// Returns the extended private key (for default 0 account with derivation).
289 + ///
290 + /// - Parameter wallet: non-null TWHDWallet
291 + /// - Parameter purpose: a purpose
292 + /// - Parameter coin: a coin type
293 + /// - Parameter derivation: a derivation
294 + /// - Parameter version: an hd version
295 + /// - Note: Returned object needs to be deleted with \TWStringDelete
296 + /// - Returns: Extended private key as a non-null TWString
297 + public func getExtendedPrivateKeyDerivation(purpose: Purpose, coin: CoinType, derivation: Derivation, version: HDVersion) -> String {
298 + return TWStringNSString(TWHDWalletGetExtendedPrivateKeyDerivation(rawValue, TWPurpose(rawValue: purpose.rawValue), TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue), TWHDVersion(rawValue: version.rawValue)))
299 + }
300 +
301 + /// Returns the extended public key (for default 0 account with derivation).
302 + ///
303 + /// - Parameter wallet: non-null TWHDWallet
304 + /// - Parameter purpose: a purpose
305 + /// - Parameter coin: a coin type
306 + /// - Parameter derivation: a derivation
307 + /// - Parameter version: an hd version
308 + /// - Note: Returned object needs to be deleted with \TWStringDelete
309 + /// - Returns: Extended public key as a non-null TWString
310 + public func getExtendedPublicKeyDerivation(purpose: Purpose, coin: CoinType, derivation: Derivation, version: HDVersion) -> String {
311 + return TWStringNSString(TWHDWalletGetExtendedPublicKeyDerivation(rawValue, TWPurpose(rawValue: purpose.rawValue), TWCoinType(rawValue: coin.rawValue), TWDerivation(rawValue: derivation.rawValue), TWHDVersion(rawValue: version.rawValue)))
312 + }
313 +
314 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Hash.swift +249 −0
@@ -0,0 +1,249 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Hash functions
13 +public struct Hash {
14 +
15 + /// Computes the SHA1 of a block of data.
16 + ///
17 + /// - Parameter data: Non-null block of data
18 + /// - Returns: Non-null computed SHA1 block of data
19 + public static func sha1(data: Data) -> Data {
20 + let dataData = TWDataCreateWithNSData(data)
21 + defer {
22 + TWDataDelete(dataData)
23 + }
24 + return TWDataNSData(TWHashSHA1(dataData))
25 + }
26 +
27 + /// Computes the SHA256 of a block of data.
28 + ///
29 + /// - Parameter data: Non-null block of data
30 + /// - Returns: Non-null computed SHA256 block of data
31 + public static func sha256(data: Data) -> Data {
32 + let dataData = TWDataCreateWithNSData(data)
33 + defer {
34 + TWDataDelete(dataData)
35 + }
36 + return TWDataNSData(TWHashSHA256(dataData))
37 + }
38 +
39 + /// Computes the SHA512 of a block of data.
40 + ///
41 + /// - Parameter data: Non-null block of data
42 + /// - Returns: Non-null computed SHA512 block of data
43 + public static func sha512(data: Data) -> Data {
44 + let dataData = TWDataCreateWithNSData(data)
45 + defer {
46 + TWDataDelete(dataData)
47 + }
48 + return TWDataNSData(TWHashSHA512(dataData))
49 + }
50 +
51 + /// Computes the SHA512_256 of a block of data.
52 + ///
53 + /// - Parameter data: Non-null block of data
54 + /// - Returns: Non-null computed SHA512_256 block of data
55 + public static func sha512_256(data: Data) -> Data {
56 + let dataData = TWDataCreateWithNSData(data)
57 + defer {
58 + TWDataDelete(dataData)
59 + }
60 + return TWDataNSData(TWHashSHA512_256(dataData))
61 + }
62 +
63 + /// Computes the Keccak256 of a block of data.
64 + ///
65 + /// - Parameter data: Non-null block of data
66 + /// - Returns: Non-null computed Keccak256 block of data
67 + public static func keccak256(data: Data) -> Data {
68 + let dataData = TWDataCreateWithNSData(data)
69 + defer {
70 + TWDataDelete(dataData)
71 + }
72 + return TWDataNSData(TWHashKeccak256(dataData))
73 + }
74 +
75 + /// Computes the Keccak512 of a block of data.
76 + ///
77 + /// - Parameter data: Non-null block of data
78 + /// - Returns: Non-null computed Keccak512 block of data
79 + public static func keccak512(data: Data) -> Data {
80 + let dataData = TWDataCreateWithNSData(data)
81 + defer {
82 + TWDataDelete(dataData)
83 + }
84 + return TWDataNSData(TWHashKeccak512(dataData))
85 + }
86 +
87 + /// Computes the SHA3_256 of a block of data.
88 + ///
89 + /// - Parameter data: Non-null block of data
90 + /// - Returns: Non-null computed SHA3_256 block of data
91 + public static func sha3_256(data: Data) -> Data {
92 + let dataData = TWDataCreateWithNSData(data)
93 + defer {
94 + TWDataDelete(dataData)
95 + }
96 + return TWDataNSData(TWHashSHA3_256(dataData))
97 + }
98 +
99 + /// Computes the SHA3_512 of a block of data.
100 + ///
101 + /// - Parameter data: Non-null block of data
102 + /// - Returns: Non-null computed SHA3_512 block of data
103 + public static func sha3_512(data: Data) -> Data {
104 + let dataData = TWDataCreateWithNSData(data)
105 + defer {
106 + TWDataDelete(dataData)
107 + }
108 + return TWDataNSData(TWHashSHA3_512(dataData))
109 + }
110 +
111 + /// Computes the RIPEMD of a block of data.
112 + ///
113 + /// - Parameter data: Non-null block of data
114 + /// - Returns: Non-null computed RIPEMD block of data
115 + public static func ripemd(data: Data) -> Data {
116 + let dataData = TWDataCreateWithNSData(data)
117 + defer {
118 + TWDataDelete(dataData)
119 + }
120 + return TWDataNSData(TWHashRIPEMD(dataData))
121 + }
122 +
123 + /// Computes the Blake256 of a block of data.
124 + ///
125 + /// - Parameter data: Non-null block of data
126 + /// - Returns: Non-null computed Blake256 block of data
127 + public static func blake256(data: Data) -> Data {
128 + let dataData = TWDataCreateWithNSData(data)
129 + defer {
130 + TWDataDelete(dataData)
131 + }
132 + return TWDataNSData(TWHashBlake256(dataData))
133 + }
134 +
135 + /// Computes the Blake2b of a block of data.
136 + ///
137 + /// - Parameter data: Non-null block of data
138 + /// - Returns: Non-null computed Blake2b block of data
139 + public static func blake2b(data: Data, size: Int) -> Data {
140 + let dataData = TWDataCreateWithNSData(data)
141 + defer {
142 + TWDataDelete(dataData)
143 + }
144 + return TWDataNSData(TWHashBlake2b(dataData, size))
145 + }
146 +
147 + /// Computes the Groestl512 of a block of data.
148 + ///
149 + /// - Parameter data: Non-null block of data
150 + /// - Returns: Non-null computed Groestl512 block of data
151 + public static func blake2bPersonal(data: Data, personal: Data, outlen: Int) -> Data {
152 + let dataData = TWDataCreateWithNSData(data)
153 + defer {
154 + TWDataDelete(dataData)
155 + }
156 + let personalData = TWDataCreateWithNSData(personal)
157 + defer {
158 + TWDataDelete(personalData)
159 + }
160 + return TWDataNSData(TWHashBlake2bPersonal(dataData, personalData, outlen))
161 + }
162 +
163 +
164 + public static func groestl512(data: Data) -> Data {
165 + let dataData = TWDataCreateWithNSData(data)
166 + defer {
167 + TWDataDelete(dataData)
168 + }
169 + return TWDataNSData(TWHashGroestl512(dataData))
170 + }
171 +
172 + /// Computes the SHA256D of a block of data.
173 + ///
174 + /// - Parameter data: Non-null block of data
175 + /// - Returns: Non-null computed SHA256D block of data
176 + public static func sha256SHA256(data: Data) -> Data {
177 + let dataData = TWDataCreateWithNSData(data)
178 + defer {
179 + TWDataDelete(dataData)
180 + }
181 + return TWDataNSData(TWHashSHA256SHA256(dataData))
182 + }
183 +
184 + /// Computes the SHA256RIPEMD of a block of data.
185 + ///
186 + /// - Parameter data: Non-null block of data
187 + /// - Returns: Non-null computed SHA256RIPEMD block of data
188 + public static func sha256RIPEMD(data: Data) -> Data {
189 + let dataData = TWDataCreateWithNSData(data)
190 + defer {
191 + TWDataDelete(dataData)
192 + }
193 + return TWDataNSData(TWHashSHA256RIPEMD(dataData))
194 + }
195 +
196 + /// Computes the SHA3_256RIPEMD of a block of data.
197 + ///
198 + /// - Parameter data: Non-null block of data
199 + /// - Returns: Non-null computed SHA3_256RIPEMD block of data
200 + public static func sha3_256RIPEMD(data: Data) -> Data {
201 + let dataData = TWDataCreateWithNSData(data)
202 + defer {
203 + TWDataDelete(dataData)
204 + }
205 + return TWDataNSData(TWHashSHA3_256RIPEMD(dataData))
206 + }
207 +
208 + /// Computes the Blake256D of a block of data.
209 + ///
210 + /// - Parameter data: Non-null block of data
211 + /// - Returns: Non-null computed Blake256D block of data
212 + public static func blake256Blake256(data: Data) -> Data {
213 + let dataData = TWDataCreateWithNSData(data)
214 + defer {
215 + TWDataDelete(dataData)
216 + }
217 + return TWDataNSData(TWHashBlake256Blake256(dataData))
218 + }
219 +
220 + /// Computes the Blake256RIPEMD of a block of data.
221 + ///
222 + /// - Parameter data: Non-null block of data
223 + /// - Returns: Non-null computed Blake256RIPEMD block of data
224 + public static func blake256RIPEMD(data: Data) -> Data {
225 + let dataData = TWDataCreateWithNSData(data)
226 + defer {
227 + TWDataDelete(dataData)
228 + }
229 + return TWDataNSData(TWHashBlake256RIPEMD(dataData))
230 + }
231 +
232 + /// Computes the Groestl512D of a block of data.
233 + ///
234 + /// - Parameter data: Non-null block of data
235 + /// - Returns: Non-null computed Groestl512D block of data
236 + public static func groestl512Groestl512(data: Data) -> Data {
237 + let dataData = TWDataCreateWithNSData(data)
238 + defer {
239 + TWDataDelete(dataData)
240 + }
241 + return TWDataNSData(TWHashGroestl512Groestl512(dataData))
242 + }
243 +
244 +
245 + init() {
246 + }
247 +
248 +
249 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/LiquidStaking.swift +32 −0
@@ -0,0 +1,32 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// THORChain swap functions
13 +public struct LiquidStaking {
14 +
15 + /// Builds a LiquidStaking transaction input.
16 + ///
17 + /// - Parameter input: The serialized data of LiquidStakingInput.
18 + /// - Returns: The serialized data of LiquidStakingOutput.
19 + public static func buildRequest(input: Data) -> Data {
20 + let inputData = TWDataCreateWithNSData(input)
21 + defer {
22 + TWDataDelete(inputData)
23 + }
24 + return TWDataNSData(TWLiquidStakingBuildRequest(inputData))
25 + }
26 +
27 +
28 + init() {
29 + }
30 +
31 +
32 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/MessageSigner.swift +67 −0
@@ -0,0 +1,67 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +
13 +public final class MessageSigner {
14 +
15 + /// Signs an arbitrary message to prove ownership of an address for off-chain services.
16 + ///
17 + /// - Parameter coin: The given coin type to sign the message for.
18 + /// - Parameter input: The serialized data of a signing input (e.g. TW.Ethereum.Proto.MessageSigningInput).
19 + /// - Returns: The serialized data of a `SigningOutput` proto object. (e.g. TW.Ethereum.Proto.MessageSigningOutput).
20 + public static func sign(coin: CoinType, input: Data) -> Data? {
21 + let inputData = TWDataCreateWithNSData(input)
22 + defer {
23 + TWDataDelete(inputData)
24 + }
25 + guard let result = TWMessageSignerSign(TWCoinType(rawValue: coin.rawValue), inputData) else {
26 + return nil
27 + }
28 + return TWDataNSData(result)
29 + }
30 +
31 + /// Verifies a signature for a message.
32 + ///
33 + /// - Parameter coin: The given coin type to sign the message for.
34 + /// - Parameter input: The serialized data of a verifying input (e.g. TW.Ethereum.Proto.MessageVerifyingInput).
35 + /// - Returns: whether the signature is valid.
36 + public static func verify(coin: CoinType, input: Data) -> Bool {
37 + let inputData = TWDataCreateWithNSData(input)
38 + defer {
39 + TWDataDelete(inputData)
40 + }
41 + return TWMessageSignerVerify(TWCoinType(rawValue: coin.rawValue), inputData)
42 + }
43 +
44 + /// Computes preimage hashes of a message.
45 + ///
46 + /// - Parameter coin: The given coin type to sign the message for.
47 + /// - Parameter input: The serialized data of a signing input (e.g. TW.Ethereum.Proto.MessageSigningInput).
48 + /// - Returns: The serialized data of TW.TxCompiler.PreSigningOutput.
49 + public static func preImageHashes(coin: CoinType, input: Data) -> Data? {
50 + let inputData = TWDataCreateWithNSData(input)
51 + defer {
52 + TWDataDelete(inputData)
53 + }
54 + guard let result = TWMessageSignerPreImageHashes(TWCoinType(rawValue: coin.rawValue), inputData) else {
55 + return nil
56 + }
57 + return TWDataNSData(result)
58 + }
59 +
60 + let rawValue: OpaquePointer
61 +
62 + init(rawValue: OpaquePointer) {
63 + self.rawValue = rawValue
64 + }
65 +
66 +
67 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Mnemonic.swift +56 −0
@@ -0,0 +1,56 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Mnemonic validate / lookup functions
13 +public struct Mnemonic {
14 +
15 + /// Determines whether a BIP39 English mnemonic phrase is valid.
16 + ///
17 + /// - Parameter mnemonic: Non-null BIP39 english mnemonic
18 + /// - Returns: true if the mnemonic is valid, false otherwise
19 + public static func isValid(mnemonic: String) -> Bool {
20 + let mnemonicString = TWStringCreateWithNSString(mnemonic)
21 + defer {
22 + TWStringDelete(mnemonicString)
23 + }
24 + return TWMnemonicIsValid(mnemonicString)
25 + }
26 +
27 + /// Determines whether word is a valid BIP39 English mnemonic word.
28 + ///
29 + /// - Parameter word: Non-null BIP39 English mnemonic word
30 + /// - Returns: true if the word is a valid BIP39 English mnemonic word, false otherwise
31 + public static func isValidWord(word: String) -> Bool {
32 + let wordString = TWStringCreateWithNSString(word)
33 + defer {
34 + TWStringDelete(wordString)
35 + }
36 + return TWMnemonicIsValidWord(wordString)
37 + }
38 +
39 + /// Return BIP39 English words that match the given prefix. A single string is returned, with space-separated list of words.
40 + ///
41 + /// - Parameter prefix: Non-null string prefix
42 + /// - Returns: Single non-null string, space-separated list of words containing BIP39 words that match the given prefix.
43 + public static func suggest(prefix: String) -> String {
44 + let prefixString = TWStringCreateWithNSString(prefix)
45 + defer {
46 + TWStringDelete(prefixString)
47 + }
48 + return TWStringNSString(TWMnemonicSuggest(prefixString))
49 + }
50 +
51 +
52 + init() {
53 + }
54 +
55 +
56 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/NEARAccount.swift +44 −0
@@ -0,0 +1,44 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a NEAR Account name
13 +public final class NEARAccount {
14 +
15 + /// Returns the user friendly string representation.
16 + ///
17 + /// - Parameter account: Pointer to a non-null NEAR Account
18 + /// - Returns: Non-null string account description
19 + public var description: String {
20 + return TWStringNSString(TWNEARAccountDescription(rawValue))
21 + }
22 +
23 + let rawValue: OpaquePointer
24 +
25 + init(rawValue: OpaquePointer) {
26 + self.rawValue = rawValue
27 + }
28 +
29 + public init?(string: String) {
30 + let stringString = TWStringCreateWithNSString(string)
31 + defer {
32 + TWStringDelete(stringString)
33 + }
34 + guard let rawValue = TWNEARAccountCreateWithString(stringString) else {
35 + return nil
36 + }
37 + self.rawValue = rawValue
38 + }
39 +
40 + deinit {
41 + TWNEARAccountDelete(rawValue)
42 + }
43 +
44 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/NervosAddress.swift +85 −0
@@ -0,0 +1,85 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a Nervos address.
13 +public final class NervosAddress: Address {
14 +
15 + /// Compares two addresses for equality.
16 + ///
17 + /// - Parameter lhs: The first address to compare.
18 + /// - Parameter rhs: The second address to compare.
19 + /// - Returns: bool indicating the addresses are equal.
20 + public static func == (lhs: NervosAddress, rhs: NervosAddress) -> Bool {
21 + return TWNervosAddressEqual(lhs.rawValue, rhs.rawValue)
22 + }
23 +
24 + /// Determines if the string is a valid Nervos address.
25 + ///
26 + /// - Parameter string: string to validate.
27 + /// - Returns: bool indicating if the address is valid.
28 + public static func isValidString(string: String) -> Bool {
29 + let stringString = TWStringCreateWithNSString(string)
30 + defer {
31 + TWStringDelete(stringString)
32 + }
33 + return TWNervosAddressIsValidString(stringString)
34 + }
35 +
36 + /// Returns the address string representation.
37 + ///
38 + /// - Parameter address: Address to get the string representation of.
39 + public var description: String {
40 + return TWStringNSString(TWNervosAddressDescription(rawValue))
41 + }
42 +
43 + /// Returns the Code hash
44 + ///
45 + /// - Parameter address: Address to get the keyhash data of.
46 + public var codeHash: Data {
47 + return TWDataNSData(TWNervosAddressCodeHash(rawValue))
48 + }
49 +
50 + /// Returns the address hash type
51 + ///
52 + /// - Parameter address: Address to get the hash type of.
53 + public var hashType: String {
54 + return TWStringNSString(TWNervosAddressHashType(rawValue))
55 + }
56 +
57 + /// Returns the address args data.
58 + ///
59 + /// - Parameter address: Address to get the args data of.
60 + public var args: Data {
61 + return TWDataNSData(TWNervosAddressArgs(rawValue))
62 + }
63 +
64 + let rawValue: OpaquePointer
65 +
66 + init(rawValue: OpaquePointer) {
67 + self.rawValue = rawValue
68 + }
69 +
70 + public init?(string: String) {
71 + let stringString = TWStringCreateWithNSString(string)
72 + defer {
73 + TWStringDelete(stringString)
74 + }
75 + guard let rawValue = TWNervosAddressCreateWithString(stringString) else {
76 + return nil
77 + }
78 + self.rawValue = rawValue
79 + }
80 +
81 + deinit {
82 + TWNervosAddressDelete(rawValue)
83 + }
84 +
85 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/PBKDF2.swift +64 −0
@@ -0,0 +1,64 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Password-Based Key Derivation Function 2
13 +public struct PBKDF2 {
14 +
15 + /// Derives a key from a password and a salt using PBKDF2 + Sha256.
16 + ///
17 + /// - Parameter password: is the master password from which a derived key is generated
18 + /// - Parameter salt: is a sequence of bits, known as a cryptographic salt
19 + /// - Parameter iterations: is the number of iterations desired
20 + /// - Parameter dkLen: is the desired bit-length of the derived key
21 + /// - Returns: the derived key data.
22 + public static func hmacSha256(password: Data, salt: Data, iterations: UInt32, dkLen: UInt32) -> Data? {
23 + let passwordData = TWDataCreateWithNSData(password)
24 + defer {
25 + TWDataDelete(passwordData)
26 + }
27 + let saltData = TWDataCreateWithNSData(salt)
28 + defer {
29 + TWDataDelete(saltData)
30 + }
31 + guard let result = TWPBKDF2HmacSha256(passwordData, saltData, iterations, dkLen) else {
32 + return nil
33 + }
34 + return TWDataNSData(result)
35 + }
36 +
37 + /// Derives a key from a password and a salt using PBKDF2 + Sha512.
38 + ///
39 + /// - Parameter password: is the master password from which a derived key is generated
40 + /// - Parameter salt: is a sequence of bits, known as a cryptographic salt
41 + /// - Parameter iterations: is the number of iterations desired
42 + /// - Parameter dkLen: is the desired bit-length of the derived key
43 + /// - Returns: the derived key data.
44 + public static func hmacSha512(password: Data, salt: Data, iterations: UInt32, dkLen: UInt32) -> Data? {
45 + let passwordData = TWDataCreateWithNSData(password)
46 + defer {
47 + TWDataDelete(passwordData)
48 + }
49 + let saltData = TWDataCreateWithNSData(salt)
50 + defer {
51 + TWDataDelete(saltData)
52 + }
53 + guard let result = TWPBKDF2HmacSha512(passwordData, saltData, iterations, dkLen) else {
54 + return nil
55 + }
56 + return TWDataNSData(result)
57 + }
58 +
59 +
60 + init() {
61 + }
62 +
63 +
64 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/PrivateKey.swift +184 −0
@@ -0,0 +1,184 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +//
7 +// This is a GENERATED FILE, changes made here WILL BE LOST.
8 +//
9 +
10 +import Foundation
11 +
12 +/// Represents a private key.
13 +public final class PrivateKey {
14 +
15 + /// Determines if the given private key is valid or not.
16 + ///
17 + /// - Parameter data: block of data (private key bytes)
18 + /// - Parameter curve: Eliptic curve of the private key
19 + /// - Returns: true if the private key is valid, false otherwise
20 + public static func isValid(data: Data, curve: Curve) -> Bool {
21 + let dataData = TWDataCreateWithNSData(data)
22 + defer {
23 + TWDataDelete(dataData)
24 + }
25 + return TWPrivateKeyIsValid(dataData, TWCurve(rawValue: curve.rawValue))
26 + }
27 +
28 + /// Convert the given private key to raw-bytes block of data
29 + ///
30 + /// - Parameter pk: Non-null pointer to the private key
31 + /// - Returns: Non-null block of data (raw bytes) of the given private key
32 + public var data: Data {
33 + return TWDataNSData(TWPrivateKeyData(rawValue))
34 + }
35 +
36 + let rawValue: OpaquePointer
37 +
38 + init(rawValue: OpaquePointer) {
39 + self.rawValue = rawValue
40 + }
41 +
42 + public init() {
43 + rawValue = TWPrivateKeyCreate()
44 + }
45 +
46 + public init?(data: Data) {
47 + let dataData = TWDataCreateWithNSData(data)
48 + defer {
49 + TWDataDelete(dataData)
50 + }
51 + guard let rawValue = TWPrivateKeyCreateWithData(dataData) else {
52 + return nil
53 + }
54 + self.rawValue = rawValue
55 + }
56 +
57 + public init?(key: PrivateKey) {
58 + guard let rawValue = TWPrivateKeyCreateCopy(key.rawValue) else {
59 + return nil
60 + }
61 + self.rawValue = rawValue
62 + }
63 +
64 + deinit {
65 + TWPrivateKeyDelete(rawValue)
66 + }
67 +
68 + /// Returns the public key associated with the given coinType and privateKey
69 + ///
70 + /// - Parameter pk: Non-null pointer to the private key
71 + /// - Parameter coinType: coinType of the given private key
72 + /// - Returns: Non-null pointer to the corresponding public key
73 + public func getPublicKey(coinType: CoinType) -> PublicKey {
74 + return PublicKey(rawValue: TWPrivateKeyGetPublicKey(rawValue, TWCoinType(rawValue: coinType.rawValue)))
75 + }
76 +
77 + /// Returns the public key associated with the given pubkeyType and privateKey
78 + ///
79 + /// - Parameter pk: Non-null pointer to the private key
80 + /// - Parameter pubkeyType: pubkeyType of the given private key
81 + /// - Returns: Non-null pointer to the corresponding public key
82 + public func getPublicKeyByType(pubkeyType: PublicKeyType) -> PublicKey {
83 + return PublicKey(rawValue: TWPrivateKeyGetPublicKeyByType(rawValue, TWPublicKeyType(rawValue: pubkeyType.rawValue)))
84 + }
85 +
86 + /// Returns the Secp256k1 public key associated with the given private key
87 + ///
88 + /// - Parameter pk: Non-null pointer to the private key
89 + /// - Parameter compressed: if the given private key is compressed or not
90 + /// - Returns: Non-null pointer to the corresponding public key
91 + public func getPublicKeySecp256k1(compressed: Bool) -> PublicKey {
92 + return PublicKey(rawValue: TWPrivateKeyGetPublicKeySecp256k1(rawValue, compressed))
93 + }
94 +
95 + /// Returns the Nist256p1 public key associated with the given private key
96 + ///
97 + /// - Parameter pk: Non-null pointer to the private key
98 + /// - Returns: Non-null pointer to the corresponding public key
99 + public func getPublicKeyNist256p1() -> PublicKey {
100 + return PublicKey(rawValue: TWPrivateKeyGetPublicKeyNist256p1(rawValue))
101 + }
102 +
103 + /// Returns the Ed25519 public key associated with the given private key
104 + ///
105 + /// - Parameter pk: Non-null pointer to the private key
106 + /// - Returns: Non-null pointer to the corresponding public key
107 + public func getPublicKeyEd25519() -> PublicKey {
108 + return PublicKey(rawValue: TWPrivateKeyGetPublicKeyEd25519(rawValue))
109 + }
110 +
111 + /// Returns the Ed25519Blake2b public key associated with the given private key
112 + ///
113 + /// - Parameter pk: Non-null pointer to the private key
114 + /// - Returns: Non-null pointer to the corresponding public key
115 + public func getPublicKeyEd25519Blake2b() -> PublicKey {
116 + return PublicKey(rawValue: TWPrivateKeyGetPublicKeyEd25519Blake2b(rawValue))
117 + }
118 +
119 + /// Returns the Ed25519Cardano public key associated with the given private key
120 + ///
121 + /// - Parameter pk: Non-null pointer to the private key
122 + /// - Returns: Non-null pointer to the corresponding public key
123 + public func getPublicKeyEd25519Cardano() -> PublicKey {
124 + return PublicKey(rawValue: TWPrivateKeyGetPublicKeyEd25519Cardano(rawValue))
125 + }
126 +
127 + /// Returns the Curve25519 public key associated with the given private key
128 + ///
129 + /// - Parameter pk: Non-null pointer to the private key
130 + /// - Returns: Non-null pointer to the corresponding public key
131 + public func getPublicKeyCurve25519() -> PublicKey {
132 + return PublicKey(rawValue: TWPrivateKeyGetPublicKeyCurve25519(rawValue))
133 + }
134 +
135 + /// Signs a digest using ECDSA and given curve.
136 + ///
137 + /// - Parameter pk: Non-null pointer to a Private key
138 + /// - Parameter digest: Non-null digest block of data
139 + /// - Parameter curve: Eliptic curve
140 + /// - Returns: Signature as a Non-null block of data
141 + public func sign(digest: Data, curve: Curve) -> Data? {
142 + let digestData = TWDataCreateWithNSData(digest)
143 + defer {
144 + TWDataDelete(digestData)
145 + }
146 + guard let result = TWPrivateKeySign(rawValue, digestData, TWCurve(rawValue: curve.rawValue)) else {
147 + return nil
148 + }
149 + return TWDataNSData(result)
150 + }
151 +
152 + /// Signs a digest using ECDSA. The result is encoded with DER.
153 + ///
154 + /// - Parameter pk: Non-null pointer to a Private key
155 + /// - Parameter digest: Non-null digest block of data
156 + /// - Returns: Signature as a Non-null block of data
157 + public func signAsDER(digest: Data) -> Data? {
158 + let digestData = TWDataCreateWithNSData(digest)
159 + defer {
160 + TWDataDelete(digestData)
161 + }
162 + guard let result = TWPrivateKeySignAsDER(rawValue, digestData) else {
163 + return nil
164 + }
165 + return TWDataNSData(result)
166 + }
167 +
168 + /// Signs a digest using ECDSA and Zilliqa schnorr signature scheme.
169 + ///
170 + /// - Parameter pk: Non-null pointer to a Private key
171 + /// - Parameter message: Non-null message
172 + /// - Returns: Signature as a Non-null block of data
173 + public func signZilliqaSchnorr(message: Data) -> Data? {
174 + let messageData = TWDataCreateWithNSData(message)
175 + defer {
176 + TWDataDelete(messageData)
177 + }
178 + guard let result = TWPrivateKeySignZilliqaSchnorr(rawValue, messageData) else {
179 + return nil
180 + }
181 + return TWDataNSData(result)
182 + }
183 +
184 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Aeternity+Proto.swift +8 −0
@@ -0,0 +1,8 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public typealias AeternitySigningInput = TW_Aeternity_Proto_SigningInput
8 +public typealias AeternitySigningOutput = TW_Aeternity_Proto_SigningOutput
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Aeternity.pb.swift +209 −0
@@ -0,0 +1,209 @@
1 +import WalletCoreC
2 +import Foundation
3 +// DO NOT EDIT.
4 +// swift-format-ignore-file
5 +//
6 +// Generated by the Swift generator plugin for the protocol buffer compiler.
7 +// Source: Aeternity.proto
8 +//
9 +// For information on using the generated types, please see the documentation:
10 +// https://github.com/apple/swift-protobuf/
11 +
12 +import Foundation
13 +import SwiftProtobuf
14 +
15 +// If the compiler emits an error on this type, it is because this file
16 +// was generated by a version of the `protoc` Swift plug-in that is
17 +// incompatible with the version of SwiftProtobuf.to which you are linking.
18 +// Please ensure that you are building against the same version of the API
19 +// that was used to generate this file.
20 +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
21 + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
22 + typealias Version = _2
23 +}
24 +
25 +/// Input data necessary to create a signed transaction.
26 +public struct TW_Aeternity_Proto_SigningInput {
27 + // SwiftProtobuf.Message conformance is added in an extension below. See the
28 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
29 + // methods supported on all messages.
30 +
31 + /// Address of the sender with "ak_" prefix
32 + public var fromAddress: String = String()
33 +
34 + /// Address of the recipient with "ak_" prefix
35 + public var toAddress: String = String()
36 +
37 + /// Amount (uint256, serialized big endian)
38 + public var amount: Data = Data()
39 +
40 + /// Fee amount (uint256, serialized big endian)
41 + public var fee: Data = Data()
42 +
43 + /// Message, optional
44 + public var payload: String = String()
45 +
46 + /// Time to live until block height
47 + public var ttl: UInt64 = 0
48 +
49 + /// Nonce (should be larger than in the last transaction of the account)
50 + public var nonce: UInt64 = 0
51 +
52 + /// The secret private key used for signing (32 bytes).
53 + public var privateKey: Data = Data()
54 +
55 + public var unknownFields = SwiftProtobuf.UnknownStorage()
56 +
57 + public init() {}
58 +}
59 +
60 +/// Result containing the signed and encoded transaction.
61 +public struct TW_Aeternity_Proto_SigningOutput {
62 + // SwiftProtobuf.Message conformance is added in an extension below. See the
63 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
64 + // methods supported on all messages.
65 +
66 + /// Signed and encoded transaction bytes, Base64 with checksum
67 + public var encoded: String = String()
68 +
69 + /// Signature, Base58 with checksum
70 + public var signature: String = String()
71 +
72 + /// error code, 0 is ok, other codes will be treated as errors
73 + public var error: TW_Common_Proto_SigningError = .ok
74 +
75 + /// error description
76 + public var errorMessage: String = String()
77 +
78 + public var unknownFields = SwiftProtobuf.UnknownStorage()
79 +
80 + public init() {}
81 +}
82 +
83 +// MARK: - Code below here is support for the SwiftProtobuf.runtime.
84 +
85 +fileprivate let _protobuf_package = "TW.Aeternity.Proto"
86 +
87 +extension TW_Aeternity_Proto_SigningInput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
88 + public static let protoMessageName: String = _protobuf_package + ".SigningInput"
89 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
90 + 1: .standard(proto: "from_address"),
91 + 2: .standard(proto: "to_address"),
92 + 3: .same(proto: "amount"),
93 + 4: .same(proto: "fee"),
94 + 5: .same(proto: "payload"),
95 + 6: .same(proto: "ttl"),
96 + 7: .same(proto: "nonce"),
97 + 8: .standard(proto: "private_key"),
98 + ]
99 +
100 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
101 + while let fieldNumber = try decoder.nextFieldNumber() {
102 + // The use of inline closures is to circumvent an issue where the compiler
103 + // allocates stack space for every case branch when no optimizations are
104 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
105 + switch fieldNumber {
106 + case 1: try { try decoder.decodeSingularStringField(value: &self.fromAddress) }()
107 + case 2: try { try decoder.decodeSingularStringField(value: &self.toAddress) }()
108 + case 3: try { try decoder.decodeSingularBytesField(value: &self.amount) }()
109 + case 4: try { try decoder.decodeSingularBytesField(value: &self.fee) }()
110 + case 5: try { try decoder.decodeSingularStringField(value: &self.payload) }()
111 + case 6: try { try decoder.decodeSingularUInt64Field(value: &self.ttl) }()
112 + case 7: try { try decoder.decodeSingularUInt64Field(value: &self.nonce) }()
113 + case 8: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }()
114 + default: break
115 + }
116 + }
117 + }
118 +
119 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
120 + if !self.fromAddress.isEmpty {
121 + try visitor.visitSingularStringField(value: self.fromAddress, fieldNumber: 1)
122 + }
123 + if !self.toAddress.isEmpty {
124 + try visitor.visitSingularStringField(value: self.toAddress, fieldNumber: 2)
125 + }
126 + if !self.amount.isEmpty {
127 + try visitor.visitSingularBytesField(value: self.amount, fieldNumber: 3)
128 + }
129 + if !self.fee.isEmpty {
130 + try visitor.visitSingularBytesField(value: self.fee, fieldNumber: 4)
131 + }
132 + if !self.payload.isEmpty {
133 + try visitor.visitSingularStringField(value: self.payload, fieldNumber: 5)
134 + }
135 + if self.ttl != 0 {
136 + try visitor.visitSingularUInt64Field(value: self.ttl, fieldNumber: 6)
137 + }
138 + if self.nonce != 0 {
139 + try visitor.visitSingularUInt64Field(value: self.nonce, fieldNumber: 7)
140 + }
141 + if !self.privateKey.isEmpty {
142 + try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 8)
143 + }
144 + try unknownFields.traverse(visitor: &visitor)
145 + }
146 +
147 + public static func ==(lhs: TW_Aeternity_Proto_SigningInput, rhs: TW_Aeternity_Proto_SigningInput) -> Bool {
148 + if lhs.fromAddress != rhs.fromAddress {return false}
149 + if lhs.toAddress != rhs.toAddress {return false}
150 + if lhs.amount != rhs.amount {return false}
151 + if lhs.fee != rhs.fee {return false}
152 + if lhs.payload != rhs.payload {return false}
153 + if lhs.ttl != rhs.ttl {return false}
154 + if lhs.nonce != rhs.nonce {return false}
155 + if lhs.privateKey != rhs.privateKey {return false}
156 + if lhs.unknownFields != rhs.unknownFields {return false}
157 + return true
158 + }
159 +}
160 +
161 +extension TW_Aeternity_Proto_SigningOutput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
162 + public static let protoMessageName: String = _protobuf_package + ".SigningOutput"
163 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
164 + 1: .same(proto: "encoded"),
165 + 2: .same(proto: "signature"),
166 + 3: .same(proto: "error"),
167 + 4: .standard(proto: "error_message"),
168 + ]
169 +
170 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
171 + while let fieldNumber = try decoder.nextFieldNumber() {
172 + // The use of inline closures is to circumvent an issue where the compiler
173 + // allocates stack space for every case branch when no optimizations are
174 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
175 + switch fieldNumber {
176 + case 1: try { try decoder.decodeSingularStringField(value: &self.encoded) }()
177 + case 2: try { try decoder.decodeSingularStringField(value: &self.signature) }()
178 + case 3: try { try decoder.decodeSingularEnumField(value: &self.error) }()
179 + case 4: try { try decoder.decodeSingularStringField(value: &self.errorMessage) }()
180 + default: break
181 + }
182 + }
183 + }
184 +
185 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
186 + if !self.encoded.isEmpty {
187 + try visitor.visitSingularStringField(value: self.encoded, fieldNumber: 1)
188 + }
189 + if !self.signature.isEmpty {
190 + try visitor.visitSingularStringField(value: self.signature, fieldNumber: 2)
191 + }
192 + if self.error != .ok {
193 + try visitor.visitSingularEnumField(value: self.error, fieldNumber: 3)
194 + }
195 + if !self.errorMessage.isEmpty {
196 + try visitor.visitSingularStringField(value: self.errorMessage, fieldNumber: 4)
197 + }
198 + try unknownFields.traverse(visitor: &visitor)
199 + }
200 +
201 + public static func ==(lhs: TW_Aeternity_Proto_SigningOutput, rhs: TW_Aeternity_Proto_SigningOutput) -> Bool {
202 + if lhs.encoded != rhs.encoded {return false}
203 + if lhs.signature != rhs.signature {return false}
204 + if lhs.error != rhs.error {return false}
205 + if lhs.errorMessage != rhs.errorMessage {return false}
206 + if lhs.unknownFields != rhs.unknownFields {return false}
207 + return true
208 + }
209 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Aion+Proto.swift +8 −0
@@ -0,0 +1,8 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public typealias AionSigningInput = TW_Aion_Proto_SigningInput
8 +public typealias AionSigningOutput = TW_Aion_Proto_SigningOutput
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Aion.pb.swift +209 −0
@@ -0,0 +1,209 @@
1 +import WalletCoreC
2 +import Foundation
3 +// DO NOT EDIT.
4 +// swift-format-ignore-file
5 +//
6 +// Generated by the Swift generator plugin for the protocol buffer compiler.
7 +// Source: Aion.proto
8 +//
9 +// For information on using the generated types, please see the documentation:
10 +// https://github.com/apple/swift-protobuf/
11 +
12 +import Foundation
13 +import SwiftProtobuf
14 +
15 +// If the compiler emits an error on this type, it is because this file
16 +// was generated by a version of the `protoc` Swift plug-in that is
17 +// incompatible with the version of SwiftProtobuf.to which you are linking.
18 +// Please ensure that you are building against the same version of the API
19 +// that was used to generate this file.
20 +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
21 + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
22 + typealias Version = _2
23 +}
24 +
25 +/// Input data necessary to create a signed transaction.
26 +public struct TW_Aion_Proto_SigningInput {
27 + // SwiftProtobuf.Message conformance is added in an extension below. See the
28 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
29 + // methods supported on all messages.
30 +
31 + /// Nonce (uint256, serialized big endian)
32 + public var nonce: Data = Data()
33 +
34 + /// Gas price (uint256, serialized big endian)
35 + public var gasPrice: Data = Data()
36 +
37 + /// Gas limit (uint256, serialized big endian)
38 + public var gasLimit: Data = Data()
39 +
40 + /// Recipient's address.
41 + public var toAddress: String = String()
42 +
43 + /// Amount to send in wei (uint256, serialized big endian)
44 + public var amount: Data = Data()
45 +
46 + /// Optional payload
47 + public var payload: Data = Data()
48 +
49 + /// The secret private key used for signing (32 bytes).
50 + public var privateKey: Data = Data()
51 +
52 + /// Timestamp
53 + public var timestamp: UInt64 = 0
54 +
55 + public var unknownFields = SwiftProtobuf.UnknownStorage()
56 +
57 + public init() {}
58 +}
59 +
60 +/// Result containing the signed and encoded transaction.
61 +public struct TW_Aion_Proto_SigningOutput {
62 + // SwiftProtobuf.Message conformance is added in an extension below. See the
63 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
64 + // methods supported on all messages.
65 +
66 + /// Signed and encoded transaction bytes.
67 + public var encoded: Data = Data()
68 +
69 + /// Signature.
70 + public var signature: Data = Data()
71 +
72 + /// error code, 0 is ok, other codes will be treated as errors
73 + public var error: TW_Common_Proto_SigningError = .ok
74 +
75 + /// error description
76 + public var errorMessage: String = String()
77 +
78 + public var unknownFields = SwiftProtobuf.UnknownStorage()
79 +
80 + public init() {}
81 +}
82 +
83 +// MARK: - Code below here is support for the SwiftProtobuf.runtime.
84 +
85 +fileprivate let _protobuf_package = "TW.Aion.Proto"
86 +
87 +extension TW_Aion_Proto_SigningInput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
88 + public static let protoMessageName: String = _protobuf_package + ".SigningInput"
89 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
90 + 1: .same(proto: "nonce"),
91 + 2: .standard(proto: "gas_price"),
92 + 3: .standard(proto: "gas_limit"),
93 + 4: .standard(proto: "to_address"),
94 + 5: .same(proto: "amount"),
95 + 6: .same(proto: "payload"),
96 + 7: .standard(proto: "private_key"),
97 + 8: .same(proto: "timestamp"),
98 + ]
99 +
100 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
101 + while let fieldNumber = try decoder.nextFieldNumber() {
102 + // The use of inline closures is to circumvent an issue where the compiler
103 + // allocates stack space for every case branch when no optimizations are
104 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
105 + switch fieldNumber {
106 + case 1: try { try decoder.decodeSingularBytesField(value: &self.nonce) }()
107 + case 2: try { try decoder.decodeSingularBytesField(value: &self.gasPrice) }()
108 + case 3: try { try decoder.decodeSingularBytesField(value: &self.gasLimit) }()
109 + case 4: try { try decoder.decodeSingularStringField(value: &self.toAddress) }()
110 + case 5: try { try decoder.decodeSingularBytesField(value: &self.amount) }()
111 + case 6: try { try decoder.decodeSingularBytesField(value: &self.payload) }()
112 + case 7: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }()
113 + case 8: try { try decoder.decodeSingularUInt64Field(value: &self.timestamp) }()
114 + default: break
115 + }
116 + }
117 + }
118 +
119 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
120 + if !self.nonce.isEmpty {
121 + try visitor.visitSingularBytesField(value: self.nonce, fieldNumber: 1)
122 + }
123 + if !self.gasPrice.isEmpty {
124 + try visitor.visitSingularBytesField(value: self.gasPrice, fieldNumber: 2)
125 + }
126 + if !self.gasLimit.isEmpty {
127 + try visitor.visitSingularBytesField(value: self.gasLimit, fieldNumber: 3)
128 + }
129 + if !self.toAddress.isEmpty {
130 + try visitor.visitSingularStringField(value: self.toAddress, fieldNumber: 4)
131 + }
132 + if !self.amount.isEmpty {
133 + try visitor.visitSingularBytesField(value: self.amount, fieldNumber: 5)
134 + }
135 + if !self.payload.isEmpty {
136 + try visitor.visitSingularBytesField(value: self.payload, fieldNumber: 6)
137 + }
138 + if !self.privateKey.isEmpty {
139 + try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 7)
140 + }
141 + if self.timestamp != 0 {
142 + try visitor.visitSingularUInt64Field(value: self.timestamp, fieldNumber: 8)
143 + }
144 + try unknownFields.traverse(visitor: &visitor)
145 + }
146 +
147 + public static func ==(lhs: TW_Aion_Proto_SigningInput, rhs: TW_Aion_Proto_SigningInput) -> Bool {
148 + if lhs.nonce != rhs.nonce {return false}
149 + if lhs.gasPrice != rhs.gasPrice {return false}
150 + if lhs.gasLimit != rhs.gasLimit {return false}
151 + if lhs.toAddress != rhs.toAddress {return false}
152 + if lhs.amount != rhs.amount {return false}
153 + if lhs.payload != rhs.payload {return false}
154 + if lhs.privateKey != rhs.privateKey {return false}
155 + if lhs.timestamp != rhs.timestamp {return false}
156 + if lhs.unknownFields != rhs.unknownFields {return false}
157 + return true
158 + }
159 +}
160 +
161 +extension TW_Aion_Proto_SigningOutput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
162 + public static let protoMessageName: String = _protobuf_package + ".SigningOutput"
163 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
164 + 1: .same(proto: "encoded"),
165 + 2: .same(proto: "signature"),
166 + 3: .same(proto: "error"),
167 + 4: .standard(proto: "error_message"),
168 + ]
169 +
170 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
171 + while let fieldNumber = try decoder.nextFieldNumber() {
172 + // The use of inline closures is to circumvent an issue where the compiler
173 + // allocates stack space for every case branch when no optimizations are
174 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
175 + switch fieldNumber {
176 + case 1: try { try decoder.decodeSingularBytesField(value: &self.encoded) }()
177 + case 2: try { try decoder.decodeSingularBytesField(value: &self.signature) }()
178 + case 3: try { try decoder.decodeSingularEnumField(value: &self.error) }()
179 + case 4: try { try decoder.decodeSingularStringField(value: &self.errorMessage) }()
180 + default: break
181 + }
182 + }
183 + }
184 +
185 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
186 + if !self.encoded.isEmpty {
187 + try visitor.visitSingularBytesField(value: self.encoded, fieldNumber: 1)
188 + }
189 + if !self.signature.isEmpty {
190 + try visitor.visitSingularBytesField(value: self.signature, fieldNumber: 2)
191 + }
192 + if self.error != .ok {
193 + try visitor.visitSingularEnumField(value: self.error, fieldNumber: 3)
194 + }
195 + if !self.errorMessage.isEmpty {
196 + try visitor.visitSingularStringField(value: self.errorMessage, fieldNumber: 4)
197 + }
198 + try unknownFields.traverse(visitor: &visitor)
199 + }
200 +
201 + public static func ==(lhs: TW_Aion_Proto_SigningOutput, rhs: TW_Aion_Proto_SigningOutput) -> Bool {
202 + if lhs.encoded != rhs.encoded {return false}
203 + if lhs.signature != rhs.signature {return false}
204 + if lhs.error != rhs.error {return false}
205 + if lhs.errorMessage != rhs.errorMessage {return false}
206 + if lhs.unknownFields != rhs.unknownFields {return false}
207 + return true
208 + }
209 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Algorand+Proto.swift +11 −0
@@ -0,0 +1,11 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public typealias AlgorandTransfer = TW_Algorand_Proto_Transfer
8 +public typealias AlgorandAssetTransfer = TW_Algorand_Proto_AssetTransfer
9 +public typealias AlgorandAssetOptIn = TW_Algorand_Proto_AssetOptIn
10 +public typealias AlgorandSigningInput = TW_Algorand_Proto_SigningInput
11 +public typealias AlgorandSigningOutput = TW_Algorand_Proto_SigningOutput
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Algorand.pb.swift +493 −0
@@ -0,0 +1,493 @@
1 +import WalletCoreC
2 +import Foundation
3 +// DO NOT EDIT.
4 +// swift-format-ignore-file
5 +//
6 +// Generated by the Swift generator plugin for the protocol buffer compiler.
7 +// Source: Algorand.proto
8 +//
9 +// For information on using the generated types, please see the documentation:
10 +// https://github.com/apple/swift-protobuf/
11 +
12 +import Foundation
13 +import SwiftProtobuf
14 +
15 +// If the compiler emits an error on this type, it is because this file
16 +// was generated by a version of the `protoc` Swift plug-in that is
17 +// incompatible with the version of SwiftProtobuf.to which you are linking.
18 +// Please ensure that you are building against the same version of the API
19 +// that was used to generate this file.
20 +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
21 + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
22 + typealias Version = _2
23 +}
24 +
25 +/// Simple transfer message, transfer an amount to an address
26 +public struct TW_Algorand_Proto_Transfer {
27 + // SwiftProtobuf.Message conformance is added in an extension below. See the
28 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
29 + // methods supported on all messages.
30 +
31 + /// Destination address (string)
32 + public var toAddress: String = String()
33 +
34 + /// Amount
35 + public var amount: UInt64 = 0
36 +
37 + public var unknownFields = SwiftProtobuf.UnknownStorage()
38 +
39 + public init() {}
40 +}
41 +
42 +/// Asset Transfer message, with assetID
43 +public struct TW_Algorand_Proto_AssetTransfer {
44 + // SwiftProtobuf.Message conformance is added in an extension below. See the
45 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
46 + // methods supported on all messages.
47 +
48 + /// Destination address (string)
49 + public var toAddress: String = String()
50 +
51 + /// Amount
52 + public var amount: UInt64 = 0
53 +
54 + /// ID of the asset being transferred
55 + public var assetID: UInt64 = 0
56 +
57 + public var unknownFields = SwiftProtobuf.UnknownStorage()
58 +
59 + public init() {}
60 +}
61 +
62 +/// Opt-in message for an asset
63 +public struct TW_Algorand_Proto_AssetOptIn {
64 + // SwiftProtobuf.Message conformance is added in an extension below. See the
65 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
66 + // methods supported on all messages.
67 +
68 + /// ID of the asset
69 + public var assetID: UInt64 = 0
70 +
71 + public var unknownFields = SwiftProtobuf.UnknownStorage()
72 +
73 + public init() {}
74 +}
75 +
76 +/// Input data necessary to create a signed transaction.
77 +public struct TW_Algorand_Proto_SigningInput {
78 + // SwiftProtobuf.Message conformance is added in an extension below. See the
79 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
80 + // methods supported on all messages.
81 +
82 + /// network / chain id
83 + public var genesisID: String = String()
84 +
85 + /// network / chain hash
86 + public var genesisHash: Data = Data()
87 +
88 + /// binary note data
89 + public var note: Data = Data()
90 +
91 + /// The secret private key used for signing (32 bytes).
92 + public var privateKey: Data = Data()
93 +
94 + /// network / first round
95 + public var firstRound: UInt64 = 0
96 +
97 + /// network / last round
98 + public var lastRound: UInt64 = 0
99 +
100 + /// fee amount
101 + public var fee: UInt64 = 0
102 +
103 + /// public key
104 + public var publicKey: Data = Data()
105 +
106 + /// message payload
107 + public var messageOneof: TW_Algorand_Proto_SigningInput.OneOf_MessageOneof? = nil
108 +
109 + public var transfer: TW_Algorand_Proto_Transfer {
110 + get {
111 + if case .transfer(let v)? = messageOneof {return v}
112 + return TW_Algorand_Proto_Transfer()
113 + }
114 + set {messageOneof = .transfer(newValue)}
115 + }
116 +
117 + public var assetTransfer: TW_Algorand_Proto_AssetTransfer {
118 + get {
119 + if case .assetTransfer(let v)? = messageOneof {return v}
120 + return TW_Algorand_Proto_AssetTransfer()
121 + }
122 + set {messageOneof = .assetTransfer(newValue)}
123 + }
124 +
125 + public var assetOptIn: TW_Algorand_Proto_AssetOptIn {
126 + get {
127 + if case .assetOptIn(let v)? = messageOneof {return v}
128 + return TW_Algorand_Proto_AssetOptIn()
129 + }
130 + set {messageOneof = .assetOptIn(newValue)}
131 + }
132 +
133 + public var unknownFields = SwiftProtobuf.UnknownStorage()
134 +
135 + /// message payload
136 + public enum OneOf_MessageOneof: Equatable {
137 + case transfer(TW_Algorand_Proto_Transfer)
138 + case assetTransfer(TW_Algorand_Proto_AssetTransfer)
139 + case assetOptIn(TW_Algorand_Proto_AssetOptIn)
140 +
141 + #if !swift(>=4.1)
142 + public static func ==(lhs: TW_Algorand_Proto_SigningInput.OneOf_MessageOneof, rhs: TW_Algorand_Proto_SigningInput.OneOf_MessageOneof) -> Bool {
143 + // The use of inline closures is to circumvent an issue where the compiler
144 + // allocates stack space for every case branch when no optimizations are
145 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
146 + switch (lhs, rhs) {
147 + case (.transfer, .transfer): return {
148 + guard case .transfer(let l) = lhs, case .transfer(let r) = rhs else { preconditionFailure() }
149 + return l == r
150 + }()
151 + case (.assetTransfer, .assetTransfer): return {
152 + guard case .assetTransfer(let l) = lhs, case .assetTransfer(let r) = rhs else { preconditionFailure() }
153 + return l == r
154 + }()
155 + case (.assetOptIn, .assetOptIn): return {
156 + guard case .assetOptIn(let l) = lhs, case .assetOptIn(let r) = rhs else { preconditionFailure() }
157 + return l == r
158 + }()
159 + default: return false
160 + }
161 + }
162 + #endif
163 + }
164 +
165 + public init() {}
166 +}
167 +
168 +/// Result containing the signed and encoded transaction.
169 +public struct TW_Algorand_Proto_SigningOutput {
170 + // SwiftProtobuf.Message conformance is added in an extension below. See the
171 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
172 + // methods supported on all messages.
173 +
174 + /// Signed and encoded transaction bytes.
175 + public var encoded: Data = Data()
176 +
177 + /// Signature in base64.
178 + public var signature: String = String()
179 +
180 + /// Error code, 0 is ok, other codes will be treated as errors.
181 + public var error: TW_Common_Proto_SigningError = .ok
182 +
183 + /// Error description.
184 + public var errorMessage: String = String()
185 +
186 + public var unknownFields = SwiftProtobuf.UnknownStorage()
187 +
188 + public init() {}
189 +}
190 +
191 +// MARK: - Code below here is support for the SwiftProtobuf.runtime.
192 +
193 +fileprivate let _protobuf_package = "TW.Algorand.Proto"
194 +
195 +extension TW_Algorand_Proto_Transfer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
196 + public static let protoMessageName: String = _protobuf_package + ".Transfer"
197 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
198 + 1: .standard(proto: "to_address"),
199 + 2: .same(proto: "amount"),
200 + ]
201 +
202 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
203 + while let fieldNumber = try decoder.nextFieldNumber() {
204 + // The use of inline closures is to circumvent an issue where the compiler
205 + // allocates stack space for every case branch when no optimizations are
206 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
207 + switch fieldNumber {
208 + case 1: try { try decoder.decodeSingularStringField(value: &self.toAddress) }()
209 + case 2: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
210 + default: break
211 + }
212 + }
213 + }
214 +
215 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
216 + if !self.toAddress.isEmpty {
217 + try visitor.visitSingularStringField(value: self.toAddress, fieldNumber: 1)
218 + }
219 + if self.amount != 0 {
220 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 2)
221 + }
222 + try unknownFields.traverse(visitor: &visitor)
223 + }
224 +
225 + public static func ==(lhs: TW_Algorand_Proto_Transfer, rhs: TW_Algorand_Proto_Transfer) -> Bool {
226 + if lhs.toAddress != rhs.toAddress {return false}
227 + if lhs.amount != rhs.amount {return false}
228 + if lhs.unknownFields != rhs.unknownFields {return false}
229 + return true
230 + }
231 +}
232 +
233 +extension TW_Algorand_Proto_AssetTransfer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
234 + public static let protoMessageName: String = _protobuf_package + ".AssetTransfer"
235 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
236 + 1: .standard(proto: "to_address"),
237 + 2: .same(proto: "amount"),
238 + 3: .standard(proto: "asset_id"),
239 + ]
240 +
241 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
242 + while let fieldNumber = try decoder.nextFieldNumber() {
243 + // The use of inline closures is to circumvent an issue where the compiler
244 + // allocates stack space for every case branch when no optimizations are
245 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
246 + switch fieldNumber {
247 + case 1: try { try decoder.decodeSingularStringField(value: &self.toAddress) }()
248 + case 2: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
249 + case 3: try { try decoder.decodeSingularUInt64Field(value: &self.assetID) }()
250 + default: break
251 + }
252 + }
253 + }
254 +
255 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
256 + if !self.toAddress.isEmpty {
257 + try visitor.visitSingularStringField(value: self.toAddress, fieldNumber: 1)
258 + }
259 + if self.amount != 0 {
260 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 2)
261 + }
262 + if self.assetID != 0 {
263 + try visitor.visitSingularUInt64Field(value: self.assetID, fieldNumber: 3)
264 + }
265 + try unknownFields.traverse(visitor: &visitor)
266 + }
267 +
268 + public static func ==(lhs: TW_Algorand_Proto_AssetTransfer, rhs: TW_Algorand_Proto_AssetTransfer) -> Bool {
269 + if lhs.toAddress != rhs.toAddress {return false}
270 + if lhs.amount != rhs.amount {return false}
271 + if lhs.assetID != rhs.assetID {return false}
272 + if lhs.unknownFields != rhs.unknownFields {return false}
273 + return true
274 + }
275 +}
276 +
277 +extension TW_Algorand_Proto_AssetOptIn: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
278 + public static let protoMessageName: String = _protobuf_package + ".AssetOptIn"
279 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
280 + 1: .standard(proto: "asset_id"),
281 + ]
282 +
283 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
284 + while let fieldNumber = try decoder.nextFieldNumber() {
285 + // The use of inline closures is to circumvent an issue where the compiler
286 + // allocates stack space for every case branch when no optimizations are
287 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
288 + switch fieldNumber {
289 + case 1: try { try decoder.decodeSingularUInt64Field(value: &self.assetID) }()
290 + default: break
291 + }
292 + }
293 + }
294 +
295 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
296 + if self.assetID != 0 {
297 + try visitor.visitSingularUInt64Field(value: self.assetID, fieldNumber: 1)
298 + }
299 + try unknownFields.traverse(visitor: &visitor)
300 + }
301 +
302 + public static func ==(lhs: TW_Algorand_Proto_AssetOptIn, rhs: TW_Algorand_Proto_AssetOptIn) -> Bool {
303 + if lhs.assetID != rhs.assetID {return false}
304 + if lhs.unknownFields != rhs.unknownFields {return false}
305 + return true
306 + }
307 +}
308 +
309 +extension TW_Algorand_Proto_SigningInput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
310 + public static let protoMessageName: String = _protobuf_package + ".SigningInput"
311 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
312 + 1: .standard(proto: "genesis_id"),
313 + 2: .standard(proto: "genesis_hash"),
314 + 3: .same(proto: "note"),
315 + 4: .standard(proto: "private_key"),
316 + 5: .standard(proto: "first_round"),
317 + 6: .standard(proto: "last_round"),
318 + 7: .same(proto: "fee"),
319 + 8: .standard(proto: "public_key"),
320 + 10: .same(proto: "transfer"),
321 + 11: .standard(proto: "asset_transfer"),
322 + 12: .standard(proto: "asset_opt_in"),
323 + ]
324 +
325 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
326 + while let fieldNumber = try decoder.nextFieldNumber() {
327 + // The use of inline closures is to circumvent an issue where the compiler
328 + // allocates stack space for every case branch when no optimizations are
329 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
330 + switch fieldNumber {
331 + case 1: try { try decoder.decodeSingularStringField(value: &self.genesisID) }()
332 + case 2: try { try decoder.decodeSingularBytesField(value: &self.genesisHash) }()
333 + case 3: try { try decoder.decodeSingularBytesField(value: &self.note) }()
334 + case 4: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }()
335 + case 5: try { try decoder.decodeSingularUInt64Field(value: &self.firstRound) }()
336 + case 6: try { try decoder.decodeSingularUInt64Field(value: &self.lastRound) }()
337 + case 7: try { try decoder.decodeSingularUInt64Field(value: &self.fee) }()
338 + case 8: try { try decoder.decodeSingularBytesField(value: &self.publicKey) }()
339 + case 10: try {
340 + var v: TW_Algorand_Proto_Transfer?
341 + var hadOneofValue = false
342 + if let current = self.messageOneof {
343 + hadOneofValue = true
344 + if case .transfer(let m) = current {v = m}
345 + }
346 + try decoder.decodeSingularMessageField(value: &v)
347 + if let v = v {
348 + if hadOneofValue {try decoder.handleConflictingOneOf()}
349 + self.messageOneof = .transfer(v)
350 + }
351 + }()
352 + case 11: try {
353 + var v: TW_Algorand_Proto_AssetTransfer?
354 + var hadOneofValue = false
355 + if let current = self.messageOneof {
356 + hadOneofValue = true
357 + if case .assetTransfer(let m) = current {v = m}
358 + }
359 + try decoder.decodeSingularMessageField(value: &v)
360 + if let v = v {
361 + if hadOneofValue {try decoder.handleConflictingOneOf()}
362 + self.messageOneof = .assetTransfer(v)
363 + }
364 + }()
365 + case 12: try {
366 + var v: TW_Algorand_Proto_AssetOptIn?
367 + var hadOneofValue = false
368 + if let current = self.messageOneof {
369 + hadOneofValue = true
370 + if case .assetOptIn(let m) = current {v = m}
371 + }
372 + try decoder.decodeSingularMessageField(value: &v)
373 + if let v = v {
374 + if hadOneofValue {try decoder.handleConflictingOneOf()}
375 + self.messageOneof = .assetOptIn(v)
376 + }
377 + }()
378 + default: break
379 + }
380 + }
381 + }
382 +
383 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
384 + // The use of inline closures is to circumvent an issue where the compiler
385 + // allocates stack space for every if/case branch local when no optimizations
386 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
387 + // https://github.com/apple/swift-protobuf/issues/1182
388 + if !self.genesisID.isEmpty {
389 + try visitor.visitSingularStringField(value: self.genesisID, fieldNumber: 1)
390 + }
391 + if !self.genesisHash.isEmpty {
392 + try visitor.visitSingularBytesField(value: self.genesisHash, fieldNumber: 2)
393 + }
394 + if !self.note.isEmpty {
395 + try visitor.visitSingularBytesField(value: self.note, fieldNumber: 3)
396 + }
397 + if !self.privateKey.isEmpty {
398 + try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 4)
399 + }
400 + if self.firstRound != 0 {
401 + try visitor.visitSingularUInt64Field(value: self.firstRound, fieldNumber: 5)
402 + }
403 + if self.lastRound != 0 {
404 + try visitor.visitSingularUInt64Field(value: self.lastRound, fieldNumber: 6)
405 + }
406 + if self.fee != 0 {
407 + try visitor.visitSingularUInt64Field(value: self.fee, fieldNumber: 7)
408 + }
409 + if !self.publicKey.isEmpty {
410 + try visitor.visitSingularBytesField(value: self.publicKey, fieldNumber: 8)
411 + }
412 + switch self.messageOneof {
413 + case .transfer?: try {
414 + guard case .transfer(let v)? = self.messageOneof else { preconditionFailure() }
415 + try visitor.visitSingularMessageField(value: v, fieldNumber: 10)
416 + }()
417 + case .assetTransfer?: try {
418 + guard case .assetTransfer(let v)? = self.messageOneof else { preconditionFailure() }
419 + try visitor.visitSingularMessageField(value: v, fieldNumber: 11)
420 + }()
421 + case .assetOptIn?: try {
422 + guard case .assetOptIn(let v)? = self.messageOneof else { preconditionFailure() }
423 + try visitor.visitSingularMessageField(value: v, fieldNumber: 12)
424 + }()
425 + case nil: break
426 + }
427 + try unknownFields.traverse(visitor: &visitor)
428 + }
429 +
430 + public static func ==(lhs: TW_Algorand_Proto_SigningInput, rhs: TW_Algorand_Proto_SigningInput) -> Bool {
431 + if lhs.genesisID != rhs.genesisID {return false}
432 + if lhs.genesisHash != rhs.genesisHash {return false}
433 + if lhs.note != rhs.note {return false}
434 + if lhs.privateKey != rhs.privateKey {return false}
435 + if lhs.firstRound != rhs.firstRound {return false}
436 + if lhs.lastRound != rhs.lastRound {return false}
437 + if lhs.fee != rhs.fee {return false}
438 + if lhs.publicKey != rhs.publicKey {return false}
439 + if lhs.messageOneof != rhs.messageOneof {return false}
440 + if lhs.unknownFields != rhs.unknownFields {return false}
441 + return true
442 + }
443 +}
444 +
445 +extension TW_Algorand_Proto_SigningOutput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
446 + public static let protoMessageName: String = _protobuf_package + ".SigningOutput"
447 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
448 + 1: .same(proto: "encoded"),
449 + 2: .same(proto: "signature"),
450 + 3: .same(proto: "error"),
451 + 4: .standard(proto: "error_message"),
452 + ]
453 +
454 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
455 + while let fieldNumber = try decoder.nextFieldNumber() {
456 + // The use of inline closures is to circumvent an issue where the compiler
457 + // allocates stack space for every case branch when no optimizations are
458 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
459 + switch fieldNumber {
460 + case 1: try { try decoder.decodeSingularBytesField(value: &self.encoded) }()
461 + case 2: try { try decoder.decodeSingularStringField(value: &self.signature) }()
462 + case 3: try { try decoder.decodeSingularEnumField(value: &self.error) }()
463 + case 4: try { try decoder.decodeSingularStringField(value: &self.errorMessage) }()
464 + default: break
465 + }
466 + }
467 + }
468 +
469 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
470 + if !self.encoded.isEmpty {
471 + try visitor.visitSingularBytesField(value: self.encoded, fieldNumber: 1)
472 + }
473 + if !self.signature.isEmpty {
474 + try visitor.visitSingularStringField(value: self.signature, fieldNumber: 2)
475 + }
476 + if self.error != .ok {
477 + try visitor.visitSingularEnumField(value: self.error, fieldNumber: 3)
478 + }
479 + if !self.errorMessage.isEmpty {
480 + try visitor.visitSingularStringField(value: self.errorMessage, fieldNumber: 4)
481 + }
482 + try unknownFields.traverse(visitor: &visitor)
483 + }
484 +
485 + public static func ==(lhs: TW_Algorand_Proto_SigningOutput, rhs: TW_Algorand_Proto_SigningOutput) -> Bool {
486 + if lhs.encoded != rhs.encoded {return false}
487 + if lhs.signature != rhs.signature {return false}
488 + if lhs.error != rhs.error {return false}
489 + if lhs.errorMessage != rhs.errorMessage {return false}
490 + if lhs.unknownFields != rhs.unknownFields {return false}
491 + return true
492 + }
493 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Aptos+Proto.swift +23 −0
@@ -0,0 +1,23 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public typealias AptosTransferMessage = TW_Aptos_Proto_TransferMessage
8 +public typealias AptosStructTag = TW_Aptos_Proto_StructTag
9 +public typealias AptosTokenTransferMessage = TW_Aptos_Proto_TokenTransferMessage
10 +public typealias AptosTokenTransferCoinsMessage = TW_Aptos_Proto_TokenTransferCoinsMessage
11 +public typealias AptosFungibleAssetTransferMessage = TW_Aptos_Proto_FungibleAssetTransferMessage
12 +public typealias AptosCreateAccountMessage = TW_Aptos_Proto_CreateAccountMessage
13 +public typealias AptosOfferNftMessage = TW_Aptos_Proto_OfferNftMessage
14 +public typealias AptosCancelOfferNftMessage = TW_Aptos_Proto_CancelOfferNftMessage
15 +public typealias AptosClaimNftMessage = TW_Aptos_Proto_ClaimNftMessage
16 +public typealias AptosTortugaClaim = TW_Aptos_Proto_TortugaClaim
17 +public typealias AptosTortugaStake = TW_Aptos_Proto_TortugaStake
18 +public typealias AptosTortugaUnstake = TW_Aptos_Proto_TortugaUnstake
19 +public typealias AptosLiquidStaking = TW_Aptos_Proto_LiquidStaking
20 +public typealias AptosNftMessage = TW_Aptos_Proto_NftMessage
21 +public typealias AptosSigningInput = TW_Aptos_Proto_SigningInput
22 +public typealias AptosTransactionAuthenticator = TW_Aptos_Proto_TransactionAuthenticator
23 +public typealias AptosSigningOutput = TW_Aptos_Proto_SigningOutput
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Aptos.pb.swift +1636 −0
@@ -0,0 +1,1636 @@
1 +import WalletCoreC
2 +import Foundation
3 +// DO NOT EDIT.
4 +// swift-format-ignore-file
5 +//
6 +// Generated by the Swift generator plugin for the protocol buffer compiler.
7 +// Source: Aptos.proto
8 +//
9 +// For information on using the generated types, please see the documentation:
10 +// https://github.com/apple/swift-protobuf/
11 +
12 +// SPDX-License-Identifier: Apache-2.0
13 +//
14 +// Copyright © 2017 Trust Wallet.
15 +
16 +import Foundation
17 +import SwiftProtobuf
18 +
19 +// If the compiler emits an error on this type, it is because this file
20 +// was generated by a version of the `protoc` Swift plug-in that is
21 +// incompatible with the version of SwiftProtobuf.to which you are linking.
22 +// Please ensure that you are building against the same version of the API
23 +// that was used to generate this file.
24 +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
25 + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
26 + typealias Version = _2
27 +}
28 +
29 +/// Necessary fields to process a TransferMessage
30 +public struct TW_Aptos_Proto_TransferMessage {
31 + // SwiftProtobuf.Message conformance is added in an extension below. See the
32 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
33 + // methods supported on all messages.
34 +
35 + /// Destination Account address (string)
36 + public var to: String = String()
37 +
38 + /// Amount to be transferred (uint64)
39 + public var amount: UInt64 = 0
40 +
41 + public var unknownFields = SwiftProtobuf.UnknownStorage()
42 +
43 + public init() {}
44 +}
45 +
46 +/// Necessary tag for type function argument
47 +public struct TW_Aptos_Proto_StructTag {
48 + // SwiftProtobuf.Message conformance is added in an extension below. See the
49 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
50 + // methods supported on all messages.
51 +
52 + /// Address of the account
53 + public var accountAddress: String = String()
54 +
55 + /// Module name
56 + public var module: String = String()
57 +
58 + /// Identifier
59 + public var name: String = String()
60 +
61 + public var unknownFields = SwiftProtobuf.UnknownStorage()
62 +
63 + public init() {}
64 +}
65 +
66 +/// Necessary fields to process a `0x1::coin::transfer` function.
67 +public struct TW_Aptos_Proto_TokenTransferMessage {
68 + // SwiftProtobuf.Message conformance is added in an extension below. See the
69 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
70 + // methods supported on all messages.
71 +
72 + /// Destination Account address (string)
73 + public var to: String = String()
74 +
75 + /// Amount to be transferred (uint64)
76 + public var amount: UInt64 = 0
77 +
78 + /// token function to call, e.g BTC: 0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC
79 + public var function: TW_Aptos_Proto_StructTag {
80 + get {return _function ?? TW_Aptos_Proto_StructTag()}
81 + set {_function = newValue}
82 + }
83 + /// Returns true if `function` has been explicitly set.
84 + public var hasFunction: Bool {return self._function != nil}
85 + /// Clears the value of `function`. Subsequent reads from it will return its default value.
86 + public mutating func clearFunction() {self._function = nil}
87 +
88 + public var unknownFields = SwiftProtobuf.UnknownStorage()
89 +
90 + public init() {}
91 +
92 + fileprivate var _function: TW_Aptos_Proto_StructTag? = nil
93 +}
94 +
95 +/// Necessary fields to process a `0x1::aptos_account::transfer_coins` function.
96 +/// Can be used to transfer tokens with registering the recipient account if needed.
97 +public struct TW_Aptos_Proto_TokenTransferCoinsMessage {
98 + // SwiftProtobuf.Message conformance is added in an extension below. See the
99 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
100 + // methods supported on all messages.
101 +
102 + /// Destination Account address (string)
103 + public var to: String = String()
104 +
105 + /// Amount to be transferred (uint64)
106 + public var amount: UInt64 = 0
107 +
108 + /// token function to call, e.g BTC: 0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC
109 + public var function: TW_Aptos_Proto_StructTag {
110 + get {return _function ?? TW_Aptos_Proto_StructTag()}
111 + set {_function = newValue}
112 + }
113 + /// Returns true if `function` has been explicitly set.
114 + public var hasFunction: Bool {return self._function != nil}
115 + /// Clears the value of `function`. Subsequent reads from it will return its default value.
116 + public mutating func clearFunction() {self._function = nil}
117 +
118 + public var unknownFields = SwiftProtobuf.UnknownStorage()
119 +
120 + public init() {}
121 +
122 + fileprivate var _function: TW_Aptos_Proto_StructTag? = nil
123 +}
124 +
125 +public struct TW_Aptos_Proto_FungibleAssetTransferMessage {
126 + // SwiftProtobuf.Message conformance is added in an extension below. See the
127 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
128 + // methods supported on all messages.
129 +
130 + /// Fungible Asset address (string)
131 + public var metadataAddress: String = String()
132 +
133 + /// Destination Account address (string)
134 + public var to: String = String()
135 +
136 + /// Amount to be transferred (uint64)
137 + public var amount: UInt64 = 0
138 +
139 + public var unknownFields = SwiftProtobuf.UnknownStorage()
140 +
141 + public init() {}
142 +}
143 +
144 +/// Necessary fields to process a CreateAccountMessage
145 +public struct TW_Aptos_Proto_CreateAccountMessage {
146 + // SwiftProtobuf.Message conformance is added in an extension below. See the
147 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
148 + // methods supported on all messages.
149 +
150 + /// auth account address to create
151 + public var authKey: String = String()
152 +
153 + public var unknownFields = SwiftProtobuf.UnknownStorage()
154 +
155 + public init() {}
156 +}
157 +
158 +/// Necessary fields to process an OfferNftMessage
159 +public struct TW_Aptos_Proto_OfferNftMessage {
160 + // SwiftProtobuf.Message conformance is added in an extension below. See the
161 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
162 + // methods supported on all messages.
163 +
164 + /// Receiver address
165 + public var receiver: String = String()
166 +
167 + /// Creator address
168 + public var creator: String = String()
169 +
170 + /// Name of the collection
171 + public var collectionName: String = String()
172 +
173 + /// Name of the NFT
174 + public var name: String = String()
175 +
176 + /// Property version (should be often 0)
177 + public var propertyVersion: UInt64 = 0
178 +
179 + /// Amount of NFT's to transfer (should be often 1)
180 + public var amount: UInt64 = 0
181 +
182 + public var unknownFields = SwiftProtobuf.UnknownStorage()
183 +
184 + public init() {}
185 +}
186 +
187 +/// Necessary fields to process an CancelOfferNftMessage
188 +public struct TW_Aptos_Proto_CancelOfferNftMessage {
189 + // SwiftProtobuf.Message conformance is added in an extension below. See the
190 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
191 + // methods supported on all messages.
192 +
193 + /// Receiver address
194 + public var receiver: String = String()
195 +
196 + /// Creator address
197 + public var creator: String = String()
198 +
199 + /// Name of the collection
200 + public var collectionName: String = String()
201 +
202 + /// Name of the NFT
203 + public var name: String = String()
204 +
205 + /// Property version (should be often 0)
206 + public var propertyVersion: UInt64 = 0
207 +
208 + public var unknownFields = SwiftProtobuf.UnknownStorage()
209 +
210 + public init() {}
211 +}
212 +
213 +/// Necessary fields to process an ClaimNftMessage
214 +public struct TW_Aptos_Proto_ClaimNftMessage {
215 + // SwiftProtobuf.Message conformance is added in an extension below. See the
216 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
217 + // methods supported on all messages.
218 +
219 + /// Sender address
220 + public var sender: String = String()
221 +
222 + /// Creator address
223 + public var creator: String = String()
224 +
225 + /// Name of the collection
226 + public var collectionName: String = String()
227 +
228 + /// Name of the NFT
229 + public var name: String = String()
230 +
231 + /// Property version (should be often 0)
232 + public var propertyVersion: UInt64 = 0
233 +
234 + public var unknownFields = SwiftProtobuf.UnknownStorage()
235 +
236 + public init() {}
237 +}
238 +
239 +public struct TW_Aptos_Proto_TortugaClaim {
240 + // SwiftProtobuf.Message conformance is added in an extension below. See the
241 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
242 + // methods supported on all messages.
243 +
244 + /// idx of ticket to claim
245 + public var idx: UInt64 = 0
246 +
247 + public var unknownFields = SwiftProtobuf.UnknownStorage()
248 +
249 + public init() {}
250 +}
251 +
252 +public struct TW_Aptos_Proto_TortugaStake {
253 + // SwiftProtobuf.Message conformance is added in an extension below. See the
254 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
255 + // methods supported on all messages.
256 +
257 + /// Amount to be stake
258 + public var amount: UInt64 = 0
259 +
260 + public var unknownFields = SwiftProtobuf.UnknownStorage()
261 +
262 + public init() {}
263 +}
264 +
265 +public struct TW_Aptos_Proto_TortugaUnstake {
266 + // SwiftProtobuf.Message conformance is added in an extension below. See the
267 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
268 + // methods supported on all messages.
269 +
270 + /// Amount to be stake
271 + public var amount: UInt64 = 0
272 +
273 + public var unknownFields = SwiftProtobuf.UnknownStorage()
274 +
275 + public init() {}
276 +}
277 +
278 +public struct TW_Aptos_Proto_LiquidStaking {
279 + // SwiftProtobuf.Message conformance is added in an extension below. See the
280 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
281 + // methods supported on all messages.
282 +
283 + /// Smart contract address of liquid staking module
284 + public var smartContractAddress: String = String()
285 +
286 + public var liquidStakeTransactionPayload: TW_Aptos_Proto_LiquidStaking.OneOf_LiquidStakeTransactionPayload? = nil
287 +
288 + public var stake: TW_Aptos_Proto_TortugaStake {
289 + get {
290 + if case .stake(let v)? = liquidStakeTransactionPayload {return v}
291 + return TW_Aptos_Proto_TortugaStake()
292 + }
293 + set {liquidStakeTransactionPayload = .stake(newValue)}
294 + }
295 +
296 + public var unstake: TW_Aptos_Proto_TortugaUnstake {
297 + get {
298 + if case .unstake(let v)? = liquidStakeTransactionPayload {return v}
299 + return TW_Aptos_Proto_TortugaUnstake()
300 + }
301 + set {liquidStakeTransactionPayload = .unstake(newValue)}
302 + }
303 +
304 + public var claim: TW_Aptos_Proto_TortugaClaim {
305 + get {
306 + if case .claim(let v)? = liquidStakeTransactionPayload {return v}
307 + return TW_Aptos_Proto_TortugaClaim()
308 + }
309 + set {liquidStakeTransactionPayload = .claim(newValue)}
310 + }
311 +
312 + public var unknownFields = SwiftProtobuf.UnknownStorage()
313 +
314 + public enum OneOf_LiquidStakeTransactionPayload: Equatable {
315 + case stake(TW_Aptos_Proto_TortugaStake)
316 + case unstake(TW_Aptos_Proto_TortugaUnstake)
317 + case claim(TW_Aptos_Proto_TortugaClaim)
318 +
319 + #if !swift(>=4.1)
320 + public static func ==(lhs: TW_Aptos_Proto_LiquidStaking.OneOf_LiquidStakeTransactionPayload, rhs: TW_Aptos_Proto_LiquidStaking.OneOf_LiquidStakeTransactionPayload) -> Bool {
321 + // The use of inline closures is to circumvent an issue where the compiler
322 + // allocates stack space for every case branch when no optimizations are
323 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
324 + switch (lhs, rhs) {
325 + case (.stake, .stake): return {
326 + guard case .stake(let l) = lhs, case .stake(let r) = rhs else { preconditionFailure() }
327 + return l == r
328 + }()
329 + case (.unstake, .unstake): return {
330 + guard case .unstake(let l) = lhs, case .unstake(let r) = rhs else { preconditionFailure() }
331 + return l == r
332 + }()
333 + case (.claim, .claim): return {
334 + guard case .claim(let l) = lhs, case .claim(let r) = rhs else { preconditionFailure() }
335 + return l == r
336 + }()
337 + default: return false
338 + }
339 + }
340 + #endif
341 + }
342 +
343 + public init() {}
344 +}
345 +
346 +public struct TW_Aptos_Proto_NftMessage {
347 + // SwiftProtobuf.Message conformance is added in an extension below. See the
348 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
349 + // methods supported on all messages.
350 +
351 + public var nftTransactionPayload: TW_Aptos_Proto_NftMessage.OneOf_NftTransactionPayload? = nil
352 +
353 + public var offerNft: TW_Aptos_Proto_OfferNftMessage {
354 + get {
355 + if case .offerNft(let v)? = nftTransactionPayload {return v}
356 + return TW_Aptos_Proto_OfferNftMessage()
357 + }
358 + set {nftTransactionPayload = .offerNft(newValue)}
359 + }
360 +
361 + public var cancelOfferNft: TW_Aptos_Proto_CancelOfferNftMessage {
362 + get {
363 + if case .cancelOfferNft(let v)? = nftTransactionPayload {return v}
364 + return TW_Aptos_Proto_CancelOfferNftMessage()
365 + }
366 + set {nftTransactionPayload = .cancelOfferNft(newValue)}
367 + }
368 +
369 + public var claimNft: TW_Aptos_Proto_ClaimNftMessage {
370 + get {
371 + if case .claimNft(let v)? = nftTransactionPayload {return v}
372 + return TW_Aptos_Proto_ClaimNftMessage()
373 + }
374 + set {nftTransactionPayload = .claimNft(newValue)}
375 + }
376 +
377 + public var unknownFields = SwiftProtobuf.UnknownStorage()
378 +
379 + public enum OneOf_NftTransactionPayload: Equatable {
380 + case offerNft(TW_Aptos_Proto_OfferNftMessage)
381 + case cancelOfferNft(TW_Aptos_Proto_CancelOfferNftMessage)
382 + case claimNft(TW_Aptos_Proto_ClaimNftMessage)
383 +
384 + #if !swift(>=4.1)
385 + public static func ==(lhs: TW_Aptos_Proto_NftMessage.OneOf_NftTransactionPayload, rhs: TW_Aptos_Proto_NftMessage.OneOf_NftTransactionPayload) -> Bool {
386 + // The use of inline closures is to circumvent an issue where the compiler
387 + // allocates stack space for every case branch when no optimizations are
388 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
389 + switch (lhs, rhs) {
390 + case (.offerNft, .offerNft): return {
391 + guard case .offerNft(let l) = lhs, case .offerNft(let r) = rhs else { preconditionFailure() }
392 + return l == r
393 + }()
394 + case (.cancelOfferNft, .cancelOfferNft): return {
395 + guard case .cancelOfferNft(let l) = lhs, case .cancelOfferNft(let r) = rhs else { preconditionFailure() }
396 + return l == r
397 + }()
398 + case (.claimNft, .claimNft): return {
399 + guard case .claimNft(let l) = lhs, case .claimNft(let r) = rhs else { preconditionFailure() }
400 + return l == r
401 + }()
402 + default: return false
403 + }
404 + }
405 + #endif
406 + }
407 +
408 + public init() {}
409 +}
410 +
411 +/// Input data necessary to create a signed transaction.
412 +public struct TW_Aptos_Proto_SigningInput {
413 + // SwiftProtobuf.Message conformance is added in an extension below. See the
414 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
415 + // methods supported on all messages.
416 +
417 + /// Sender Account address (string)
418 + public var sender: String = String()
419 +
420 + /// Sequence number, incremented atomically for each tx present on the account, start at 0 (int64)
421 + public var sequenceNumber: Int64 = 0
422 +
423 + /// Max gas amount that the user is willing to pay (uint64)
424 + public var maxGasAmount: UInt64 = 0
425 +
426 + /// Gas unit price - queried through API (uint64)
427 + public var gasUnitPrice: UInt64 = 0
428 +
429 + /// Expiration timestamp for the transaction, can't be in the past (uint64)
430 + public var expirationTimestampSecs: UInt64 = 0
431 +
432 + /// Chain id 1 (mainnet) 32(devnet) (uint32 - casted in uint8_t later)
433 + public var chainID: UInt32 = 0
434 +
435 + /// Private key to sign the transaction (bytes)
436 + public var privateKey: Data = Data()
437 +
438 + /// hex encoded function to sign, use it for smart contract approval (string)
439 + public var anyEncoded: String = String()
440 +
441 + public var transactionPayload: TW_Aptos_Proto_SigningInput.OneOf_TransactionPayload? = nil
442 +
443 + public var transfer: TW_Aptos_Proto_TransferMessage {
444 + get {
445 + if case .transfer(let v)? = transactionPayload {return v}
446 + return TW_Aptos_Proto_TransferMessage()
447 + }
448 + set {transactionPayload = .transfer(newValue)}
449 + }
450 +
451 + public var tokenTransfer: TW_Aptos_Proto_TokenTransferMessage {
452 + get {
453 + if case .tokenTransfer(let v)? = transactionPayload {return v}
454 + return TW_Aptos_Proto_TokenTransferMessage()
455 + }
456 + set {transactionPayload = .tokenTransfer(newValue)}
457 + }
458 +
459 + public var createAccount: TW_Aptos_Proto_CreateAccountMessage {
460 + get {
461 + if case .createAccount(let v)? = transactionPayload {return v}
462 + return TW_Aptos_Proto_CreateAccountMessage()
463 + }
464 + set {transactionPayload = .createAccount(newValue)}
465 + }
466 +
467 + public var nftMessage: TW_Aptos_Proto_NftMessage {
468 + get {
469 + if case .nftMessage(let v)? = transactionPayload {return v}
470 + return TW_Aptos_Proto_NftMessage()
471 + }
472 + set {transactionPayload = .nftMessage(newValue)}
473 + }
474 +
475 + public var liquidStakingMessage: TW_Aptos_Proto_LiquidStaking {
476 + get {
477 + if case .liquidStakingMessage(let v)? = transactionPayload {return v}
478 + return TW_Aptos_Proto_LiquidStaking()
479 + }
480 + set {transactionPayload = .liquidStakingMessage(newValue)}
481 + }
482 +
483 + public var tokenTransferCoins: TW_Aptos_Proto_TokenTransferCoinsMessage {
484 + get {
485 + if case .tokenTransferCoins(let v)? = transactionPayload {return v}
486 + return TW_Aptos_Proto_TokenTransferCoinsMessage()
487 + }
488 + set {transactionPayload = .tokenTransferCoins(newValue)}
489 + }
490 +
491 + public var fungibleAssetTransfer: TW_Aptos_Proto_FungibleAssetTransferMessage {
492 + get {
493 + if case .fungibleAssetTransfer(let v)? = transactionPayload {return v}
494 + return TW_Aptos_Proto_FungibleAssetTransferMessage()
495 + }
496 + set {transactionPayload = .fungibleAssetTransfer(newValue)}
497 + }
498 +
499 + public var abi: String = String()
500 +
501 + public var unknownFields = SwiftProtobuf.UnknownStorage()
502 +
503 + public enum OneOf_TransactionPayload: Equatable {
504 + case transfer(TW_Aptos_Proto_TransferMessage)
505 + case tokenTransfer(TW_Aptos_Proto_TokenTransferMessage)
506 + case createAccount(TW_Aptos_Proto_CreateAccountMessage)
507 + case nftMessage(TW_Aptos_Proto_NftMessage)
508 + case liquidStakingMessage(TW_Aptos_Proto_LiquidStaking)
509 + case tokenTransferCoins(TW_Aptos_Proto_TokenTransferCoinsMessage)
510 + case fungibleAssetTransfer(TW_Aptos_Proto_FungibleAssetTransferMessage)
511 +
512 + #if !swift(>=4.1)
513 + public static func ==(lhs: TW_Aptos_Proto_SigningInput.OneOf_TransactionPayload, rhs: TW_Aptos_Proto_SigningInput.OneOf_TransactionPayload) -> Bool {
514 + // The use of inline closures is to circumvent an issue where the compiler
515 + // allocates stack space for every case branch when no optimizations are
516 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
517 + switch (lhs, rhs) {
518 + case (.transfer, .transfer): return {
519 + guard case .transfer(let l) = lhs, case .transfer(let r) = rhs else { preconditionFailure() }
520 + return l == r
521 + }()
522 + case (.tokenTransfer, .tokenTransfer): return {
523 + guard case .tokenTransfer(let l) = lhs, case .tokenTransfer(let r) = rhs else { preconditionFailure() }
524 + return l == r
525 + }()
526 + case (.createAccount, .createAccount): return {
527 + guard case .createAccount(let l) = lhs, case .createAccount(let r) = rhs else { preconditionFailure() }
528 + return l == r
529 + }()
530 + case (.nftMessage, .nftMessage): return {
531 + guard case .nftMessage(let l) = lhs, case .nftMessage(let r) = rhs else { preconditionFailure() }
532 + return l == r
533 + }()
534 + case (.liquidStakingMessage, .liquidStakingMessage): return {
535 + guard case .liquidStakingMessage(let l) = lhs, case .liquidStakingMessage(let r) = rhs else { preconditionFailure() }
536 + return l == r
537 + }()
538 + case (.tokenTransferCoins, .tokenTransferCoins): return {
539 + guard case .tokenTransferCoins(let l) = lhs, case .tokenTransferCoins(let r) = rhs else { preconditionFailure() }
540 + return l == r
541 + }()
542 + case (.fungibleAssetTransfer, .fungibleAssetTransfer): return {
543 + guard case .fungibleAssetTransfer(let l) = lhs, case .fungibleAssetTransfer(let r) = rhs else { preconditionFailure() }
544 + return l == r
545 + }()
546 + default: return false
547 + }
548 + }
549 + #endif
550 + }
551 +
552 + public init() {}
553 +}
554 +
555 +/// Information related to the signed transaction
556 +public struct TW_Aptos_Proto_TransactionAuthenticator {
557 + // SwiftProtobuf.Message conformance is added in an extension below. See the
558 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
559 + // methods supported on all messages.
560 +
561 + /// Signature part of the signed transaction (bytes)
562 + public var signature: Data = Data()
563 +
564 + /// Public key of the signer (bytes)
565 + public var publicKey: Data = Data()
566 +
567 + public var unknownFields = SwiftProtobuf.UnknownStorage()
568 +
569 + public init() {}
570 +}
571 +
572 +/// Transaction signing output.
573 +public struct TW_Aptos_Proto_SigningOutput {
574 + // SwiftProtobuf.Message conformance is added in an extension below. See the
575 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
576 + // methods supported on all messages.
577 +
578 + //// The raw transaction (bytes)
579 + public var rawTxn: Data = Data()
580 +
581 + //// Public key and signature to authenticate
582 + public var authenticator: TW_Aptos_Proto_TransactionAuthenticator {
583 + get {return _authenticator ?? TW_Aptos_Proto_TransactionAuthenticator()}
584 + set {_authenticator = newValue}
585 + }
586 + /// Returns true if `authenticator` has been explicitly set.
587 + public var hasAuthenticator: Bool {return self._authenticator != nil}
588 + /// Clears the value of `authenticator`. Subsequent reads from it will return its default value.
589 + public mutating func clearAuthenticator() {self._authenticator = nil}
590 +
591 + //// Signed and encoded transaction bytes.
592 + public var encoded: Data = Data()
593 +
594 + /// Transaction json format for api broadcasting (string)
595 + public var json: String = String()
596 +
597 + /// Error code, 0 is ok, other codes will be treated as errors.
598 + public var error: TW_Common_Proto_SigningError = .ok
599 +
600 + /// Error description.
601 + public var errorMessage: String = String()
602 +
603 + public var unknownFields = SwiftProtobuf.UnknownStorage()
604 +
605 + public init() {}
606 +
607 + fileprivate var _authenticator: TW_Aptos_Proto_TransactionAuthenticator? = nil
608 +}
609 +
610 +// MARK: - Code below here is support for the SwiftProtobuf.runtime.
611 +
612 +fileprivate let _protobuf_package = "TW.Aptos.Proto"
613 +
614 +extension TW_Aptos_Proto_TransferMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
615 + public static let protoMessageName: String = _protobuf_package + ".TransferMessage"
616 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
617 + 1: .same(proto: "to"),
618 + 2: .same(proto: "amount"),
619 + ]
620 +
621 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
622 + while let fieldNumber = try decoder.nextFieldNumber() {
623 + // The use of inline closures is to circumvent an issue where the compiler
624 + // allocates stack space for every case branch when no optimizations are
625 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
626 + switch fieldNumber {
627 + case 1: try { try decoder.decodeSingularStringField(value: &self.to) }()
628 + case 2: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
629 + default: break
630 + }
631 + }
632 + }
633 +
634 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
635 + if !self.to.isEmpty {
636 + try visitor.visitSingularStringField(value: self.to, fieldNumber: 1)
637 + }
638 + if self.amount != 0 {
639 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 2)
640 + }
641 + try unknownFields.traverse(visitor: &visitor)
642 + }
643 +
644 + public static func ==(lhs: TW_Aptos_Proto_TransferMessage, rhs: TW_Aptos_Proto_TransferMessage) -> Bool {
645 + if lhs.to != rhs.to {return false}
646 + if lhs.amount != rhs.amount {return false}
647 + if lhs.unknownFields != rhs.unknownFields {return false}
648 + return true
649 + }
650 +}
651 +
652 +extension TW_Aptos_Proto_StructTag: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
653 + public static let protoMessageName: String = _protobuf_package + ".StructTag"
654 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
655 + 1: .standard(proto: "account_address"),
656 + 2: .same(proto: "module"),
657 + 3: .same(proto: "name"),
658 + ]
659 +
660 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
661 + while let fieldNumber = try decoder.nextFieldNumber() {
662 + // The use of inline closures is to circumvent an issue where the compiler
663 + // allocates stack space for every case branch when no optimizations are
664 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
665 + switch fieldNumber {
666 + case 1: try { try decoder.decodeSingularStringField(value: &self.accountAddress) }()
667 + case 2: try { try decoder.decodeSingularStringField(value: &self.module) }()
668 + case 3: try { try decoder.decodeSingularStringField(value: &self.name) }()
669 + default: break
670 + }
671 + }
672 + }
673 +
674 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
675 + if !self.accountAddress.isEmpty {
676 + try visitor.visitSingularStringField(value: self.accountAddress, fieldNumber: 1)
677 + }
678 + if !self.module.isEmpty {
679 + try visitor.visitSingularStringField(value: self.module, fieldNumber: 2)
680 + }
681 + if !self.name.isEmpty {
682 + try visitor.visitSingularStringField(value: self.name, fieldNumber: 3)
683 + }
684 + try unknownFields.traverse(visitor: &visitor)
685 + }
686 +
687 + public static func ==(lhs: TW_Aptos_Proto_StructTag, rhs: TW_Aptos_Proto_StructTag) -> Bool {
688 + if lhs.accountAddress != rhs.accountAddress {return false}
689 + if lhs.module != rhs.module {return false}
690 + if lhs.name != rhs.name {return false}
691 + if lhs.unknownFields != rhs.unknownFields {return false}
692 + return true
693 + }
694 +}
695 +
696 +extension TW_Aptos_Proto_TokenTransferMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
697 + public static let protoMessageName: String = _protobuf_package + ".TokenTransferMessage"
698 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
699 + 1: .same(proto: "to"),
700 + 2: .same(proto: "amount"),
701 + 3: .same(proto: "function"),
702 + ]
703 +
704 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
705 + while let fieldNumber = try decoder.nextFieldNumber() {
706 + // The use of inline closures is to circumvent an issue where the compiler
707 + // allocates stack space for every case branch when no optimizations are
708 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
709 + switch fieldNumber {
710 + case 1: try { try decoder.decodeSingularStringField(value: &self.to) }()
711 + case 2: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
712 + case 3: try { try decoder.decodeSingularMessageField(value: &self._function) }()
713 + default: break
714 + }
715 + }
716 + }
717 +
718 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
719 + // The use of inline closures is to circumvent an issue where the compiler
720 + // allocates stack space for every if/case branch local when no optimizations
721 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
722 + // https://github.com/apple/swift-protobuf/issues/1182
723 + if !self.to.isEmpty {
724 + try visitor.visitSingularStringField(value: self.to, fieldNumber: 1)
725 + }
726 + if self.amount != 0 {
727 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 2)
728 + }
729 + try { if let v = self._function {
730 + try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
731 + } }()
732 + try unknownFields.traverse(visitor: &visitor)
733 + }
734 +
735 + public static func ==(lhs: TW_Aptos_Proto_TokenTransferMessage, rhs: TW_Aptos_Proto_TokenTransferMessage) -> Bool {
736 + if lhs.to != rhs.to {return false}
737 + if lhs.amount != rhs.amount {return false}
738 + if lhs._function != rhs._function {return false}
739 + if lhs.unknownFields != rhs.unknownFields {return false}
740 + return true
741 + }
742 +}
743 +
744 +extension TW_Aptos_Proto_TokenTransferCoinsMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
745 + public static let protoMessageName: String = _protobuf_package + ".TokenTransferCoinsMessage"
746 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
747 + 1: .same(proto: "to"),
748 + 2: .same(proto: "amount"),
749 + 3: .same(proto: "function"),
750 + ]
751 +
752 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
753 + while let fieldNumber = try decoder.nextFieldNumber() {
754 + // The use of inline closures is to circumvent an issue where the compiler
755 + // allocates stack space for every case branch when no optimizations are
756 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
757 + switch fieldNumber {
758 + case 1: try { try decoder.decodeSingularStringField(value: &self.to) }()
759 + case 2: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
760 + case 3: try { try decoder.decodeSingularMessageField(value: &self._function) }()
761 + default: break
762 + }
763 + }
764 + }
765 +
766 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
767 + // The use of inline closures is to circumvent an issue where the compiler
768 + // allocates stack space for every if/case branch local when no optimizations
769 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
770 + // https://github.com/apple/swift-protobuf/issues/1182
771 + if !self.to.isEmpty {
772 + try visitor.visitSingularStringField(value: self.to, fieldNumber: 1)
773 + }
774 + if self.amount != 0 {
775 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 2)
776 + }
777 + try { if let v = self._function {
778 + try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
779 + } }()
780 + try unknownFields.traverse(visitor: &visitor)
781 + }
782 +
783 + public static func ==(lhs: TW_Aptos_Proto_TokenTransferCoinsMessage, rhs: TW_Aptos_Proto_TokenTransferCoinsMessage) -> Bool {
784 + if lhs.to != rhs.to {return false}
785 + if lhs.amount != rhs.amount {return false}
786 + if lhs._function != rhs._function {return false}
787 + if lhs.unknownFields != rhs.unknownFields {return false}
788 + return true
789 + }
790 +}
791 +
792 +extension TW_Aptos_Proto_FungibleAssetTransferMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
793 + public static let protoMessageName: String = _protobuf_package + ".FungibleAssetTransferMessage"
794 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
795 + 1: .standard(proto: "metadata_address"),
796 + 2: .same(proto: "to"),
797 + 3: .same(proto: "amount"),
798 + ]
799 +
800 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
801 + while let fieldNumber = try decoder.nextFieldNumber() {
802 + // The use of inline closures is to circumvent an issue where the compiler
803 + // allocates stack space for every case branch when no optimizations are
804 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
805 + switch fieldNumber {
806 + case 1: try { try decoder.decodeSingularStringField(value: &self.metadataAddress) }()
807 + case 2: try { try decoder.decodeSingularStringField(value: &self.to) }()
808 + case 3: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
809 + default: break
810 + }
811 + }
812 + }
813 +
814 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
815 + if !self.metadataAddress.isEmpty {
816 + try visitor.visitSingularStringField(value: self.metadataAddress, fieldNumber: 1)
817 + }
818 + if !self.to.isEmpty {
819 + try visitor.visitSingularStringField(value: self.to, fieldNumber: 2)
820 + }
821 + if self.amount != 0 {
822 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 3)
823 + }
824 + try unknownFields.traverse(visitor: &visitor)
825 + }
826 +
827 + public static func ==(lhs: TW_Aptos_Proto_FungibleAssetTransferMessage, rhs: TW_Aptos_Proto_FungibleAssetTransferMessage) -> Bool {
828 + if lhs.metadataAddress != rhs.metadataAddress {return false}
829 + if lhs.to != rhs.to {return false}
830 + if lhs.amount != rhs.amount {return false}
831 + if lhs.unknownFields != rhs.unknownFields {return false}
832 + return true
833 + }
834 +}
835 +
836 +extension TW_Aptos_Proto_CreateAccountMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
837 + public static let protoMessageName: String = _protobuf_package + ".CreateAccountMessage"
838 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
839 + 1: .standard(proto: "auth_key"),
840 + ]
841 +
842 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
843 + while let fieldNumber = try decoder.nextFieldNumber() {
844 + // The use of inline closures is to circumvent an issue where the compiler
845 + // allocates stack space for every case branch when no optimizations are
846 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
847 + switch fieldNumber {
848 + case 1: try { try decoder.decodeSingularStringField(value: &self.authKey) }()
849 + default: break
850 + }
851 + }
852 + }
853 +
854 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
855 + if !self.authKey.isEmpty {
856 + try visitor.visitSingularStringField(value: self.authKey, fieldNumber: 1)
857 + }
858 + try unknownFields.traverse(visitor: &visitor)
859 + }
860 +
861 + public static func ==(lhs: TW_Aptos_Proto_CreateAccountMessage, rhs: TW_Aptos_Proto_CreateAccountMessage) -> Bool {
862 + if lhs.authKey != rhs.authKey {return false}
863 + if lhs.unknownFields != rhs.unknownFields {return false}
864 + return true
865 + }
866 +}
867 +
868 +extension TW_Aptos_Proto_OfferNftMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
869 + public static let protoMessageName: String = _protobuf_package + ".OfferNftMessage"
870 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
871 + 1: .same(proto: "receiver"),
872 + 2: .same(proto: "creator"),
873 + 3: .same(proto: "collectionName"),
874 + 4: .same(proto: "name"),
875 + 5: .standard(proto: "property_version"),
876 + 6: .same(proto: "amount"),
877 + ]
878 +
879 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
880 + while let fieldNumber = try decoder.nextFieldNumber() {
881 + // The use of inline closures is to circumvent an issue where the compiler
882 + // allocates stack space for every case branch when no optimizations are
883 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
884 + switch fieldNumber {
885 + case 1: try { try decoder.decodeSingularStringField(value: &self.receiver) }()
886 + case 2: try { try decoder.decodeSingularStringField(value: &self.creator) }()
887 + case 3: try { try decoder.decodeSingularStringField(value: &self.collectionName) }()
888 + case 4: try { try decoder.decodeSingularStringField(value: &self.name) }()
889 + case 5: try { try decoder.decodeSingularUInt64Field(value: &self.propertyVersion) }()
890 + case 6: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
891 + default: break
892 + }
893 + }
894 + }
895 +
896 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
897 + if !self.receiver.isEmpty {
898 + try visitor.visitSingularStringField(value: self.receiver, fieldNumber: 1)
899 + }
900 + if !self.creator.isEmpty {
901 + try visitor.visitSingularStringField(value: self.creator, fieldNumber: 2)
902 + }
903 + if !self.collectionName.isEmpty {
904 + try visitor.visitSingularStringField(value: self.collectionName, fieldNumber: 3)
905 + }
906 + if !self.name.isEmpty {
907 + try visitor.visitSingularStringField(value: self.name, fieldNumber: 4)
908 + }
909 + if self.propertyVersion != 0 {
910 + try visitor.visitSingularUInt64Field(value: self.propertyVersion, fieldNumber: 5)
911 + }
912 + if self.amount != 0 {
913 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 6)
914 + }
915 + try unknownFields.traverse(visitor: &visitor)
916 + }
917 +
918 + public static func ==(lhs: TW_Aptos_Proto_OfferNftMessage, rhs: TW_Aptos_Proto_OfferNftMessage) -> Bool {
919 + if lhs.receiver != rhs.receiver {return false}
920 + if lhs.creator != rhs.creator {return false}
921 + if lhs.collectionName != rhs.collectionName {return false}
922 + if lhs.name != rhs.name {return false}
923 + if lhs.propertyVersion != rhs.propertyVersion {return false}
924 + if lhs.amount != rhs.amount {return false}
925 + if lhs.unknownFields != rhs.unknownFields {return false}
926 + return true
927 + }
928 +}
929 +
930 +extension TW_Aptos_Proto_CancelOfferNftMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
931 + public static let protoMessageName: String = _protobuf_package + ".CancelOfferNftMessage"
932 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
933 + 1: .same(proto: "receiver"),
934 + 2: .same(proto: "creator"),
935 + 3: .same(proto: "collectionName"),
936 + 4: .same(proto: "name"),
937 + 5: .standard(proto: "property_version"),
938 + ]
939 +
940 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
941 + while let fieldNumber = try decoder.nextFieldNumber() {
942 + // The use of inline closures is to circumvent an issue where the compiler
943 + // allocates stack space for every case branch when no optimizations are
944 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
945 + switch fieldNumber {
946 + case 1: try { try decoder.decodeSingularStringField(value: &self.receiver) }()
947 + case 2: try { try decoder.decodeSingularStringField(value: &self.creator) }()
948 + case 3: try { try decoder.decodeSingularStringField(value: &self.collectionName) }()
949 + case 4: try { try decoder.decodeSingularStringField(value: &self.name) }()
950 + case 5: try { try decoder.decodeSingularUInt64Field(value: &self.propertyVersion) }()
951 + default: break
952 + }
953 + }
954 + }
955 +
956 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
957 + if !self.receiver.isEmpty {
958 + try visitor.visitSingularStringField(value: self.receiver, fieldNumber: 1)
959 + }
960 + if !self.creator.isEmpty {
961 + try visitor.visitSingularStringField(value: self.creator, fieldNumber: 2)
962 + }
963 + if !self.collectionName.isEmpty {
964 + try visitor.visitSingularStringField(value: self.collectionName, fieldNumber: 3)
965 + }
966 + if !self.name.isEmpty {
967 + try visitor.visitSingularStringField(value: self.name, fieldNumber: 4)
968 + }
969 + if self.propertyVersion != 0 {
970 + try visitor.visitSingularUInt64Field(value: self.propertyVersion, fieldNumber: 5)
971 + }
972 + try unknownFields.traverse(visitor: &visitor)
973 + }
974 +
975 + public static func ==(lhs: TW_Aptos_Proto_CancelOfferNftMessage, rhs: TW_Aptos_Proto_CancelOfferNftMessage) -> Bool {
976 + if lhs.receiver != rhs.receiver {return false}
977 + if lhs.creator != rhs.creator {return false}
978 + if lhs.collectionName != rhs.collectionName {return false}
979 + if lhs.name != rhs.name {return false}
980 + if lhs.propertyVersion != rhs.propertyVersion {return false}
981 + if lhs.unknownFields != rhs.unknownFields {return false}
982 + return true
983 + }
984 +}
985 +
986 +extension TW_Aptos_Proto_ClaimNftMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
987 + public static let protoMessageName: String = _protobuf_package + ".ClaimNftMessage"
988 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
989 + 1: .same(proto: "sender"),
990 + 2: .same(proto: "creator"),
991 + 3: .same(proto: "collectionName"),
992 + 4: .same(proto: "name"),
993 + 5: .standard(proto: "property_version"),
994 + ]
995 +
996 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
997 + while let fieldNumber = try decoder.nextFieldNumber() {
998 + // The use of inline closures is to circumvent an issue where the compiler
999 + // allocates stack space for every case branch when no optimizations are
1000 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1001 + switch fieldNumber {
1002 + case 1: try { try decoder.decodeSingularStringField(value: &self.sender) }()
1003 + case 2: try { try decoder.decodeSingularStringField(value: &self.creator) }()
1004 + case 3: try { try decoder.decodeSingularStringField(value: &self.collectionName) }()
1005 + case 4: try { try decoder.decodeSingularStringField(value: &self.name) }()
1006 + case 5: try { try decoder.decodeSingularUInt64Field(value: &self.propertyVersion) }()
1007 + default: break
1008 + }
1009 + }
1010 + }
1011 +
1012 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1013 + if !self.sender.isEmpty {
1014 + try visitor.visitSingularStringField(value: self.sender, fieldNumber: 1)
1015 + }
1016 + if !self.creator.isEmpty {
1017 + try visitor.visitSingularStringField(value: self.creator, fieldNumber: 2)
1018 + }
1019 + if !self.collectionName.isEmpty {
1020 + try visitor.visitSingularStringField(value: self.collectionName, fieldNumber: 3)
1021 + }
1022 + if !self.name.isEmpty {
1023 + try visitor.visitSingularStringField(value: self.name, fieldNumber: 4)
1024 + }
1025 + if self.propertyVersion != 0 {
1026 + try visitor.visitSingularUInt64Field(value: self.propertyVersion, fieldNumber: 5)
1027 + }
1028 + try unknownFields.traverse(visitor: &visitor)
1029 + }
1030 +
1031 + public static func ==(lhs: TW_Aptos_Proto_ClaimNftMessage, rhs: TW_Aptos_Proto_ClaimNftMessage) -> Bool {
1032 + if lhs.sender != rhs.sender {return false}
1033 + if lhs.creator != rhs.creator {return false}
1034 + if lhs.collectionName != rhs.collectionName {return false}
1035 + if lhs.name != rhs.name {return false}
1036 + if lhs.propertyVersion != rhs.propertyVersion {return false}
1037 + if lhs.unknownFields != rhs.unknownFields {return false}
1038 + return true
1039 + }
1040 +}
1041 +
1042 +extension TW_Aptos_Proto_TortugaClaim: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1043 + public static let protoMessageName: String = _protobuf_package + ".TortugaClaim"
1044 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1045 + 1: .same(proto: "idx"),
1046 + ]
1047 +
1048 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1049 + while let fieldNumber = try decoder.nextFieldNumber() {
1050 + // The use of inline closures is to circumvent an issue where the compiler
1051 + // allocates stack space for every case branch when no optimizations are
1052 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1053 + switch fieldNumber {
1054 + case 1: try { try decoder.decodeSingularUInt64Field(value: &self.idx) }()
1055 + default: break
1056 + }
1057 + }
1058 + }
1059 +
1060 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1061 + if self.idx != 0 {
1062 + try visitor.visitSingularUInt64Field(value: self.idx, fieldNumber: 1)
1063 + }
1064 + try unknownFields.traverse(visitor: &visitor)
1065 + }
1066 +
1067 + public static func ==(lhs: TW_Aptos_Proto_TortugaClaim, rhs: TW_Aptos_Proto_TortugaClaim) -> Bool {
1068 + if lhs.idx != rhs.idx {return false}
1069 + if lhs.unknownFields != rhs.unknownFields {return false}
1070 + return true
1071 + }
1072 +}
1073 +
1074 +extension TW_Aptos_Proto_TortugaStake: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1075 + public static let protoMessageName: String = _protobuf_package + ".TortugaStake"
1076 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1077 + 1: .same(proto: "amount"),
1078 + ]
1079 +
1080 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1081 + while let fieldNumber = try decoder.nextFieldNumber() {
1082 + // The use of inline closures is to circumvent an issue where the compiler
1083 + // allocates stack space for every case branch when no optimizations are
1084 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1085 + switch fieldNumber {
1086 + case 1: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
1087 + default: break
1088 + }
1089 + }
1090 + }
1091 +
1092 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1093 + if self.amount != 0 {
1094 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 1)
1095 + }
1096 + try unknownFields.traverse(visitor: &visitor)
1097 + }
1098 +
1099 + public static func ==(lhs: TW_Aptos_Proto_TortugaStake, rhs: TW_Aptos_Proto_TortugaStake) -> Bool {
1100 + if lhs.amount != rhs.amount {return false}
1101 + if lhs.unknownFields != rhs.unknownFields {return false}
1102 + return true
1103 + }
1104 +}
1105 +
1106 +extension TW_Aptos_Proto_TortugaUnstake: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1107 + public static let protoMessageName: String = _protobuf_package + ".TortugaUnstake"
1108 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1109 + 1: .same(proto: "amount"),
1110 + ]
1111 +
1112 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1113 + while let fieldNumber = try decoder.nextFieldNumber() {
1114 + // The use of inline closures is to circumvent an issue where the compiler
1115 + // allocates stack space for every case branch when no optimizations are
1116 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1117 + switch fieldNumber {
1118 + case 1: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }()
1119 + default: break
1120 + }
1121 + }
1122 + }
1123 +
1124 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1125 + if self.amount != 0 {
1126 + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 1)
1127 + }
1128 + try unknownFields.traverse(visitor: &visitor)
1129 + }
1130 +
1131 + public static func ==(lhs: TW_Aptos_Proto_TortugaUnstake, rhs: TW_Aptos_Proto_TortugaUnstake) -> Bool {
1132 + if lhs.amount != rhs.amount {return false}
1133 + if lhs.unknownFields != rhs.unknownFields {return false}
1134 + return true
1135 + }
1136 +}
1137 +
1138 +extension TW_Aptos_Proto_LiquidStaking: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1139 + public static let protoMessageName: String = _protobuf_package + ".LiquidStaking"
1140 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1141 + 1: .standard(proto: "smart_contract_address"),
1142 + 2: .same(proto: "stake"),
1143 + 3: .same(proto: "unstake"),
1144 + 4: .same(proto: "claim"),
1145 + ]
1146 +
1147 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1148 + while let fieldNumber = try decoder.nextFieldNumber() {
1149 + // The use of inline closures is to circumvent an issue where the compiler
1150 + // allocates stack space for every case branch when no optimizations are
1151 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1152 + switch fieldNumber {
1153 + case 1: try { try decoder.decodeSingularStringField(value: &self.smartContractAddress) }()
1154 + case 2: try {
1155 + var v: TW_Aptos_Proto_TortugaStake?
1156 + var hadOneofValue = false
1157 + if let current = self.liquidStakeTransactionPayload {
1158 + hadOneofValue = true
1159 + if case .stake(let m) = current {v = m}
1160 + }
1161 + try decoder.decodeSingularMessageField(value: &v)
1162 + if let v = v {
1163 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1164 + self.liquidStakeTransactionPayload = .stake(v)
1165 + }
1166 + }()
1167 + case 3: try {
1168 + var v: TW_Aptos_Proto_TortugaUnstake?
1169 + var hadOneofValue = false
1170 + if let current = self.liquidStakeTransactionPayload {
1171 + hadOneofValue = true
1172 + if case .unstake(let m) = current {v = m}
1173 + }
1174 + try decoder.decodeSingularMessageField(value: &v)
1175 + if let v = v {
1176 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1177 + self.liquidStakeTransactionPayload = .unstake(v)
1178 + }
1179 + }()
1180 + case 4: try {
1181 + var v: TW_Aptos_Proto_TortugaClaim?
1182 + var hadOneofValue = false
1183 + if let current = self.liquidStakeTransactionPayload {
1184 + hadOneofValue = true
1185 + if case .claim(let m) = current {v = m}
1186 + }
1187 + try decoder.decodeSingularMessageField(value: &v)
1188 + if let v = v {
1189 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1190 + self.liquidStakeTransactionPayload = .claim(v)
1191 + }
1192 + }()
1193 + default: break
1194 + }
1195 + }
1196 + }
1197 +
1198 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1199 + // The use of inline closures is to circumvent an issue where the compiler
1200 + // allocates stack space for every if/case branch local when no optimizations
1201 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1202 + // https://github.com/apple/swift-protobuf/issues/1182
1203 + if !self.smartContractAddress.isEmpty {
1204 + try visitor.visitSingularStringField(value: self.smartContractAddress, fieldNumber: 1)
1205 + }
1206 + switch self.liquidStakeTransactionPayload {
1207 + case .stake?: try {
1208 + guard case .stake(let v)? = self.liquidStakeTransactionPayload else { preconditionFailure() }
1209 + try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
1210 + }()
1211 + case .unstake?: try {
1212 + guard case .unstake(let v)? = self.liquidStakeTransactionPayload else { preconditionFailure() }
1213 + try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
1214 + }()
1215 + case .claim?: try {
1216 + guard case .claim(let v)? = self.liquidStakeTransactionPayload else { preconditionFailure() }
1217 + try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
1218 + }()
1219 + case nil: break
1220 + }
1221 + try unknownFields.traverse(visitor: &visitor)
1222 + }
1223 +
1224 + public static func ==(lhs: TW_Aptos_Proto_LiquidStaking, rhs: TW_Aptos_Proto_LiquidStaking) -> Bool {
1225 + if lhs.smartContractAddress != rhs.smartContractAddress {return false}
1226 + if lhs.liquidStakeTransactionPayload != rhs.liquidStakeTransactionPayload {return false}
1227 + if lhs.unknownFields != rhs.unknownFields {return false}
1228 + return true
1229 + }
1230 +}
1231 +
1232 +extension TW_Aptos_Proto_NftMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1233 + public static let protoMessageName: String = _protobuf_package + ".NftMessage"
1234 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1235 + 1: .standard(proto: "offer_nft"),
1236 + 2: .standard(proto: "cancel_offer_nft"),
1237 + 3: .standard(proto: "claim_nft"),
1238 + ]
1239 +
1240 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1241 + while let fieldNumber = try decoder.nextFieldNumber() {
1242 + // The use of inline closures is to circumvent an issue where the compiler
1243 + // allocates stack space for every case branch when no optimizations are
1244 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1245 + switch fieldNumber {
1246 + case 1: try {
1247 + var v: TW_Aptos_Proto_OfferNftMessage?
1248 + var hadOneofValue = false
1249 + if let current = self.nftTransactionPayload {
1250 + hadOneofValue = true
1251 + if case .offerNft(let m) = current {v = m}
1252 + }
1253 + try decoder.decodeSingularMessageField(value: &v)
1254 + if let v = v {
1255 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1256 + self.nftTransactionPayload = .offerNft(v)
1257 + }
1258 + }()
1259 + case 2: try {
1260 + var v: TW_Aptos_Proto_CancelOfferNftMessage?
1261 + var hadOneofValue = false
1262 + if let current = self.nftTransactionPayload {
1263 + hadOneofValue = true
1264 + if case .cancelOfferNft(let m) = current {v = m}
1265 + }
1266 + try decoder.decodeSingularMessageField(value: &v)
1267 + if let v = v {
1268 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1269 + self.nftTransactionPayload = .cancelOfferNft(v)
1270 + }
1271 + }()
1272 + case 3: try {
1273 + var v: TW_Aptos_Proto_ClaimNftMessage?
1274 + var hadOneofValue = false
1275 + if let current = self.nftTransactionPayload {
1276 + hadOneofValue = true
1277 + if case .claimNft(let m) = current {v = m}
1278 + }
1279 + try decoder.decodeSingularMessageField(value: &v)
1280 + if let v = v {
1281 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1282 + self.nftTransactionPayload = .claimNft(v)
1283 + }
1284 + }()
1285 + default: break
1286 + }
1287 + }
1288 + }
1289 +
1290 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1291 + // The use of inline closures is to circumvent an issue where the compiler
1292 + // allocates stack space for every if/case branch local when no optimizations
1293 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1294 + // https://github.com/apple/swift-protobuf/issues/1182
1295 + switch self.nftTransactionPayload {
1296 + case .offerNft?: try {
1297 + guard case .offerNft(let v)? = self.nftTransactionPayload else { preconditionFailure() }
1298 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
1299 + }()
1300 + case .cancelOfferNft?: try {
1301 + guard case .cancelOfferNft(let v)? = self.nftTransactionPayload else { preconditionFailure() }
1302 + try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
1303 + }()
1304 + case .claimNft?: try {
1305 + guard case .claimNft(let v)? = self.nftTransactionPayload else { preconditionFailure() }
1306 + try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
1307 + }()
1308 + case nil: break
1309 + }
1310 + try unknownFields.traverse(visitor: &visitor)
1311 + }
1312 +
1313 + public static func ==(lhs: TW_Aptos_Proto_NftMessage, rhs: TW_Aptos_Proto_NftMessage) -> Bool {
1314 + if lhs.nftTransactionPayload != rhs.nftTransactionPayload {return false}
1315 + if lhs.unknownFields != rhs.unknownFields {return false}
1316 + return true
1317 + }
1318 +}
1319 +
1320 +extension TW_Aptos_Proto_SigningInput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1321 + public static let protoMessageName: String = _protobuf_package + ".SigningInput"
1322 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1323 + 1: .same(proto: "sender"),
1324 + 2: .standard(proto: "sequence_number"),
1325 + 3: .standard(proto: "max_gas_amount"),
1326 + 4: .standard(proto: "gas_unit_price"),
1327 + 5: .standard(proto: "expiration_timestamp_secs"),
1328 + 6: .standard(proto: "chain_id"),
1329 + 7: .standard(proto: "private_key"),
1330 + 8: .standard(proto: "any_encoded"),
1331 + 9: .same(proto: "transfer"),
1332 + 10: .standard(proto: "token_transfer"),
1333 + 11: .standard(proto: "create_account"),
1334 + 12: .standard(proto: "nft_message"),
1335 + 14: .standard(proto: "liquid_staking_message"),
1336 + 15: .standard(proto: "token_transfer_coins"),
1337 + 16: .standard(proto: "fungible_asset_transfer"),
1338 + 21: .same(proto: "abi"),
1339 + ]
1340 +
1341 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1342 + while let fieldNumber = try decoder.nextFieldNumber() {
1343 + // The use of inline closures is to circumvent an issue where the compiler
1344 + // allocates stack space for every case branch when no optimizations are
1345 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1346 + switch fieldNumber {
1347 + case 1: try { try decoder.decodeSingularStringField(value: &self.sender) }()
1348 + case 2: try { try decoder.decodeSingularInt64Field(value: &self.sequenceNumber) }()
1349 + case 3: try { try decoder.decodeSingularUInt64Field(value: &self.maxGasAmount) }()
1350 + case 4: try { try decoder.decodeSingularUInt64Field(value: &self.gasUnitPrice) }()
1351 + case 5: try { try decoder.decodeSingularUInt64Field(value: &self.expirationTimestampSecs) }()
1352 + case 6: try { try decoder.decodeSingularUInt32Field(value: &self.chainID) }()
1353 + case 7: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }()
1354 + case 8: try { try decoder.decodeSingularStringField(value: &self.anyEncoded) }()
1355 + case 9: try {
1356 + var v: TW_Aptos_Proto_TransferMessage?
1357 + var hadOneofValue = false
1358 + if let current = self.transactionPayload {
1359 + hadOneofValue = true
1360 + if case .transfer(let m) = current {v = m}
1361 + }
1362 + try decoder.decodeSingularMessageField(value: &v)
1363 + if let v = v {
1364 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1365 + self.transactionPayload = .transfer(v)
1366 + }
1367 + }()
1368 + case 10: try {
1369 + var v: TW_Aptos_Proto_TokenTransferMessage?
1370 + var hadOneofValue = false
1371 + if let current = self.transactionPayload {
1372 + hadOneofValue = true
1373 + if case .tokenTransfer(let m) = current {v = m}
1374 + }
1375 + try decoder.decodeSingularMessageField(value: &v)
1376 + if let v = v {
1377 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1378 + self.transactionPayload = .tokenTransfer(v)
1379 + }
1380 + }()
1381 + case 11: try {
1382 + var v: TW_Aptos_Proto_CreateAccountMessage?
1383 + var hadOneofValue = false
1384 + if let current = self.transactionPayload {
1385 + hadOneofValue = true
1386 + if case .createAccount(let m) = current {v = m}
1387 + }
1388 + try decoder.decodeSingularMessageField(value: &v)
1389 + if let v = v {
1390 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1391 + self.transactionPayload = .createAccount(v)
1392 + }
1393 + }()
1394 + case 12: try {
1395 + var v: TW_Aptos_Proto_NftMessage?
1396 + var hadOneofValue = false
1397 + if let current = self.transactionPayload {
1398 + hadOneofValue = true
1399 + if case .nftMessage(let m) = current {v = m}
1400 + }
1401 + try decoder.decodeSingularMessageField(value: &v)
1402 + if let v = v {
1403 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1404 + self.transactionPayload = .nftMessage(v)
1405 + }
1406 + }()
1407 + case 14: try {
1408 + var v: TW_Aptos_Proto_LiquidStaking?
1409 + var hadOneofValue = false
1410 + if let current = self.transactionPayload {
1411 + hadOneofValue = true
1412 + if case .liquidStakingMessage(let m) = current {v = m}
1413 + }
1414 + try decoder.decodeSingularMessageField(value: &v)
1415 + if let v = v {
1416 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1417 + self.transactionPayload = .liquidStakingMessage(v)
1418 + }
1419 + }()
1420 + case 15: try {
1421 + var v: TW_Aptos_Proto_TokenTransferCoinsMessage?
1422 + var hadOneofValue = false
1423 + if let current = self.transactionPayload {
1424 + hadOneofValue = true
1425 + if case .tokenTransferCoins(let m) = current {v = m}
1426 + }
1427 + try decoder.decodeSingularMessageField(value: &v)
1428 + if let v = v {
1429 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1430 + self.transactionPayload = .tokenTransferCoins(v)
1431 + }
1432 + }()
1433 + case 16: try {
1434 + var v: TW_Aptos_Proto_FungibleAssetTransferMessage?
1435 + var hadOneofValue = false
1436 + if let current = self.transactionPayload {
1437 + hadOneofValue = true
1438 + if case .fungibleAssetTransfer(let m) = current {v = m}
1439 + }
1440 + try decoder.decodeSingularMessageField(value: &v)
1441 + if let v = v {
1442 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1443 + self.transactionPayload = .fungibleAssetTransfer(v)
1444 + }
1445 + }()
1446 + case 21: try { try decoder.decodeSingularStringField(value: &self.abi) }()
1447 + default: break
1448 + }
1449 + }
1450 + }
1451 +
1452 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1453 + // The use of inline closures is to circumvent an issue where the compiler
1454 + // allocates stack space for every if/case branch local when no optimizations
1455 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1456 + // https://github.com/apple/swift-protobuf/issues/1182
1457 + if !self.sender.isEmpty {
1458 + try visitor.visitSingularStringField(value: self.sender, fieldNumber: 1)
1459 + }
1460 + if self.sequenceNumber != 0 {
1461 + try visitor.visitSingularInt64Field(value: self.sequenceNumber, fieldNumber: 2)
1462 + }
1463 + if self.maxGasAmount != 0 {
1464 + try visitor.visitSingularUInt64Field(value: self.maxGasAmount, fieldNumber: 3)
1465 + }
1466 + if self.gasUnitPrice != 0 {
1467 + try visitor.visitSingularUInt64Field(value: self.gasUnitPrice, fieldNumber: 4)
1468 + }
1469 + if self.expirationTimestampSecs != 0 {
1470 + try visitor.visitSingularUInt64Field(value: self.expirationTimestampSecs, fieldNumber: 5)
1471 + }
1472 + if self.chainID != 0 {
1473 + try visitor.visitSingularUInt32Field(value: self.chainID, fieldNumber: 6)
1474 + }
1475 + if !self.privateKey.isEmpty {
1476 + try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 7)
1477 + }
1478 + if !self.anyEncoded.isEmpty {
1479 + try visitor.visitSingularStringField(value: self.anyEncoded, fieldNumber: 8)
1480 + }
1481 + switch self.transactionPayload {
1482 + case .transfer?: try {
1483 + guard case .transfer(let v)? = self.transactionPayload else { preconditionFailure() }
1484 + try visitor.visitSingularMessageField(value: v, fieldNumber: 9)
1485 + }()
1486 + case .tokenTransfer?: try {
1487 + guard case .tokenTransfer(let v)? = self.transactionPayload else { preconditionFailure() }
1488 + try visitor.visitSingularMessageField(value: v, fieldNumber: 10)
1489 + }()
1490 + case .createAccount?: try {
1491 + guard case .createAccount(let v)? = self.transactionPayload else { preconditionFailure() }
1492 + try visitor.visitSingularMessageField(value: v, fieldNumber: 11)
1493 + }()
1494 + case .nftMessage?: try {
1495 + guard case .nftMessage(let v)? = self.transactionPayload else { preconditionFailure() }
1496 + try visitor.visitSingularMessageField(value: v, fieldNumber: 12)
1497 + }()
1498 + case .liquidStakingMessage?: try {
1499 + guard case .liquidStakingMessage(let v)? = self.transactionPayload else { preconditionFailure() }
1500 + try visitor.visitSingularMessageField(value: v, fieldNumber: 14)
1501 + }()
1502 + case .tokenTransferCoins?: try {
1503 + guard case .tokenTransferCoins(let v)? = self.transactionPayload else { preconditionFailure() }
1504 + try visitor.visitSingularMessageField(value: v, fieldNumber: 15)
1505 + }()
1506 + case .fungibleAssetTransfer?: try {
1507 + guard case .fungibleAssetTransfer(let v)? = self.transactionPayload else { preconditionFailure() }
1508 + try visitor.visitSingularMessageField(value: v, fieldNumber: 16)
1509 + }()
1510 + case nil: break
1511 + }
1512 + if !self.abi.isEmpty {
1513 + try visitor.visitSingularStringField(value: self.abi, fieldNumber: 21)
1514 + }
1515 + try unknownFields.traverse(visitor: &visitor)
1516 + }
1517 +
1518 + public static func ==(lhs: TW_Aptos_Proto_SigningInput, rhs: TW_Aptos_Proto_SigningInput) -> Bool {
1519 + if lhs.sender != rhs.sender {return false}
1520 + if lhs.sequenceNumber != rhs.sequenceNumber {return false}
1521 + if lhs.maxGasAmount != rhs.maxGasAmount {return false}
1522 + if lhs.gasUnitPrice != rhs.gasUnitPrice {return false}
1523 + if lhs.expirationTimestampSecs != rhs.expirationTimestampSecs {return false}
1524 + if lhs.chainID != rhs.chainID {return false}
1525 + if lhs.privateKey != rhs.privateKey {return false}
1526 + if lhs.anyEncoded != rhs.anyEncoded {return false}
1527 + if lhs.transactionPayload != rhs.transactionPayload {return false}
1528 + if lhs.abi != rhs.abi {return false}
1529 + if lhs.unknownFields != rhs.unknownFields {return false}
1530 + return true
1531 + }
1532 +}
1533 +
1534 +extension TW_Aptos_Proto_TransactionAuthenticator: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1535 + public static let protoMessageName: String = _protobuf_package + ".TransactionAuthenticator"
1536 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1537 + 1: .same(proto: "signature"),
1538 + 2: .standard(proto: "public_key"),
1539 + ]
1540 +
1541 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1542 + while let fieldNumber = try decoder.nextFieldNumber() {
1543 + // The use of inline closures is to circumvent an issue where the compiler
1544 + // allocates stack space for every case branch when no optimizations are
1545 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1546 + switch fieldNumber {
1547 + case 1: try { try decoder.decodeSingularBytesField(value: &self.signature) }()
1548 + case 2: try { try decoder.decodeSingularBytesField(value: &self.publicKey) }()
1549 + default: break
1550 + }
1551 + }
1552 + }
1553 +
1554 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1555 + if !self.signature.isEmpty {
1556 + try visitor.visitSingularBytesField(value: self.signature, fieldNumber: 1)
1557 + }
1558 + if !self.publicKey.isEmpty {
1559 + try visitor.visitSingularBytesField(value: self.publicKey, fieldNumber: 2)
1560 + }
1561 + try unknownFields.traverse(visitor: &visitor)
1562 + }
1563 +
1564 + public static func ==(lhs: TW_Aptos_Proto_TransactionAuthenticator, rhs: TW_Aptos_Proto_TransactionAuthenticator) -> Bool {
1565 + if lhs.signature != rhs.signature {return false}
1566 + if lhs.publicKey != rhs.publicKey {return false}
1567 + if lhs.unknownFields != rhs.unknownFields {return false}
1568 + return true
1569 + }
1570 +}
1571 +
1572 +extension TW_Aptos_Proto_SigningOutput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1573 + public static let protoMessageName: String = _protobuf_package + ".SigningOutput"
1574 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1575 + 1: .standard(proto: "raw_txn"),
1576 + 2: .same(proto: "authenticator"),
1577 + 3: .same(proto: "encoded"),
1578 + 4: .same(proto: "json"),
1579 + 5: .same(proto: "error"),
1580 + 6: .standard(proto: "error_message"),
1581 + ]
1582 +
1583 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1584 + while let fieldNumber = try decoder.nextFieldNumber() {
1585 + // The use of inline closures is to circumvent an issue where the compiler
1586 + // allocates stack space for every case branch when no optimizations are
1587 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1588 + switch fieldNumber {
1589 + case 1: try { try decoder.decodeSingularBytesField(value: &self.rawTxn) }()
1590 + case 2: try { try decoder.decodeSingularMessageField(value: &self._authenticator) }()
1591 + case 3: try { try decoder.decodeSingularBytesField(value: &self.encoded) }()
1592 + case 4: try { try decoder.decodeSingularStringField(value: &self.json) }()
1593 + case 5: try { try decoder.decodeSingularEnumField(value: &self.error) }()
1594 + case 6: try { try decoder.decodeSingularStringField(value: &self.errorMessage) }()
1595 + default: break
1596 + }
1597 + }
1598 + }
1599 +
1600 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1601 + // The use of inline closures is to circumvent an issue where the compiler
1602 + // allocates stack space for every if/case branch local when no optimizations
1603 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1604 + // https://github.com/apple/swift-protobuf/issues/1182
1605 + if !self.rawTxn.isEmpty {
1606 + try visitor.visitSingularBytesField(value: self.rawTxn, fieldNumber: 1)
1607 + }
1608 + try { if let v = self._authenticator {
1609 + try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
1610 + } }()
1611 + if !self.encoded.isEmpty {
1612 + try visitor.visitSingularBytesField(value: self.encoded, fieldNumber: 3)
1613 + }
1614 + if !self.json.isEmpty {
1615 + try visitor.visitSingularStringField(value: self.json, fieldNumber: 4)
1616 + }
1617 + if self.error != .ok {
1618 + try visitor.visitSingularEnumField(value: self.error, fieldNumber: 5)
1619 + }
1620 + if !self.errorMessage.isEmpty {
1621 + try visitor.visitSingularStringField(value: self.errorMessage, fieldNumber: 6)
1622 + }
1623 + try unknownFields.traverse(visitor: &visitor)
1624 + }
1625 +
1626 + public static func ==(lhs: TW_Aptos_Proto_SigningOutput, rhs: TW_Aptos_Proto_SigningOutput) -> Bool {
1627 + if lhs.rawTxn != rhs.rawTxn {return false}
1628 + if lhs._authenticator != rhs._authenticator {return false}
1629 + if lhs.encoded != rhs.encoded {return false}
1630 + if lhs.json != rhs.json {return false}
1631 + if lhs.error != rhs.error {return false}
1632 + if lhs.errorMessage != rhs.errorMessage {return false}
1633 + if lhs.unknownFields != rhs.unknownFields {return false}
1634 + return true
1635 + }
1636 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/BabylonStaking+Proto.swift +10 −0
@@ -0,0 +1,10 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public typealias BabylonStakingPublicKeySignature = TW_BabylonStaking_Proto_PublicKeySignature
8 +public typealias BabylonStakingStakingInfo = TW_BabylonStaking_Proto_StakingInfo
9 +public typealias BabylonStakingInputBuilder = TW_BabylonStaking_Proto_InputBuilder
10 +public typealias BabylonStakingOutputBuilder = TW_BabylonStaking_Proto_OutputBuilder
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/BabylonStaking.pb.swift +755 −0
@@ -0,0 +1,755 @@
1 +import WalletCoreC
2 +import Foundation
3 +// DO NOT EDIT.
4 +// swift-format-ignore-file
5 +//
6 +// Generated by the Swift generator plugin for the protocol buffer compiler.
7 +// Source: BabylonStaking.proto
8 +//
9 +// For information on using the generated types, please see the documentation:
10 +// https://github.com/apple/swift-protobuf/
11 +
12 +import Foundation
13 +import SwiftProtobuf
14 +
15 +// If the compiler emits an error on this type, it is because this file
16 +// was generated by a version of the `protoc` Swift plug-in that is
17 +// incompatible with the version of SwiftProtobuf.to which you are linking.
18 +// Please ensure that you are building against the same version of the API
19 +// that was used to generate this file.
20 +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
21 + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
22 + typealias Version = _2
23 +}
24 +
25 +/// Public key and corresponding signature.
26 +public struct TW_BabylonStaking_Proto_PublicKeySignature {
27 + // SwiftProtobuf.Message conformance is added in an extension below. See the
28 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
29 + // methods supported on all messages.
30 +
31 + /// Public key bytes. Can be either compressed (33 bytes) or x-only (32 bytes).
32 + public var publicKey: Data = Data()
33 +
34 + /// Signature 64-length byte array.
35 + public var signature: Data = Data()
36 +
37 + public var unknownFields = SwiftProtobuf.UnknownStorage()
38 +
39 + public init() {}
40 +}
41 +
42 +public struct TW_BabylonStaking_Proto_StakingInfo {
43 + // SwiftProtobuf.Message conformance is added in an extension below. See the
44 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
45 + // methods supported on all messages.
46 +
47 + /// User's public key.
48 + public var stakerPublicKey: Data = Data()
49 +
50 + /// Finality provider's public key chosen by the user.
51 + public var finalityProviderPublicKey: Data = Data()
52 +
53 + /// Staking Output's lock time.
54 + /// Equal to `global_parameters.staking_time` when creating a Staking transaction.
55 + /// or `global_parameters.unbonding_time` when creating an Unbonding transaction.
56 + public var stakingTime: UInt32 = 0
57 +
58 + /// Retrieved from global_parameters.covenant_pks.
59 + /// Babylon nodes that can approve Unbonding tx or Slash the staked position when acting bad.
60 + public var covenantCommitteePublicKeys: [Data] = []
61 +
62 + /// Retrieved from global_parameters.covenant_quorum.
63 + /// Specifies the quorum required by the covenant committee for unbonding transactions to be confirmed.
64 + public var covenantQuorum: UInt32 = 0
65 +
66 + public var unknownFields = SwiftProtobuf.UnknownStorage()
67 +
68 + public init() {}
69 +}
70 +
71 +public struct TW_BabylonStaking_Proto_InputBuilder {
72 + // SwiftProtobuf.Message conformance is added in an extension below. See the
73 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
74 + // methods supported on all messages.
75 +
76 + public var unknownFields = SwiftProtobuf.UnknownStorage()
77 +
78 + /// Spend a Staking Output via timelock path (staking time expired).
79 + /// In other words, create a Withdraw transaction.
80 + public struct StakingTimelockPath {
81 + // SwiftProtobuf.Message conformance is added in an extension below. See the
82 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
83 + // methods supported on all messages.
84 +
85 + public var params: TW_BabylonStaking_Proto_StakingInfo {
86 + get {return _params ?? TW_BabylonStaking_Proto_StakingInfo()}
87 + set {_params = newValue}
88 + }
89 + /// Returns true if `params` has been explicitly set.
90 + public var hasParams: Bool {return self._params != nil}
91 + /// Clears the value of `params`. Subsequent reads from it will return its default value.
92 + public mutating func clearParams() {self._params = nil}
93 +
94 + public var unknownFields = SwiftProtobuf.UnknownStorage()
95 +
96 + public init() {}
97 +
98 + fileprivate var _params: TW_BabylonStaking_Proto_StakingInfo? = nil
99 + }
100 +
101 + /// Spend a Staking Output via unbonding path.
102 + /// In other words, create an Unbonding transaction.
103 + public struct StakingUnbondingPath {
104 + // SwiftProtobuf.Message conformance is added in an extension below. See the
105 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
106 + // methods supported on all messages.
107 +
108 + public var params: TW_BabylonStaking_Proto_StakingInfo {
109 + get {return _params ?? TW_BabylonStaking_Proto_StakingInfo()}
110 + set {_params = newValue}
111 + }
112 + /// Returns true if `params` has been explicitly set.
113 + public var hasParams: Bool {return self._params != nil}
114 + /// Clears the value of `params`. Subsequent reads from it will return its default value.
115 + public mutating func clearParams() {self._params = nil}
116 +
117 + /// Signatures signed by covenant committees.
118 + /// There can be less signatures than covenant public keys, but not less than `covenant_quorum`.
119 + public var covenantCommitteeSignatures: [TW_BabylonStaking_Proto_PublicKeySignature] = []
120 +
121 + public var unknownFields = SwiftProtobuf.UnknownStorage()
122 +
123 + public init() {}
124 +
125 + fileprivate var _params: TW_BabylonStaking_Proto_StakingInfo? = nil
126 + }
127 +
128 + /// Spend a Staking Output via slashing path.
129 + /// Slashing path is only used in [ExpressOfInterest](https://github.com/babylonlabs-io/babylon-proto-ts/blob/ef42d04959b326849fe8c9773ab23802573ad407/src/generated/babylon/btcstaking/v1/tx.ts#L61).
130 + /// In other words, generate an unsigned Slashing transaction, pre-sign the staker's signature only and share to Babylon PoS chain.
131 + public struct StakingSlashingPath {
132 + // SwiftProtobuf.Message conformance is added in an extension below. See the
133 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
134 + // methods supported on all messages.
135 +
136 + public var params: TW_BabylonStaking_Proto_StakingInfo {
137 + get {return _params ?? TW_BabylonStaking_Proto_StakingInfo()}
138 + set {_params = newValue}
139 + }
140 + /// Returns true if `params` has been explicitly set.
141 + public var hasParams: Bool {return self._params != nil}
142 + /// Clears the value of `params`. Subsequent reads from it will return its default value.
143 + public mutating func clearParams() {self._params = nil}
144 +
145 + /// Empty in most of the cases. Staker's signature can be calculated without the fp signature.
146 + public var finalityProviderSignature: TW_BabylonStaking_Proto_PublicKeySignature {
147 + get {return _finalityProviderSignature ?? TW_BabylonStaking_Proto_PublicKeySignature()}
148 + set {_finalityProviderSignature = newValue}
149 + }
150 + /// Returns true if `finalityProviderSignature` has been explicitly set.
151 + public var hasFinalityProviderSignature: Bool {return self._finalityProviderSignature != nil}
152 + /// Clears the value of `finalityProviderSignature`. Subsequent reads from it will return its default value.
153 + public mutating func clearFinalityProviderSignature() {self._finalityProviderSignature = nil}
154 +
155 + public var unknownFields = SwiftProtobuf.UnknownStorage()
156 +
157 + public init() {}
158 +
159 + fileprivate var _params: TW_BabylonStaking_Proto_StakingInfo? = nil
160 + fileprivate var _finalityProviderSignature: TW_BabylonStaking_Proto_PublicKeySignature? = nil
161 + }
162 +
163 + /// Spend an Unbonding Output via timelock path (unbonding time expired).
164 + /// In other words, create a Withdraw transaction spending an Unbonding transaction.
165 + public struct UnbondingTimelockPath {
166 + // SwiftProtobuf.Message conformance is added in an extension below. See the
167 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
168 + // methods supported on all messages.
169 +
170 + public var params: TW_BabylonStaking_Proto_StakingInfo {
171 + get {return _params ?? TW_BabylonStaking_Proto_StakingInfo()}
172 + set {_params = newValue}
173 + }
174 + /// Returns true if `params` has been explicitly set.
175 + public var hasParams: Bool {return self._params != nil}
176 + /// Clears the value of `params`. Subsequent reads from it will return its default value.
177 + public mutating func clearParams() {self._params = nil}
178 +
179 + public var unknownFields = SwiftProtobuf.UnknownStorage()
180 +
181 + public init() {}
182 +
183 + fileprivate var _params: TW_BabylonStaking_Proto_StakingInfo? = nil
184 + }
185 +
186 + /// Spend an Unbonding Output via slashing path.
187 + /// Slashing path is only used in [ExpressOfInterest](https://github.com/babylonlabs-io/babylon-proto-ts/blob/ef42d04959b326849fe8c9773ab23802573ad407/src/generated/babylon/btcstaking/v1/tx.ts#L61).
188 + /// In other words, generate an unsigned Slashing transaction, pre-sign the staker's signature only and share to Babylon PoS chain.
189 + public struct UnbondingSlashingPath {
190 + // SwiftProtobuf.Message conformance is added in an extension below. See the
191 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
192 + // methods supported on all messages.
193 +
194 + public var params: TW_BabylonStaking_Proto_StakingInfo {
195 + get {return _params ?? TW_BabylonStaking_Proto_StakingInfo()}
196 + set {_params = newValue}
197 + }
198 + /// Returns true if `params` has been explicitly set.
199 + public var hasParams: Bool {return self._params != nil}
200 + /// Clears the value of `params`. Subsequent reads from it will return its default value.
201 + public mutating func clearParams() {self._params = nil}
202 +
203 + /// Empty in most of the cases. Staker's signature can be calculated without the fp signature.
204 + public var finalityProviderSignature: TW_BabylonStaking_Proto_PublicKeySignature {
205 + get {return _finalityProviderSignature ?? TW_BabylonStaking_Proto_PublicKeySignature()}
206 + set {_finalityProviderSignature = newValue}
207 + }
208 + /// Returns true if `finalityProviderSignature` has been explicitly set.
209 + public var hasFinalityProviderSignature: Bool {return self._finalityProviderSignature != nil}
210 + /// Clears the value of `finalityProviderSignature`. Subsequent reads from it will return its default value.
211 + public mutating func clearFinalityProviderSignature() {self._finalityProviderSignature = nil}
212 +
213 + public var unknownFields = SwiftProtobuf.UnknownStorage()
214 +
215 + public init() {}
216 +
217 + fileprivate var _params: TW_BabylonStaking_Proto_StakingInfo? = nil
218 + fileprivate var _finalityProviderSignature: TW_BabylonStaking_Proto_PublicKeySignature? = nil
219 + }
220 +
221 + public init() {}
222 +}
223 +
224 +public struct TW_BabylonStaking_Proto_OutputBuilder {
225 + // SwiftProtobuf.Message conformance is added in an extension below. See the
226 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
227 + // methods supported on all messages.
228 +
229 + public var unknownFields = SwiftProtobuf.UnknownStorage()
230 +
231 + /// Create a Staking Output.
232 + public struct StakingOutput {
233 + // SwiftProtobuf.Message conformance is added in an extension below. See the
234 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
235 + // methods supported on all messages.
236 +
237 + public var params: TW_BabylonStaking_Proto_StakingInfo {
238 + get {return _params ?? TW_BabylonStaking_Proto_StakingInfo()}
239 + set {_params = newValue}
240 + }
241 + /// Returns true if `params` has been explicitly set.
242 + public var hasParams: Bool {return self._params != nil}
243 + /// Clears the value of `params`. Subsequent reads from it will return its default value.
244 + public mutating func clearParams() {self._params = nil}
245 +
246 + public var unknownFields = SwiftProtobuf.UnknownStorage()
247 +
248 + public init() {}
249 +
250 + fileprivate var _params: TW_BabylonStaking_Proto_StakingInfo? = nil
251 + }
252 +
253 + /// Create an Unbonding Output.
254 + public struct UnbondingOutput {
255 + // SwiftProtobuf.Message conformance is added in an extension below. See the
256 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
257 + // methods supported on all messages.
258 +
259 + public var params: TW_BabylonStaking_Proto_StakingInfo {
260 + get {return _params ?? TW_BabylonStaking_Proto_StakingInfo()}
261 + set {_params = newValue}
262 + }
263 + /// Returns true if `params` has been explicitly set.
264 + public var hasParams: Bool {return self._params != nil}
265 + /// Clears the value of `params`. Subsequent reads from it will return its default value.
266 + public mutating func clearParams() {self._params = nil}
267 +
268 + public var unknownFields = SwiftProtobuf.UnknownStorage()
269 +
270 + public init() {}
271 +
272 + fileprivate var _params: TW_BabylonStaking_Proto_StakingInfo? = nil
273 + }
274 +
275 + /// Creates an OP_RETURN output used to identify the staking transaction among other transactions in the Bitcoin ledger.
276 + public struct OpReturn {
277 + // SwiftProtobuf.Message conformance is added in an extension below. See the
278 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
279 + // methods supported on all messages.
280 +
281 + /// Retrieved from global_parameters.Tag.
282 + public var tag: Data = Data()
283 +
284 + /// User's public key.
285 + public var stakerPublicKey: Data = Data()
286 +
287 + /// Finality provider's public key chosen by the user.
288 + public var finalityProviderPublicKey: Data = Data()
289 +
290 + /// global_parameters.min_staking_time <= staking_time <= global_parameters.max_staking_time.
291 + public var stakingTime: UInt32 = 0
292 +
293 + public var unknownFields = SwiftProtobuf.UnknownStorage()
294 +
295 + public init() {}
296 + }
297 +
298 + public init() {}
299 +}
300 +
301 +// MARK: - Code below here is support for the SwiftProtobuf.runtime.
302 +
303 +fileprivate let _protobuf_package = "TW.BabylonStaking.Proto"
304 +
305 +extension TW_BabylonStaking_Proto_PublicKeySignature: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
306 + public static let protoMessageName: String = _protobuf_package + ".PublicKeySignature"
307 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
308 + 1: .standard(proto: "public_key"),
309 + 2: .same(proto: "signature"),
310 + ]
311 +
312 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
313 + while let fieldNumber = try decoder.nextFieldNumber() {
314 + // The use of inline closures is to circumvent an issue where the compiler
315 + // allocates stack space for every case branch when no optimizations are
316 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
317 + switch fieldNumber {
318 + case 1: try { try decoder.decodeSingularBytesField(value: &self.publicKey) }()
319 + case 2: try { try decoder.decodeSingularBytesField(value: &self.signature) }()
320 + default: break
321 + }
322 + }
323 + }
324 +
325 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
326 + if !self.publicKey.isEmpty {
327 + try visitor.visitSingularBytesField(value: self.publicKey, fieldNumber: 1)
328 + }
329 + if !self.signature.isEmpty {
330 + try visitor.visitSingularBytesField(value: self.signature, fieldNumber: 2)
331 + }
332 + try unknownFields.traverse(visitor: &visitor)
333 + }
334 +
335 + public static func ==(lhs: TW_BabylonStaking_Proto_PublicKeySignature, rhs: TW_BabylonStaking_Proto_PublicKeySignature) -> Bool {
336 + if lhs.publicKey != rhs.publicKey {return false}
337 + if lhs.signature != rhs.signature {return false}
338 + if lhs.unknownFields != rhs.unknownFields {return false}
339 + return true
340 + }
341 +}
342 +
343 +extension TW_BabylonStaking_Proto_StakingInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
344 + public static let protoMessageName: String = _protobuf_package + ".StakingInfo"
345 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
346 + 1: .standard(proto: "staker_public_key"),
347 + 2: .standard(proto: "finality_provider_public_key"),
348 + 3: .standard(proto: "staking_time"),
349 + 4: .standard(proto: "covenant_committee_public_keys"),
350 + 5: .standard(proto: "covenant_quorum"),
351 + ]
352 +
353 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
354 + while let fieldNumber = try decoder.nextFieldNumber() {
355 + // The use of inline closures is to circumvent an issue where the compiler
356 + // allocates stack space for every case branch when no optimizations are
357 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
358 + switch fieldNumber {
359 + case 1: try { try decoder.decodeSingularBytesField(value: &self.stakerPublicKey) }()
360 + case 2: try { try decoder.decodeSingularBytesField(value: &self.finalityProviderPublicKey) }()
361 + case 3: try { try decoder.decodeSingularUInt32Field(value: &self.stakingTime) }()
362 + case 4: try { try decoder.decodeRepeatedBytesField(value: &self.covenantCommitteePublicKeys) }()
363 + case 5: try { try decoder.decodeSingularUInt32Field(value: &self.covenantQuorum) }()
364 + default: break
365 + }
366 + }
367 + }
368 +
369 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
370 + if !self.stakerPublicKey.isEmpty {
371 + try visitor.visitSingularBytesField(value: self.stakerPublicKey, fieldNumber: 1)
372 + }
373 + if !self.finalityProviderPublicKey.isEmpty {
374 + try visitor.visitSingularBytesField(value: self.finalityProviderPublicKey, fieldNumber: 2)
375 + }
376 + if self.stakingTime != 0 {
377 + try visitor.visitSingularUInt32Field(value: self.stakingTime, fieldNumber: 3)
378 + }
379 + if !self.covenantCommitteePublicKeys.isEmpty {
380 + try visitor.visitRepeatedBytesField(value: self.covenantCommitteePublicKeys, fieldNumber: 4)
381 + }
382 + if self.covenantQuorum != 0 {
383 + try visitor.visitSingularUInt32Field(value: self.covenantQuorum, fieldNumber: 5)
384 + }
385 + try unknownFields.traverse(visitor: &visitor)
386 + }
387 +
388 + public static func ==(lhs: TW_BabylonStaking_Proto_StakingInfo, rhs: TW_BabylonStaking_Proto_StakingInfo) -> Bool {
389 + if lhs.stakerPublicKey != rhs.stakerPublicKey {return false}
390 + if lhs.finalityProviderPublicKey != rhs.finalityProviderPublicKey {return false}
391 + if lhs.stakingTime != rhs.stakingTime {return false}
392 + if lhs.covenantCommitteePublicKeys != rhs.covenantCommitteePublicKeys {return false}
393 + if lhs.covenantQuorum != rhs.covenantQuorum {return false}
394 + if lhs.unknownFields != rhs.unknownFields {return false}
395 + return true
396 + }
397 +}
398 +
399 +extension TW_BabylonStaking_Proto_InputBuilder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
400 + public static let protoMessageName: String = _protobuf_package + ".InputBuilder"
401 + public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
402 +
403 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
404 + while let _ = try decoder.nextFieldNumber() {
405 + }
406 + }
407 +
408 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
409 + try unknownFields.traverse(visitor: &visitor)
410 + }
411 +
412 + public static func ==(lhs: TW_BabylonStaking_Proto_InputBuilder, rhs: TW_BabylonStaking_Proto_InputBuilder) -> Bool {
413 + if lhs.unknownFields != rhs.unknownFields {return false}
414 + return true
415 + }
416 +}
417 +
418 +extension TW_BabylonStaking_Proto_InputBuilder.StakingTimelockPath: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
419 + public static let protoMessageName: String = TW_BabylonStaking_Proto_InputBuilder.protoMessageName + ".StakingTimelockPath"
420 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
421 + 1: .same(proto: "params"),
422 + ]
423 +
424 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
425 + while let fieldNumber = try decoder.nextFieldNumber() {
426 + // The use of inline closures is to circumvent an issue where the compiler
427 + // allocates stack space for every case branch when no optimizations are
428 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
429 + switch fieldNumber {
430 + case 1: try { try decoder.decodeSingularMessageField(value: &self._params) }()
431 + default: break
432 + }
433 + }
434 + }
435 +
436 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
437 + // The use of inline closures is to circumvent an issue where the compiler
438 + // allocates stack space for every if/case branch local when no optimizations
439 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
440 + // https://github.com/apple/swift-protobuf/issues/1182
441 + try { if let v = self._params {
442 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
443 + } }()
444 + try unknownFields.traverse(visitor: &visitor)
445 + }
446 +
447 + public static func ==(lhs: TW_BabylonStaking_Proto_InputBuilder.StakingTimelockPath, rhs: TW_BabylonStaking_Proto_InputBuilder.StakingTimelockPath) -> Bool {
448 + if lhs._params != rhs._params {return false}
449 + if lhs.unknownFields != rhs.unknownFields {return false}
450 + return true
451 + }
452 +}
453 +
454 +extension TW_BabylonStaking_Proto_InputBuilder.StakingUnbondingPath: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
455 + public static let protoMessageName: String = TW_BabylonStaking_Proto_InputBuilder.protoMessageName + ".StakingUnbondingPath"
456 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
457 + 1: .same(proto: "params"),
458 + 2: .standard(proto: "covenant_committee_signatures"),
459 + ]
460 +
461 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
462 + while let fieldNumber = try decoder.nextFieldNumber() {
463 + // The use of inline closures is to circumvent an issue where the compiler
464 + // allocates stack space for every case branch when no optimizations are
465 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
466 + switch fieldNumber {
467 + case 1: try { try decoder.decodeSingularMessageField(value: &self._params) }()
468 + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.covenantCommitteeSignatures) }()
469 + default: break
470 + }
471 + }
472 + }
473 +
474 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
475 + // The use of inline closures is to circumvent an issue where the compiler
476 + // allocates stack space for every if/case branch local when no optimizations
477 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
478 + // https://github.com/apple/swift-protobuf/issues/1182
479 + try { if let v = self._params {
480 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
481 + } }()
482 + if !self.covenantCommitteeSignatures.isEmpty {
483 + try visitor.visitRepeatedMessageField(value: self.covenantCommitteeSignatures, fieldNumber: 2)
484 + }
485 + try unknownFields.traverse(visitor: &visitor)
486 + }
487 +
488 + public static func ==(lhs: TW_BabylonStaking_Proto_InputBuilder.StakingUnbondingPath, rhs: TW_BabylonStaking_Proto_InputBuilder.StakingUnbondingPath) -> Bool {
489 + if lhs._params != rhs._params {return false}
490 + if lhs.covenantCommitteeSignatures != rhs.covenantCommitteeSignatures {return false}
491 + if lhs.unknownFields != rhs.unknownFields {return false}
492 + return true
493 + }
494 +}
495 +
496 +extension TW_BabylonStaking_Proto_InputBuilder.StakingSlashingPath: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
497 + public static let protoMessageName: String = TW_BabylonStaking_Proto_InputBuilder.protoMessageName + ".StakingSlashingPath"
498 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
499 + 1: .same(proto: "params"),
500 + 2: .standard(proto: "finality_provider_signature"),
501 + ]
502 +
503 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
504 + while let fieldNumber = try decoder.nextFieldNumber() {
505 + // The use of inline closures is to circumvent an issue where the compiler
506 + // allocates stack space for every case branch when no optimizations are
507 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
508 + switch fieldNumber {
509 + case 1: try { try decoder.decodeSingularMessageField(value: &self._params) }()
510 + case 2: try { try decoder.decodeSingularMessageField(value: &self._finalityProviderSignature) }()
511 + default: break
512 + }
513 + }
514 + }
515 +
516 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
517 + // The use of inline closures is to circumvent an issue where the compiler
518 + // allocates stack space for every if/case branch local when no optimizations
519 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
520 + // https://github.com/apple/swift-protobuf/issues/1182
521 + try { if let v = self._params {
522 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
523 + } }()
524 + try { if let v = self._finalityProviderSignature {
525 + try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
526 + } }()
527 + try unknownFields.traverse(visitor: &visitor)
528 + }
529 +
530 + public static func ==(lhs: TW_BabylonStaking_Proto_InputBuilder.StakingSlashingPath, rhs: TW_BabylonStaking_Proto_InputBuilder.StakingSlashingPath) -> Bool {
531 + if lhs._params != rhs._params {return false}
532 + if lhs._finalityProviderSignature != rhs._finalityProviderSignature {return false}
533 + if lhs.unknownFields != rhs.unknownFields {return false}
534 + return true
535 + }
536 +}
537 +
538 +extension TW_BabylonStaking_Proto_InputBuilder.UnbondingTimelockPath: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
539 + public static let protoMessageName: String = TW_BabylonStaking_Proto_InputBuilder.protoMessageName + ".UnbondingTimelockPath"
540 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
541 + 1: .same(proto: "params"),
542 + ]
543 +
544 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
545 + while let fieldNumber = try decoder.nextFieldNumber() {
546 + // The use of inline closures is to circumvent an issue where the compiler
547 + // allocates stack space for every case branch when no optimizations are
548 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
549 + switch fieldNumber {
550 + case 1: try { try decoder.decodeSingularMessageField(value: &self._params) }()
551 + default: break
552 + }
553 + }
554 + }
555 +
556 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
557 + // The use of inline closures is to circumvent an issue where the compiler
558 + // allocates stack space for every if/case branch local when no optimizations
559 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
560 + // https://github.com/apple/swift-protobuf/issues/1182
561 + try { if let v = self._params {
562 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
563 + } }()
564 + try unknownFields.traverse(visitor: &visitor)
565 + }
566 +
567 + public static func ==(lhs: TW_BabylonStaking_Proto_InputBuilder.UnbondingTimelockPath, rhs: TW_BabylonStaking_Proto_InputBuilder.UnbondingTimelockPath) -> Bool {
568 + if lhs._params != rhs._params {return false}
569 + if lhs.unknownFields != rhs.unknownFields {return false}
570 + return true
571 + }
572 +}
573 +
574 +extension TW_BabylonStaking_Proto_InputBuilder.UnbondingSlashingPath: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
575 + public static let protoMessageName: String = TW_BabylonStaking_Proto_InputBuilder.protoMessageName + ".UnbondingSlashingPath"
576 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
577 + 1: .same(proto: "params"),
578 + 2: .standard(proto: "finality_provider_signature"),
579 + ]
580 +
581 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
582 + while let fieldNumber = try decoder.nextFieldNumber() {
583 + // The use of inline closures is to circumvent an issue where the compiler
584 + // allocates stack space for every case branch when no optimizations are
585 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
586 + switch fieldNumber {
587 + case 1: try { try decoder.decodeSingularMessageField(value: &self._params) }()
588 + case 2: try { try decoder.decodeSingularMessageField(value: &self._finalityProviderSignature) }()
589 + default: break
590 + }
591 + }
592 + }
593 +
594 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
595 + // The use of inline closures is to circumvent an issue where the compiler
596 + // allocates stack space for every if/case branch local when no optimizations
597 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
598 + // https://github.com/apple/swift-protobuf/issues/1182
599 + try { if let v = self._params {
600 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
601 + } }()
602 + try { if let v = self._finalityProviderSignature {
603 + try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
604 + } }()
605 + try unknownFields.traverse(visitor: &visitor)
606 + }
607 +
608 + public static func ==(lhs: TW_BabylonStaking_Proto_InputBuilder.UnbondingSlashingPath, rhs: TW_BabylonStaking_Proto_InputBuilder.UnbondingSlashingPath) -> Bool {
609 + if lhs._params != rhs._params {return false}
610 + if lhs._finalityProviderSignature != rhs._finalityProviderSignature {return false}
611 + if lhs.unknownFields != rhs.unknownFields {return false}
612 + return true
613 + }
614 +}
615 +
616 +extension TW_BabylonStaking_Proto_OutputBuilder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
617 + public static let protoMessageName: String = _protobuf_package + ".OutputBuilder"
618 + public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
619 +
620 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
621 + while let _ = try decoder.nextFieldNumber() {
622 + }
623 + }
624 +
625 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
626 + try unknownFields.traverse(visitor: &visitor)
627 + }
628 +
629 + public static func ==(lhs: TW_BabylonStaking_Proto_OutputBuilder, rhs: TW_BabylonStaking_Proto_OutputBuilder) -> Bool {
630 + if lhs.unknownFields != rhs.unknownFields {return false}
631 + return true
632 + }
633 +}
634 +
635 +extension TW_BabylonStaking_Proto_OutputBuilder.StakingOutput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
636 + public static let protoMessageName: String = TW_BabylonStaking_Proto_OutputBuilder.protoMessageName + ".StakingOutput"
637 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
638 + 1: .same(proto: "params"),
639 + ]
640 +
641 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
642 + while let fieldNumber = try decoder.nextFieldNumber() {
643 + // The use of inline closures is to circumvent an issue where the compiler
644 + // allocates stack space for every case branch when no optimizations are
645 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
646 + switch fieldNumber {
647 + case 1: try { try decoder.decodeSingularMessageField(value: &self._params) }()
648 + default: break
649 + }
650 + }
651 + }
652 +
653 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
654 + // The use of inline closures is to circumvent an issue where the compiler
655 + // allocates stack space for every if/case branch local when no optimizations
656 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
657 + // https://github.com/apple/swift-protobuf/issues/1182
658 + try { if let v = self._params {
659 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
660 + } }()
661 + try unknownFields.traverse(visitor: &visitor)
662 + }
663 +
664 + public static func ==(lhs: TW_BabylonStaking_Proto_OutputBuilder.StakingOutput, rhs: TW_BabylonStaking_Proto_OutputBuilder.StakingOutput) -> Bool {
665 + if lhs._params != rhs._params {return false}
666 + if lhs.unknownFields != rhs.unknownFields {return false}
667 + return true
668 + }
669 +}
670 +
671 +extension TW_BabylonStaking_Proto_OutputBuilder.UnbondingOutput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
672 + public static let protoMessageName: String = TW_BabylonStaking_Proto_OutputBuilder.protoMessageName + ".UnbondingOutput"
673 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
674 + 1: .same(proto: "params"),
675 + ]
676 +
677 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
678 + while let fieldNumber = try decoder.nextFieldNumber() {
679 + // The use of inline closures is to circumvent an issue where the compiler
680 + // allocates stack space for every case branch when no optimizations are
681 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
682 + switch fieldNumber {
683 + case 1: try { try decoder.decodeSingularMessageField(value: &self._params) }()
684 + default: break
685 + }
686 + }
687 + }
688 +
689 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
690 + // The use of inline closures is to circumvent an issue where the compiler
691 + // allocates stack space for every if/case branch local when no optimizations
692 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
693 + // https://github.com/apple/swift-protobuf/issues/1182
694 + try { if let v = self._params {
695 + try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
696 + } }()
697 + try unknownFields.traverse(visitor: &visitor)
698 + }
699 +
700 + public static func ==(lhs: TW_BabylonStaking_Proto_OutputBuilder.UnbondingOutput, rhs: TW_BabylonStaking_Proto_OutputBuilder.UnbondingOutput) -> Bool {
701 + if lhs._params != rhs._params {return false}
702 + if lhs.unknownFields != rhs.unknownFields {return false}
703 + return true
704 + }
705 +}
706 +
707 +extension TW_BabylonStaking_Proto_OutputBuilder.OpReturn: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
708 + public static let protoMessageName: String = TW_BabylonStaking_Proto_OutputBuilder.protoMessageName + ".OpReturn"
709 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
710 + 1: .same(proto: "tag"),
711 + 2: .standard(proto: "staker_public_key"),
712 + 3: .standard(proto: "finality_provider_public_key"),
713 + 4: .standard(proto: "staking_time"),
714 + ]
715 +
716 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
717 + while let fieldNumber = try decoder.nextFieldNumber() {
718 + // The use of inline closures is to circumvent an issue where the compiler
719 + // allocates stack space for every case branch when no optimizations are
720 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
721 + switch fieldNumber {
722 + case 1: try { try decoder.decodeSingularBytesField(value: &self.tag) }()
723 + case 2: try { try decoder.decodeSingularBytesField(value: &self.stakerPublicKey) }()
724 + case 3: try { try decoder.decodeSingularBytesField(value: &self.finalityProviderPublicKey) }()
725 + case 4: try { try decoder.decodeSingularUInt32Field(value: &self.stakingTime) }()
726 + default: break
727 + }
728 + }
729 + }
730 +
731 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
732 + if !self.tag.isEmpty {
733 + try visitor.visitSingularBytesField(value: self.tag, fieldNumber: 1)
734 + }
735 + if !self.stakerPublicKey.isEmpty {
736 + try visitor.visitSingularBytesField(value: self.stakerPublicKey, fieldNumber: 2)
737 + }
738 + if !self.finalityProviderPublicKey.isEmpty {
739 + try visitor.visitSingularBytesField(value: self.finalityProviderPublicKey, fieldNumber: 3)
740 + }
741 + if self.stakingTime != 0 {
742 + try visitor.visitSingularUInt32Field(value: self.stakingTime, fieldNumber: 4)
743 + }
744 + try unknownFields.traverse(visitor: &visitor)
745 + }
746 +
747 + public static func ==(lhs: TW_BabylonStaking_Proto_OutputBuilder.OpReturn, rhs: TW_BabylonStaking_Proto_OutputBuilder.OpReturn) -> Bool {
748 + if lhs.tag != rhs.tag {return false}
749 + if lhs.stakerPublicKey != rhs.stakerPublicKey {return false}
750 + if lhs.finalityProviderPublicKey != rhs.finalityProviderPublicKey {return false}
751 + if lhs.stakingTime != rhs.stakingTime {return false}
752 + if lhs.unknownFields != rhs.unknownFields {return false}
753 + return true
754 + }
755 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Barz+Proto.swift +10 −0
@@ -0,0 +1,10 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public typealias BarzContractAddressInput = TW_Barz_Proto_ContractAddressInput
8 +public typealias BarzFacetCut = TW_Barz_Proto_FacetCut
9 +public typealias BarzDiamondCutInput = TW_Barz_Proto_DiamondCutInput
10 +public typealias BarzFacetCutAction = TW_Barz_Proto_FacetCutAction
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Barz.pb.swift +327 −0
@@ -0,0 +1,327 @@
1 +import WalletCoreC
2 +import Foundation
3 +// DO NOT EDIT.
4 +// swift-format-ignore-file
5 +//
6 +// Generated by the Swift generator plugin for the protocol buffer compiler.
7 +// Source: Barz.proto
8 +//
9 +// For information on using the generated types, please see the documentation:
10 +// https://github.com/apple/swift-protobuf/
11 +
12 +// SPDX-License-Identifier: Apache-2.0
13 +//
14 +// Copyright © 2017 Trust Wallet.
15 +
16 +import Foundation
17 +import SwiftProtobuf
18 +
19 +// If the compiler emits an error on this type, it is because this file
20 +// was generated by a version of the `protoc` Swift plug-in that is
21 +// incompatible with the version of SwiftProtobuf.to which you are linking.
22 +// Please ensure that you are building against the same version of the API
23 +// that was used to generate this file.
24 +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
25 + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
26 + typealias Version = _2
27 +}
28 +
29 +/// FacetCutAction represents the action to be performed for a FacetCut
30 +public enum TW_Barz_Proto_FacetCutAction: SwiftProtobuf.Enum {
31 + public typealias RawValue = Int
32 + case add // = 0
33 + case replace // = 1
34 + case remove // = 2
35 + case UNRECOGNIZED(Int)
36 +
37 + public init() {
38 + self = .add
39 + }
40 +
41 + public init?(rawValue: Int) {
42 + switch rawValue {
43 + case 0: self = .add
44 + case 1: self = .replace
45 + case 2: self = .remove
46 + default: self = .UNRECOGNIZED(rawValue)
47 + }
48 + }
49 +
50 + public var rawValue: Int {
51 + switch self {
52 + case .add: return 0
53 + case .replace: return 1
54 + case .remove: return 2
55 + case .UNRECOGNIZED(let i): return i
56 + }
57 + }
58 +
59 +}
60 +
61 +#if swift(>=4.2)
62 +
63 +extension TW_Barz_Proto_FacetCutAction: CaseIterable {
64 + // The compiler won't synthesize support with the UNRECOGNIZED case.
65 + public static var allCases: [TW_Barz_Proto_FacetCutAction] = [
66 + .add,
67 + .replace,
68 + .remove,
69 + ]
70 +}
71 +
72 +#endif // swift(>=4.2)
73 +
74 +/// Input parameters for calculating a counterfactual address for ERC-4337 based smart contract wallet
75 +public struct TW_Barz_Proto_ContractAddressInput {
76 + // SwiftProtobuf.Message conformance is added in an extension below. See the
77 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
78 + // methods supported on all messages.
79 +
80 + /// ERC-4337 entry point
81 + public var entryPoint: String = String()
82 +
83 + /// Address of the contract factory
84 + public var factory: String = String()
85 +
86 + /// Diamond proxy facets required for the contract setup
87 + public var accountFacet: String = String()
88 +
89 + public var verificationFacet: String = String()
90 +
91 + public var facetRegistry: String = String()
92 +
93 + public var defaultFallback: String = String()
94 +
95 + /// Bytecode of the smart contract to deploy
96 + public var bytecode: String = String()
97 +
98 + /// PublicKey of the wallet
99 + public var publicKey: String = String()
100 +
101 + /// Salt is used to derive multiple account from the same public key
102 + public var salt: UInt32 = 0
103 +
104 + public var unknownFields = SwiftProtobuf.UnknownStorage()
105 +
106 + public init() {}
107 +}
108 +
109 +/// FacetCut represents a single operation to be performed on a facet
110 +public struct TW_Barz_Proto_FacetCut {
111 + // SwiftProtobuf.Message conformance is added in an extension below. See the
112 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
113 + // methods supported on all messages.
114 +
115 + /// The address of the facet
116 + public var facetAddress: String = String()
117 +
118 + /// The action to perform
119 + public var action: TW_Barz_Proto_FacetCutAction = .add
120 +
121 + /// List of function selectors, each is bytes4
122 + public var functionSelectors: [Data] = []
123 +
124 + public var unknownFields = SwiftProtobuf.UnknownStorage()
125 +
126 + public init() {}
127 +}
128 +
129 +/// DiamondCutInput represents the input parameters for a diamondCut operation
130 +public struct TW_Barz_Proto_DiamondCutInput {
131 + // SwiftProtobuf.Message conformance is added in an extension below. See the
132 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
133 + // methods supported on all messages.
134 +
135 + /// List of facet cuts to apply
136 + public var facetCuts: [TW_Barz_Proto_FacetCut] = []
137 +
138 + /// Address to call with `init` data after applying cuts
139 + public var initAddress: String = String()
140 +
141 + /// Data to pass to `init` function call
142 + public var initData: Data = Data()
143 +
144 + public var unknownFields = SwiftProtobuf.UnknownStorage()
145 +
146 + public init() {}
147 +}
148 +
149 +// MARK: - Code below here is support for the SwiftProtobuf.runtime.
150 +
151 +fileprivate let _protobuf_package = "TW.Barz.Proto"
152 +
153 +extension TW_Barz_Proto_FacetCutAction: SwiftProtobuf._ProtoNameProviding {
154 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
155 + 0: .same(proto: "ADD"),
156 + 1: .same(proto: "REPLACE"),
157 + 2: .same(proto: "REMOVE"),
158 + ]
159 +}
160 +
161 +extension TW_Barz_Proto_ContractAddressInput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
162 + public static let protoMessageName: String = _protobuf_package + ".ContractAddressInput"
163 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
164 + 1: .standard(proto: "entry_point"),
165 + 2: .same(proto: "factory"),
166 + 3: .standard(proto: "account_facet"),
167 + 4: .standard(proto: "verification_facet"),
168 + 5: .standard(proto: "facet_registry"),
169 + 6: .standard(proto: "default_fallback"),
170 + 7: .same(proto: "bytecode"),
171 + 8: .standard(proto: "public_key"),
172 + 9: .same(proto: "salt"),
173 + ]
174 +
175 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
176 + while let fieldNumber = try decoder.nextFieldNumber() {
177 + // The use of inline closures is to circumvent an issue where the compiler
178 + // allocates stack space for every case branch when no optimizations are
179 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
180 + switch fieldNumber {
181 + case 1: try { try decoder.decodeSingularStringField(value: &self.entryPoint) }()
182 + case 2: try { try decoder.decodeSingularStringField(value: &self.factory) }()
183 + case 3: try { try decoder.decodeSingularStringField(value: &self.accountFacet) }()
184 + case 4: try { try decoder.decodeSingularStringField(value: &self.verificationFacet) }()
185 + case 5: try { try decoder.decodeSingularStringField(value: &self.facetRegistry) }()
186 + case 6: try { try decoder.decodeSingularStringField(value: &self.defaultFallback) }()
187 + case 7: try { try decoder.decodeSingularStringField(value: &self.bytecode) }()
188 + case 8: try { try decoder.decodeSingularStringField(value: &self.publicKey) }()
189 + case 9: try { try decoder.decodeSingularUInt32Field(value: &self.salt) }()
190 + default: break
191 + }
192 + }
193 + }
194 +
195 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
196 + if !self.entryPoint.isEmpty {
197 + try visitor.visitSingularStringField(value: self.entryPoint, fieldNumber: 1)
198 + }
199 + if !self.factory.isEmpty {
200 + try visitor.visitSingularStringField(value: self.factory, fieldNumber: 2)
201 + }
202 + if !self.accountFacet.isEmpty {
203 + try visitor.visitSingularStringField(value: self.accountFacet, fieldNumber: 3)
204 + }
205 + if !self.verificationFacet.isEmpty {
206 + try visitor.visitSingularStringField(value: self.verificationFacet, fieldNumber: 4)
207 + }
208 + if !self.facetRegistry.isEmpty {
209 + try visitor.visitSingularStringField(value: self.facetRegistry, fieldNumber: 5)
210 + }
211 + if !self.defaultFallback.isEmpty {
212 + try visitor.visitSingularStringField(value: self.defaultFallback, fieldNumber: 6)
213 + }
214 + if !self.bytecode.isEmpty {
215 + try visitor.visitSingularStringField(value: self.bytecode, fieldNumber: 7)
216 + }
217 + if !self.publicKey.isEmpty {
218 + try visitor.visitSingularStringField(value: self.publicKey, fieldNumber: 8)
219 + }
220 + if self.salt != 0 {
221 + try visitor.visitSingularUInt32Field(value: self.salt, fieldNumber: 9)
222 + }
223 + try unknownFields.traverse(visitor: &visitor)
224 + }
225 +
226 + public static func ==(lhs: TW_Barz_Proto_ContractAddressInput, rhs: TW_Barz_Proto_ContractAddressInput) -> Bool {
227 + if lhs.entryPoint != rhs.entryPoint {return false}
228 + if lhs.factory != rhs.factory {return false}
229 + if lhs.accountFacet != rhs.accountFacet {return false}
230 + if lhs.verificationFacet != rhs.verificationFacet {return false}
231 + if lhs.facetRegistry != rhs.facetRegistry {return false}
232 + if lhs.defaultFallback != rhs.defaultFallback {return false}
233 + if lhs.bytecode != rhs.bytecode {return false}
234 + if lhs.publicKey != rhs.publicKey {return false}
235 + if lhs.salt != rhs.salt {return false}
236 + if lhs.unknownFields != rhs.unknownFields {return false}
237 + return true
238 + }
239 +}
240 +
241 +extension TW_Barz_Proto_FacetCut: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
242 + public static let protoMessageName: String = _protobuf_package + ".FacetCut"
243 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
244 + 1: .standard(proto: "facet_address"),
245 + 2: .same(proto: "action"),
246 + 3: .standard(proto: "function_selectors"),
247 + ]
248 +
249 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
250 + while let fieldNumber = try decoder.nextFieldNumber() {
251 + // The use of inline closures is to circumvent an issue where the compiler
252 + // allocates stack space for every case branch when no optimizations are
253 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
254 + switch fieldNumber {
255 + case 1: try { try decoder.decodeSingularStringField(value: &self.facetAddress) }()
256 + case 2: try { try decoder.decodeSingularEnumField(value: &self.action) }()
257 + case 3: try { try decoder.decodeRepeatedBytesField(value: &self.functionSelectors) }()
258 + default: break
259 + }
260 + }
261 + }
262 +
263 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
264 + if !self.facetAddress.isEmpty {
265 + try visitor.visitSingularStringField(value: self.facetAddress, fieldNumber: 1)
266 + }
267 + if self.action != .add {
268 + try visitor.visitSingularEnumField(value: self.action, fieldNumber: 2)
269 + }
270 + if !self.functionSelectors.isEmpty {
271 + try visitor.visitRepeatedBytesField(value: self.functionSelectors, fieldNumber: 3)
272 + }
273 + try unknownFields.traverse(visitor: &visitor)
274 + }
275 +
276 + public static func ==(lhs: TW_Barz_Proto_FacetCut, rhs: TW_Barz_Proto_FacetCut) -> Bool {
277 + if lhs.facetAddress != rhs.facetAddress {return false}
278 + if lhs.action != rhs.action {return false}
279 + if lhs.functionSelectors != rhs.functionSelectors {return false}
280 + if lhs.unknownFields != rhs.unknownFields {return false}
281 + return true
282 + }
283 +}
284 +
285 +extension TW_Barz_Proto_DiamondCutInput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
286 + public static let protoMessageName: String = _protobuf_package + ".DiamondCutInput"
287 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
288 + 1: .standard(proto: "facet_cuts"),
289 + 2: .standard(proto: "init_address"),
290 + 3: .standard(proto: "init_data"),
291 + ]
292 +
293 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
294 + while let fieldNumber = try decoder.nextFieldNumber() {
295 + // The use of inline closures is to circumvent an issue where the compiler
296 + // allocates stack space for every case branch when no optimizations are
297 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
298 + switch fieldNumber {
299 + case 1: try { try decoder.decodeRepeatedMessageField(value: &self.facetCuts) }()
300 + case 2: try { try decoder.decodeSingularStringField(value: &self.initAddress) }()
301 + case 3: try { try decoder.decodeSingularBytesField(value: &self.initData) }()
302 + default: break
303 + }
304 + }
305 + }
306 +
307 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
308 + if !self.facetCuts.isEmpty {
309 + try visitor.visitRepeatedMessageField(value: self.facetCuts, fieldNumber: 1)
310 + }
311 + if !self.initAddress.isEmpty {
312 + try visitor.visitSingularStringField(value: self.initAddress, fieldNumber: 2)
313 + }
314 + if !self.initData.isEmpty {
315 + try visitor.visitSingularBytesField(value: self.initData, fieldNumber: 3)
316 + }
317 + try unknownFields.traverse(visitor: &visitor)
318 + }
319 +
320 + public static func ==(lhs: TW_Barz_Proto_DiamondCutInput, rhs: TW_Barz_Proto_DiamondCutInput) -> Bool {
321 + if lhs.facetCuts != rhs.facetCuts {return false}
322 + if lhs.initAddress != rhs.initAddress {return false}
323 + if lhs.initData != rhs.initData {return false}
324 + if lhs.unknownFields != rhs.unknownFields {return false}
325 + return true
326 + }
327 +}
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Binance+Proto.swift +25 −0
@@ -0,0 +1,25 @@
1 +import WalletCoreC
2 +import Foundation
3 +// SPDX-License-Identifier: Apache-2.0
4 +//
5 +// Copyright © 2017 Trust Wallet.
6 +
7 +public typealias BinanceTransaction = TW_Binance_Proto_Transaction
8 +public typealias BinanceSignature = TW_Binance_Proto_Signature
9 +public typealias BinanceTradeOrder = TW_Binance_Proto_TradeOrder
10 +public typealias BinanceCancelTradeOrder = TW_Binance_Proto_CancelTradeOrder
11 +public typealias BinanceSendOrder = TW_Binance_Proto_SendOrder
12 +public typealias BinanceHTLTOrder = TW_Binance_Proto_HTLTOrder
13 +public typealias BinanceDepositHTLTOrder = TW_Binance_Proto_DepositHTLTOrder
14 +public typealias BinanceClaimHTLOrder = TW_Binance_Proto_ClaimHTLOrder
15 +public typealias BinanceRefundHTLTOrder = TW_Binance_Proto_RefundHTLTOrder
16 +public typealias BinanceTransferOut = TW_Binance_Proto_TransferOut
17 +public typealias BinanceSideChainDelegate = TW_Binance_Proto_SideChainDelegate
18 +public typealias BinanceSideChainRedelegate = TW_Binance_Proto_SideChainRedelegate
19 +public typealias BinanceSideChainUndelegate = TW_Binance_Proto_SideChainUndelegate
20 +public typealias BinanceSideChainStakeMigration = TW_Binance_Proto_SideChainStakeMigration
21 +public typealias BinanceTimeLockOrder = TW_Binance_Proto_TimeLockOrder
22 +public typealias BinanceTimeRelockOrder = TW_Binance_Proto_TimeRelockOrder
23 +public typealias BinanceTimeUnlockOrder = TW_Binance_Proto_TimeUnlockOrder
24 +public typealias BinanceSigningInput = TW_Binance_Proto_SigningInput
25 +public typealias BinanceSigningOutput = TW_Binance_Proto_SigningOutput
added vendor/WalletCoreSPM/Sources/WalletCore/Generated/Protobuf/Binance.pb.swift +2171 −0
@@ -0,0 +1,2191 @@
1 +import WalletCoreC
2 +import Foundation
3 +// DO NOT EDIT.
4 +// swift-format-ignore-file
5 +//
6 +// Generated by the Swift generator plugin for the protocol buffer compiler.
7 +// Source: Binance.proto
8 +//
9 +// For information on using the generated types, please see the documentation:
10 +// https://github.com/apple/swift-protobuf/
11 +
12 +import Foundation
13 +import SwiftProtobuf
14 +
15 +// If the compiler emits an error on this type, it is because this file
16 +// was generated by a version of the `protoc` Swift plug-in that is
17 +// incompatible with the version of SwiftProtobuf.to which you are linking.
18 +// Please ensure that you are building against the same version of the API
19 +// that was used to generate this file.
20 +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
21 + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
22 + typealias Version = _2
23 +}
24 +
25 +/// Transaction structure, used internally
26 +public struct TW_Binance_Proto_Transaction {
27 + // SwiftProtobuf.Message conformance is added in an extension below. See the
28 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
29 + // methods supported on all messages.
30 +
31 + /// array of size 1, containing the transaction message, which are one of the transaction type below
32 + public var msgs: [Data] = []
33 +
34 + /// array of size 1, containing the standard signature structure of the transaction sender
35 + public var signatures: [Data] = []
36 +
37 + /// a short sentence of remark for the transaction, only for `Transfer` transactions.
38 + public var memo: String = String()
39 +
40 + /// an identifier for tools triggering this transaction, set to zero if unwilling to disclose.
41 + public var source: Int64 = 0
42 +
43 + /// reserved for future use
44 + public var data: Data = Data()
45 +
46 + public var unknownFields = SwiftProtobuf.UnknownStorage()
47 +
48 + public init() {}
49 +}
50 +
51 +/// Signature structure, used internally
52 +public struct TW_Binance_Proto_Signature {
53 + // SwiftProtobuf.Message conformance is added in an extension below. See the
54 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
55 + // methods supported on all messages.
56 +
57 + /// public key bytes of the signer address
58 + public var pubKey: Data = Data()
59 +
60 + /// signature bytes, please check chain access section for signature generation
61 + public var signature: Data = Data()
62 +
63 + /// another identifier of signer, which can be read from chain by account REST API or RPC
64 + public var accountNumber: Int64 = 0
65 +
66 + /// sequence number for the next transaction
67 + public var sequence: Int64 = 0
68 +
69 + public var unknownFields = SwiftProtobuf.UnknownStorage()
70 +
71 + public init() {}
72 +}
73 +
74 +/// Message for Trade order
75 +public struct TW_Binance_Proto_TradeOrder {
76 + // SwiftProtobuf.Message conformance is added in an extension below. See the
77 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
78 + // methods supported on all messages.
79 +
80 + /// originating address
81 + public var sender: Data = Data()
82 +
83 + /// order id, optional
84 + public var id: String = String()
85 +
86 + /// symbol for trading pair in full name of the tokens
87 + public var symbol: String = String()
88 +
89 + /// only accept 2 for now, meaning limit order
90 + public var ordertype: Int64 = 0
91 +
92 + /// 1 for buy and 2 for sell
93 + public var side: Int64 = 0
94 +
95 + /// price of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer
96 + public var price: Int64 = 0
97 +
98 + /// quantity of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer
99 + public var quantity: Int64 = 0
100 +
101 + /// 1 for Good Till Expire(GTE) order and 3 for Immediate Or Cancel (IOC)
102 + public var timeinforce: Int64 = 0
103 +
104 + public var unknownFields = SwiftProtobuf.UnknownStorage()
105 +
106 + public init() {}
107 +}
108 +
109 +/// Message for CancelTrade order
110 +public struct TW_Binance_Proto_CancelTradeOrder {
111 + // SwiftProtobuf.Message conformance is added in an extension below. See the
112 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
113 + // methods supported on all messages.
114 +
115 + /// originating address
116 + public var sender: Data = Data()
117 +
118 + /// symbol for trading pair in full name of the tokens
119 + public var symbol: String = String()
120 +
121 + /// order id to cancel
122 + public var refid: String = String()
123 +
124 + public var unknownFields = SwiftProtobuf.UnknownStorage()
125 +
126 + public init() {}
127 +}
128 +
129 +/// Message for Send order
130 +public struct TW_Binance_Proto_SendOrder {
131 + // SwiftProtobuf.Message conformance is added in an extension below. See the
132 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
133 + // methods supported on all messages.
134 +
135 + /// Send inputs
136 + public var inputs: [TW_Binance_Proto_SendOrder.Input] = []
137 +
138 + /// Send outputs
139 + public var outputs: [TW_Binance_Proto_SendOrder.Output] = []
140 +
141 + public var unknownFields = SwiftProtobuf.UnknownStorage()
142 +
143 + /// A token amount, symbol-amount pair. Could be moved out of SendOrder; kept here for backward compatibility.
144 + public struct Token {
145 + // SwiftProtobuf.Message conformance is added in an extension below. See the
146 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
147 + // methods supported on all messages.
148 +
149 + /// Token ID
150 + public var denom: String = String()
151 +
152 + /// Amount
153 + public var amount: Int64 = 0
154 +
155 + public var unknownFields = SwiftProtobuf.UnknownStorage()
156 +
157 + public init() {}
158 + }
159 +
160 + /// Transaction input
161 + public struct Input {
162 + // SwiftProtobuf.Message conformance is added in an extension below. See the
163 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
164 + // methods supported on all messages.
165 +
166 + /// source address
167 + public var address: Data = Data()
168 +
169 + /// input coin amounts
170 + public var coins: [TW_Binance_Proto_SendOrder.Token] = []
171 +
172 + public var unknownFields = SwiftProtobuf.UnknownStorage()
173 +
174 + public init() {}
175 + }
176 +
177 + /// Transaction output
178 + public struct Output {
179 + // SwiftProtobuf.Message conformance is added in an extension below. See the
180 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
181 + // methods supported on all messages.
182 +
183 + /// destination address
184 + public var address: Data = Data()
185 +
186 + /// output coin amounts
187 + public var coins: [TW_Binance_Proto_SendOrder.Token] = []
188 +
189 + public var unknownFields = SwiftProtobuf.UnknownStorage()
190 +
191 + public init() {}
192 + }
193 +
194 + public init() {}
195 +}
196 +
197 +/// Message for HashTimeLock order
198 +public struct TW_Binance_Proto_HTLTOrder {
199 + // SwiftProtobuf.Message conformance is added in an extension below. See the
200 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
201 + // methods supported on all messages.
202 +
203 + /// signer address
204 + public var from: Data = Data()
205 +
206 + /// recipient address
207 + public var to: Data = Data()
208 +
209 + /// source on other chain, optional
210 + public var recipientOtherChain: String = String()
211 +
212 + /// recipient on other chain, optional
213 + public var senderOtherChain: String = String()
214 +
215 + /// hash of a random number and timestamp, based on SHA256
216 + public var randomNumberHash: Data = Data()
217 +
218 + /// timestamp
219 + public var timestamp: Int64 = 0
220 +
221 + /// amounts
222 + public var amount: [TW_Binance_Proto_SendOrder.Token] = []
223 +
224 + /// expected gained token on the other chain
225 + public var expectedIncome: String = String()
226 +
227 + /// period expressed in block heights
228 + public var heightSpan: Int64 = 0
229 +
230 + /// set for cross-chain send
231 + public var crossChain: Bool = false
232 +
233 + public var unknownFields = SwiftProtobuf.UnknownStorage()
234 +
235 + public init() {}
236 +}
237 +
238 +/// Message for Deposit HTLT order
239 +public struct TW_Binance_Proto_DepositHTLTOrder {
240 + // SwiftProtobuf.Message conformance is added in an extension below. See the
241 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
242 + // methods supported on all messages.
243 +
244 + /// signer address
245 + public var from: Data = Data()
246 +
247 + /// amounts
248 + public var amount: [TW_Binance_Proto_SendOrder.Token] = []
249 +
250 + /// swap ID
251 + public var swapID: Data = Data()
252 +
253 + public var unknownFields = SwiftProtobuf.UnknownStorage()
254 +
255 + public init() {}
256 +}
257 +
258 +/// Message for Claim HTLT order
259 +public struct TW_Binance_Proto_ClaimHTLOrder {
260 + // SwiftProtobuf.Message conformance is added in an extension below. See the
261 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
262 + // methods supported on all messages.
263 +
264 + /// signer address
265 + public var from: Data = Data()
266 +
267 + /// swap ID
268 + public var swapID: Data = Data()
269 +
270 + /// random number input
271 + public var randomNumber: Data = Data()
272 +
273 + public var unknownFields = SwiftProtobuf.UnknownStorage()
274 +
275 + public init() {}
276 +}
277 +
278 +/// Message for Refund HTLT order
279 +public struct TW_Binance_Proto_RefundHTLTOrder {
280 + // SwiftProtobuf.Message conformance is added in an extension below. See the
281 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
282 + // methods supported on all messages.
283 +
284 + /// signer address
285 + public var from: Data = Data()
286 +
287 + /// swap ID
288 + public var swapID: Data = Data()
289 +
290 + public var unknownFields = SwiftProtobuf.UnknownStorage()
291 +
292 + public init() {}
293 +}
294 +
295 +/// Transfer
296 +public struct TW_Binance_Proto_TransferOut {
297 + // SwiftProtobuf.Message conformance is added in an extension below. See the
298 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
299 + // methods supported on all messages.
300 +
301 + /// source address
302 + public var from: Data = Data()
303 +
304 + /// recipient address
305 + public var to: Data = Data()
306 +
307 + /// transfer amount
308 + public var amount: TW_Binance_Proto_SendOrder.Token {
309 + get {return _amount ?? TW_Binance_Proto_SendOrder.Token()}
310 + set {_amount = newValue}
311 + }
312 + /// Returns true if `amount` has been explicitly set.
313 + public var hasAmount: Bool {return self._amount != nil}
314 + /// Clears the value of `amount`. Subsequent reads from it will return its default value.
315 + public mutating func clearAmount() {self._amount = nil}
316 +
317 + /// expiration time
318 + public var expireTime: Int64 = 0
319 +
320 + public var unknownFields = SwiftProtobuf.UnknownStorage()
321 +
322 + public init() {}
323 +
324 + fileprivate var _amount: TW_Binance_Proto_SendOrder.Token? = nil
325 +}
326 +
327 +public struct TW_Binance_Proto_SideChainDelegate {
328 + // SwiftProtobuf.Message conformance is added in an extension below. See the
329 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
330 + // methods supported on all messages.
331 +
332 + public var delegatorAddr: Data = Data()
333 +
334 + public var validatorAddr: Data = Data()
335 +
336 + public var delegation: TW_Binance_Proto_SendOrder.Token {
337 + get {return _delegation ?? TW_Binance_Proto_SendOrder.Token()}
338 + set {_delegation = newValue}
339 + }
340 + /// Returns true if `delegation` has been explicitly set.
341 + public var hasDelegation: Bool {return self._delegation != nil}
342 + /// Clears the value of `delegation`. Subsequent reads from it will return its default value.
343 + public mutating func clearDelegation() {self._delegation = nil}
344 +
345 + public var chainID: String = String()
346 +
347 + public var unknownFields = SwiftProtobuf.UnknownStorage()
348 +
349 + public init() {}
350 +
351 + fileprivate var _delegation: TW_Binance_Proto_SendOrder.Token? = nil
352 +}
353 +
354 +public struct TW_Binance_Proto_SideChainRedelegate {
355 + // SwiftProtobuf.Message conformance is added in an extension below. See the
356 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
357 + // methods supported on all messages.
358 +
359 + public var delegatorAddr: Data = Data()
360 +
361 + public var validatorSrcAddr: Data = Data()
362 +
363 + public var validatorDstAddr: Data = Data()
364 +
365 + public var amount: TW_Binance_Proto_SendOrder.Token {
366 + get {return _amount ?? TW_Binance_Proto_SendOrder.Token()}
367 + set {_amount = newValue}
368 + }
369 + /// Returns true if `amount` has been explicitly set.
370 + public var hasAmount: Bool {return self._amount != nil}
371 + /// Clears the value of `amount`. Subsequent reads from it will return its default value.
372 + public mutating func clearAmount() {self._amount = nil}
373 +
374 + public var chainID: String = String()
375 +
376 + public var unknownFields = SwiftProtobuf.UnknownStorage()
377 +
378 + public init() {}
379 +
380 + fileprivate var _amount: TW_Binance_Proto_SendOrder.Token? = nil
381 +}
382 +
383 +public struct TW_Binance_Proto_SideChainUndelegate {
384 + // SwiftProtobuf.Message conformance is added in an extension below. See the
385 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
386 + // methods supported on all messages.
387 +
388 + public var delegatorAddr: Data = Data()
389 +
390 + public var validatorAddr: Data = Data()
391 +
392 + public var amount: TW_Binance_Proto_SendOrder.Token {
393 + get {return _amount ?? TW_Binance_Proto_SendOrder.Token()}
394 + set {_amount = newValue}
395 + }
396 + /// Returns true if `amount` has been explicitly set.
397 + public var hasAmount: Bool {return self._amount != nil}
398 + /// Clears the value of `amount`. Subsequent reads from it will return its default value.
399 + public mutating func clearAmount() {self._amount = nil}
400 +
401 + public var chainID: String = String()
402 +
403 + public var unknownFields = SwiftProtobuf.UnknownStorage()
404 +
405 + public init() {}
406 +
407 + fileprivate var _amount: TW_Binance_Proto_SendOrder.Token? = nil
408 +}
409 +
410 +/// Message for BNB Beacon Chain -> BSC Stake Migration.
411 +/// https://github.com/bnb-chain/javascript-sdk/blob/26f6db8b67326e6214e74203ff90c89777b592a1/src/types/msg/stake/stakeMigrationMsg.ts#L13-L18
412 +public struct TW_Binance_Proto_SideChainStakeMigration {
413 + // SwiftProtobuf.Message conformance is added in an extension below. See the
414 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
415 + // methods supported on all messages.
416 +
417 + public var validatorSrcAddr: Data = Data()
418 +
419 + public var validatorDstAddr: Data = Data()
420 +
421 + public var delegatorAddr: Data = Data()
422 +
423 + public var refundAddr: Data = Data()
424 +
425 + public var amount: TW_Binance_Proto_SendOrder.Token {
426 + get {return _amount ?? TW_Binance_Proto_SendOrder.Token()}
427 + set {_amount = newValue}
428 + }
429 + /// Returns true if `amount` has been explicitly set.
430 + public var hasAmount: Bool {return self._amount != nil}
431 + /// Clears the value of `amount`. Subsequent reads from it will return its default value.
432 + public mutating func clearAmount() {self._amount = nil}
433 +
434 + public var unknownFields = SwiftProtobuf.UnknownStorage()
435 +
436 + public init() {}
437 +
438 + fileprivate var _amount: TW_Binance_Proto_SendOrder.Token? = nil
439 +}
440 +
441 +/// Message for TimeLock order
442 +public struct TW_Binance_Proto_TimeLockOrder {
443 + // SwiftProtobuf.Message conformance is added in an extension below. See the
444 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
445 + // methods supported on all messages.
446 +
447 + /// owner address
448 + public var fromAddress: Data = Data()
449 +
450 + /// Description (optional)
451 + public var description_p: String = String()
452 +
453 + /// Array of symbol/amount pairs. see SDK https://github.com/binance-chain/javascript-sdk/blob/master/docs/api-docs/classes/tokenmanagement.md#timelock
454 + public var amount: [TW_Binance_Proto_SendOrder.Token] = []
455 +
456 + /// lock time
457 + public var lockTime: Int64 = 0
458 +
459 + public var unknownFields = SwiftProtobuf.UnknownStorage()
460 +
461 + public init() {}
462 +}
463 +
464 +/// Message for TimeRelock order
465 +public struct TW_Binance_Proto_TimeRelockOrder {
466 + // SwiftProtobuf.Message conformance is added in an extension below. See the
467 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
468 + // methods supported on all messages.
469 +
470 + /// owner address
471 + public var fromAddress: Data = Data()
472 +
473 + /// order ID
474 + public var id: Int64 = 0
475 +
476 + /// Description (optional)
477 + public var description_p: String = String()
478 +
479 + /// Array of symbol/amount pairs.
480 + public var amount: [TW_Binance_Proto_SendOrder.Token] = []
481 +
482 + /// lock time
483 + public var lockTime: Int64 = 0
484 +
485 + public var unknownFields = SwiftProtobuf.UnknownStorage()
486 +
487 + public init() {}
488 +}
489 +
490 +/// Message for TimeUnlock order
491 +public struct TW_Binance_Proto_TimeUnlockOrder {
492 + // SwiftProtobuf.Message conformance is added in an extension below. See the
493 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
494 + // methods supported on all messages.
495 +
496 + /// owner address
497 + public var fromAddress: Data = Data()
498 +
499 + /// order ID
500 + public var id: Int64 = 0
501 +
502 + public var unknownFields = SwiftProtobuf.UnknownStorage()
503 +
504 + public init() {}
505 +}
506 +
507 +/// Input data necessary to create a signed transaction.
508 +public struct TW_Binance_Proto_SigningInput {
509 + // SwiftProtobuf.Message conformance is added in an extension below. See the
510 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
511 + // methods supported on all messages.
512 +
513 + /// Chain ID
514 + public var chainID: String = String()
515 +
516 + /// Source account number
517 + public var accountNumber: Int64 = 0
518 +
519 + /// Sequence number (account specific)
520 + public var sequence: Int64 = 0
521 +
522 + /// Transaction source, see https://github.com/bnb-chain/BEPs/blob/master/BEP10.md
523 + /// Some important values:
524 + /// 0: Default source value (e.g. for Binance Chain Command Line, or SDKs)
525 + /// 1: Binance DEX Web Wallet
526 + /// 2: Trust Wallet
527 + public var source: Int64 = 0
528 +
529 + /// Optional memo
530 + public var memo: String = String()
531 +
532 + /// The secret private key used for signing (32 bytes).
533 + public var privateKey: Data = Data()
534 +
535 + /// Payload message
536 + public var orderOneof: TW_Binance_Proto_SigningInput.OneOf_OrderOneof? = nil
537 +
538 + public var tradeOrder: TW_Binance_Proto_TradeOrder {
539 + get {
540 + if case .tradeOrder(let v)? = orderOneof {return v}
541 + return TW_Binance_Proto_TradeOrder()
542 + }
543 + set {orderOneof = .tradeOrder(newValue)}
544 + }
545 +
546 + public var cancelTradeOrder: TW_Binance_Proto_CancelTradeOrder {
547 + get {
548 + if case .cancelTradeOrder(let v)? = orderOneof {return v}
549 + return TW_Binance_Proto_CancelTradeOrder()
550 + }
551 + set {orderOneof = .cancelTradeOrder(newValue)}
552 + }
553 +
554 + public var sendOrder: TW_Binance_Proto_SendOrder {
555 + get {
556 + if case .sendOrder(let v)? = orderOneof {return v}
557 + return TW_Binance_Proto_SendOrder()
558 + }
559 + set {orderOneof = .sendOrder(newValue)}
560 + }
561 +
562 + public var htltOrder: TW_Binance_Proto_HTLTOrder {
563 + get {
564 + if case .htltOrder(let v)? = orderOneof {return v}
565 + return TW_Binance_Proto_HTLTOrder()
566 + }
567 + set {orderOneof = .htltOrder(newValue)}
568 + }
569 +
570 + public var depositHtltOrder: TW_Binance_Proto_DepositHTLTOrder {
571 + get {
572 + if case .depositHtltOrder(let v)? = orderOneof {return v}
573 + return TW_Binance_Proto_DepositHTLTOrder()
574 + }
575 + set {orderOneof = .depositHtltOrder(newValue)}
576 + }
577 +
578 + public var claimHtltOrder: TW_Binance_Proto_ClaimHTLOrder {
579 + get {
580 + if case .claimHtltOrder(let v)? = orderOneof {return v}
581 + return TW_Binance_Proto_ClaimHTLOrder()
582 + }
583 + set {orderOneof = .claimHtltOrder(newValue)}
584 + }
585 +
586 + public var refundHtltOrder: TW_Binance_Proto_RefundHTLTOrder {
587 + get {
588 + if case .refundHtltOrder(let v)? = orderOneof {return v}
589 + return TW_Binance_Proto_RefundHTLTOrder()
590 + }
591 + set {orderOneof = .refundHtltOrder(newValue)}
592 + }
593 +
594 + public var transferOutOrder: TW_Binance_Proto_TransferOut {
595 + get {
596 + if case .transferOutOrder(let v)? = orderOneof {return v}
597 + return TW_Binance_Proto_TransferOut()
598 + }
599 + set {orderOneof = .transferOutOrder(newValue)}
600 + }
601 +
602 + public var sideDelegateOrder: TW_Binance_Proto_SideChainDelegate {
603 + get {
604 + if case .sideDelegateOrder(let v)? = orderOneof {return v}
605 + return TW_Binance_Proto_SideChainDelegate()
606 + }
607 + set {orderOneof = .sideDelegateOrder(newValue)}
608 + }
609 +
610 + public var sideRedelegateOrder: TW_Binance_Proto_SideChainRedelegate {
611 + get {
612 + if case .sideRedelegateOrder(let v)? = orderOneof {return v}
613 + return TW_Binance_Proto_SideChainRedelegate()
614 + }
615 + set {orderOneof = .sideRedelegateOrder(newValue)}
616 + }
617 +
618 + public var sideUndelegateOrder: TW_Binance_Proto_SideChainUndelegate {
619 + get {
620 + if case .sideUndelegateOrder(let v)? = orderOneof {return v}
621 + return TW_Binance_Proto_SideChainUndelegate()
622 + }
623 + set {orderOneof = .sideUndelegateOrder(newValue)}
624 + }
625 +
626 + public var timeLockOrder: TW_Binance_Proto_TimeLockOrder {
627 + get {
628 + if case .timeLockOrder(let v)? = orderOneof {return v}
629 + return TW_Binance_Proto_TimeLockOrder()
630 + }
631 + set {orderOneof = .timeLockOrder(newValue)}
632 + }
633 +
634 + public var timeRelockOrder: TW_Binance_Proto_TimeRelockOrder {
635 + get {
636 + if case .timeRelockOrder(let v)? = orderOneof {return v}
637 + return TW_Binance_Proto_TimeRelockOrder()
638 + }
639 + set {orderOneof = .timeRelockOrder(newValue)}
640 + }
641 +
642 + public var timeUnlockOrder: TW_Binance_Proto_TimeUnlockOrder {
643 + get {
644 + if case .timeUnlockOrder(let v)? = orderOneof {return v}
645 + return TW_Binance_Proto_TimeUnlockOrder()
646 + }
647 + set {orderOneof = .timeUnlockOrder(newValue)}
648 + }
649 +
650 + public var sideStakeMigrationOrder: TW_Binance_Proto_SideChainStakeMigration {
651 + get {
652 + if case .sideStakeMigrationOrder(let v)? = orderOneof {return v}
653 + return TW_Binance_Proto_SideChainStakeMigration()
654 + }
655 + set {orderOneof = .sideStakeMigrationOrder(newValue)}
656 + }
657 +
658 + public var unknownFields = SwiftProtobuf.UnknownStorage()
659 +
660 + /// Payload message
661 + public enum OneOf_OrderOneof: Equatable {
662 + case tradeOrder(TW_Binance_Proto_TradeOrder)
663 + case cancelTradeOrder(TW_Binance_Proto_CancelTradeOrder)
664 + case sendOrder(TW_Binance_Proto_SendOrder)
665 + case htltOrder(TW_Binance_Proto_HTLTOrder)
666 + case depositHtltOrder(TW_Binance_Proto_DepositHTLTOrder)
667 + case claimHtltOrder(TW_Binance_Proto_ClaimHTLOrder)
668 + case refundHtltOrder(TW_Binance_Proto_RefundHTLTOrder)
669 + case transferOutOrder(TW_Binance_Proto_TransferOut)
670 + case sideDelegateOrder(TW_Binance_Proto_SideChainDelegate)
671 + case sideRedelegateOrder(TW_Binance_Proto_SideChainRedelegate)
672 + case sideUndelegateOrder(TW_Binance_Proto_SideChainUndelegate)
673 + case timeLockOrder(TW_Binance_Proto_TimeLockOrder)
674 + case timeRelockOrder(TW_Binance_Proto_TimeRelockOrder)
675 + case timeUnlockOrder(TW_Binance_Proto_TimeUnlockOrder)
676 + case sideStakeMigrationOrder(TW_Binance_Proto_SideChainStakeMigration)
677 +
678 + #if !swift(>=4.1)
679 + public static func ==(lhs: TW_Binance_Proto_SigningInput.OneOf_OrderOneof, rhs: TW_Binance_Proto_SigningInput.OneOf_OrderOneof) -> Bool {
680 + // The use of inline closures is to circumvent an issue where the compiler
681 + // allocates stack space for every case branch when no optimizations are
682 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
683 + switch (lhs, rhs) {
684 + case (.tradeOrder, .tradeOrder): return {
685 + guard case .tradeOrder(let l) = lhs, case .tradeOrder(let r) = rhs else { preconditionFailure() }
686 + return l == r
687 + }()
688 + case (.cancelTradeOrder, .cancelTradeOrder): return {
689 + guard case .cancelTradeOrder(let l) = lhs, case .cancelTradeOrder(let r) = rhs else { preconditionFailure() }
690 + return l == r
691 + }()
692 + case (.sendOrder, .sendOrder): return {
693 + guard case .sendOrder(let l) = lhs, case .sendOrder(let r) = rhs else { preconditionFailure() }
694 + return l == r
695 + }()
696 + case (.htltOrder, .htltOrder): return {
697 + guard case .htltOrder(let l) = lhs, case .htltOrder(let r) = rhs else { preconditionFailure() }
698 + return l == r
699 + }()
700 + case (.depositHtltOrder, .depositHtltOrder): return {
701 + guard case .depositHtltOrder(let l) = lhs, case .depositHtltOrder(let r) = rhs else { preconditionFailure() }
702 + return l == r
703 + }()
704 + case (.claimHtltOrder, .claimHtltOrder): return {
705 + guard case .claimHtltOrder(let l) = lhs, case .claimHtltOrder(let r) = rhs else { preconditionFailure() }
706 + return l == r
707 + }()
708 + case (.refundHtltOrder, .refundHtltOrder): return {
709 + guard case .refundHtltOrder(let l) = lhs, case .refundHtltOrder(let r) = rhs else { preconditionFailure() }
710 + return l == r
711 + }()
712 + case (.transferOutOrder, .transferOutOrder): return {
713 + guard case .transferOutOrder(let l) = lhs, case .transferOutOrder(let r) = rhs else { preconditionFailure() }
714 + return l == r
715 + }()
716 + case (.sideDelegateOrder, .sideDelegateOrder): return {
717 + guard case .sideDelegateOrder(let l) = lhs, case .sideDelegateOrder(let r) = rhs else { preconditionFailure() }
718 + return l == r
719 + }()
720 + case (.sideRedelegateOrder, .sideRedelegateOrder): return {
721 + guard case .sideRedelegateOrder(let l) = lhs, case .sideRedelegateOrder(let r) = rhs else { preconditionFailure() }
722 + return l == r
723 + }()
724 + case (.sideUndelegateOrder, .sideUndelegateOrder): return {
725 + guard case .sideUndelegateOrder(let l) = lhs, case .sideUndelegateOrder(let r) = rhs else { preconditionFailure() }
726 + return l == r
727 + }()
728 + case (.timeLockOrder, .timeLockOrder): return {
729 + guard case .timeLockOrder(let l) = lhs, case .timeLockOrder(let r) = rhs else { preconditionFailure() }
730 + return l == r
731 + }()
732 + case (.timeRelockOrder, .timeRelockOrder): return {
733 + guard case .timeRelockOrder(let l) = lhs, case .timeRelockOrder(let r) = rhs else { preconditionFailure() }
734 + return l == r
735 + }()
736 + case (.timeUnlockOrder, .timeUnlockOrder): return {
737 + guard case .timeUnlockOrder(let l) = lhs, case .timeUnlockOrder(let r) = rhs else { preconditionFailure() }
738 + return l == r
739 + }()
740 + case (.sideStakeMigrationOrder, .sideStakeMigrationOrder): return {
741 + guard case .sideStakeMigrationOrder(let l) = lhs, case .sideStakeMigrationOrder(let r) = rhs else { preconditionFailure() }
742 + return l == r
743 + }()
744 + default: return false
745 + }
746 + }
747 + #endif
748 + }
749 +
750 + public init() {}
751 +}
752 +
753 +/// Result containing the signed and encoded transaction.
754 +public struct TW_Binance_Proto_SigningOutput {
755 + // SwiftProtobuf.Message conformance is added in an extension below. See the
756 + // `Message` and `Message+*Additions` files in the SwiftProtobuf.library for
757 + // methods supported on all messages.
758 +
759 + /// Signed and encoded transaction bytes.
760 + public var encoded: Data = Data()
761 +
762 + /// OK (=0) or other codes in case of error
763 + public var error: TW_Common_Proto_SigningError = .ok
764 +
765 + /// error description in case of error
766 + public var errorMessage: String = String()
767 +
768 + /// Signature bytes.
769 + public var signature: Data = Data()
770 +
771 + /// Signature JSON string.
772 + public var signatureJson: String = String()
773 +
774 + public var unknownFields = SwiftProtobuf.UnknownStorage()
775 +
776 + public init() {}
777 +}
778 +
779 +// MARK: - Code below here is support for the SwiftProtobuf.runtime.
780 +
781 +fileprivate let _protobuf_package = "TW.Binance.Proto"
782 +
783 +extension TW_Binance_Proto_Transaction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
784 + public static let protoMessageName: String = _protobuf_package + ".Transaction"
785 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
786 + 1: .same(proto: "msgs"),
787 + 2: .same(proto: "signatures"),
788 + 3: .same(proto: "memo"),
789 + 4: .same(proto: "source"),
790 + 5: .same(proto: "data"),
791 + ]
792 +
793 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
794 + while let fieldNumber = try decoder.nextFieldNumber() {
795 + // The use of inline closures is to circumvent an issue where the compiler
796 + // allocates stack space for every case branch when no optimizations are
797 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
798 + switch fieldNumber {
799 + case 1: try { try decoder.decodeRepeatedBytesField(value: &self.msgs) }()
800 + case 2: try { try decoder.decodeRepeatedBytesField(value: &self.signatures) }()
801 + case 3: try { try decoder.decodeSingularStringField(value: &self.memo) }()
802 + case 4: try { try decoder.decodeSingularInt64Field(value: &self.source) }()
803 + case 5: try { try decoder.decodeSingularBytesField(value: &self.data) }()
804 + default: break
805 + }
806 + }
807 + }
808 +
809 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
810 + if !self.msgs.isEmpty {
811 + try visitor.visitRepeatedBytesField(value: self.msgs, fieldNumber: 1)
812 + }
813 + if !self.signatures.isEmpty {
814 + try visitor.visitRepeatedBytesField(value: self.signatures, fieldNumber: 2)
815 + }
816 + if !self.memo.isEmpty {
817 + try visitor.visitSingularStringField(value: self.memo, fieldNumber: 3)
818 + }
819 + if self.source != 0 {
820 + try visitor.visitSingularInt64Field(value: self.source, fieldNumber: 4)
821 + }
822 + if !self.data.isEmpty {
823 + try visitor.visitSingularBytesField(value: self.data, fieldNumber: 5)
824 + }
825 + try unknownFields.traverse(visitor: &visitor)
826 + }
827 +
828 + public static func ==(lhs: TW_Binance_Proto_Transaction, rhs: TW_Binance_Proto_Transaction) -> Bool {
829 + if lhs.msgs != rhs.msgs {return false}
830 + if lhs.signatures != rhs.signatures {return false}
831 + if lhs.memo != rhs.memo {return false}
832 + if lhs.source != rhs.source {return false}
833 + if lhs.data != rhs.data {return false}
834 + if lhs.unknownFields != rhs.unknownFields {return false}
835 + return true
836 + }
837 +}
838 +
839 +extension TW_Binance_Proto_Signature: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
840 + public static let protoMessageName: String = _protobuf_package + ".Signature"
841 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
842 + 1: .standard(proto: "pub_key"),
843 + 2: .same(proto: "signature"),
844 + 3: .standard(proto: "account_number"),
845 + 4: .same(proto: "sequence"),
846 + ]
847 +
848 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
849 + while let fieldNumber = try decoder.nextFieldNumber() {
850 + // The use of inline closures is to circumvent an issue where the compiler
851 + // allocates stack space for every case branch when no optimizations are
852 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
853 + switch fieldNumber {
854 + case 1: try { try decoder.decodeSingularBytesField(value: &self.pubKey) }()
855 + case 2: try { try decoder.decodeSingularBytesField(value: &self.signature) }()
856 + case 3: try { try decoder.decodeSingularInt64Field(value: &self.accountNumber) }()
857 + case 4: try { try decoder.decodeSingularInt64Field(value: &self.sequence) }()
858 + default: break
859 + }
860 + }
861 + }
862 +
863 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
864 + if !self.pubKey.isEmpty {
865 + try visitor.visitSingularBytesField(value: self.pubKey, fieldNumber: 1)
866 + }
867 + if !self.signature.isEmpty {
868 + try visitor.visitSingularBytesField(value: self.signature, fieldNumber: 2)
869 + }
870 + if self.accountNumber != 0 {
871 + try visitor.visitSingularInt64Field(value: self.accountNumber, fieldNumber: 3)
872 + }
873 + if self.sequence != 0 {
874 + try visitor.visitSingularInt64Field(value: self.sequence, fieldNumber: 4)
875 + }
876 + try unknownFields.traverse(visitor: &visitor)
877 + }
878 +
879 + public static func ==(lhs: TW_Binance_Proto_Signature, rhs: TW_Binance_Proto_Signature) -> Bool {
880 + if lhs.pubKey != rhs.pubKey {return false}
881 + if lhs.signature != rhs.signature {return false}
882 + if lhs.accountNumber != rhs.accountNumber {return false}
883 + if lhs.sequence != rhs.sequence {return false}
884 + if lhs.unknownFields != rhs.unknownFields {return false}
885 + return true
886 + }
887 +}
888 +
889 +extension TW_Binance_Proto_TradeOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
890 + public static let protoMessageName: String = _protobuf_package + ".TradeOrder"
891 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
892 + 1: .same(proto: "sender"),
893 + 2: .same(proto: "id"),
894 + 3: .same(proto: "symbol"),
895 + 4: .same(proto: "ordertype"),
896 + 5: .same(proto: "side"),
897 + 6: .same(proto: "price"),
898 + 7: .same(proto: "quantity"),
899 + 8: .same(proto: "timeinforce"),
900 + ]
901 +
902 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
903 + while let fieldNumber = try decoder.nextFieldNumber() {
904 + // The use of inline closures is to circumvent an issue where the compiler
905 + // allocates stack space for every case branch when no optimizations are
906 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
907 + switch fieldNumber {
908 + case 1: try { try decoder.decodeSingularBytesField(value: &self.sender) }()
909 + case 2: try { try decoder.decodeSingularStringField(value: &self.id) }()
910 + case 3: try { try decoder.decodeSingularStringField(value: &self.symbol) }()
911 + case 4: try { try decoder.decodeSingularInt64Field(value: &self.ordertype) }()
912 + case 5: try { try decoder.decodeSingularInt64Field(value: &self.side) }()
913 + case 6: try { try decoder.decodeSingularInt64Field(value: &self.price) }()
914 + case 7: try { try decoder.decodeSingularInt64Field(value: &self.quantity) }()
915 + case 8: try { try decoder.decodeSingularInt64Field(value: &self.timeinforce) }()
916 + default: break
917 + }
918 + }
919 + }
920 +
921 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
922 + if !self.sender.isEmpty {
923 + try visitor.visitSingularBytesField(value: self.sender, fieldNumber: 1)
924 + }
925 + if !self.id.isEmpty {
926 + try visitor.visitSingularStringField(value: self.id, fieldNumber: 2)
927 + }
928 + if !self.symbol.isEmpty {
929 + try visitor.visitSingularStringField(value: self.symbol, fieldNumber: 3)
930 + }
931 + if self.ordertype != 0 {
932 + try visitor.visitSingularInt64Field(value: self.ordertype, fieldNumber: 4)
933 + }
934 + if self.side != 0 {
935 + try visitor.visitSingularInt64Field(value: self.side, fieldNumber: 5)
936 + }
937 + if self.price != 0 {
938 + try visitor.visitSingularInt64Field(value: self.price, fieldNumber: 6)
939 + }
940 + if self.quantity != 0 {
941 + try visitor.visitSingularInt64Field(value: self.quantity, fieldNumber: 7)
942 + }
943 + if self.timeinforce != 0 {
944 + try visitor.visitSingularInt64Field(value: self.timeinforce, fieldNumber: 8)
945 + }
946 + try unknownFields.traverse(visitor: &visitor)
947 + }
948 +
949 + public static func ==(lhs: TW_Binance_Proto_TradeOrder, rhs: TW_Binance_Proto_TradeOrder) -> Bool {
950 + if lhs.sender != rhs.sender {return false}
951 + if lhs.id != rhs.id {return false}
952 + if lhs.symbol != rhs.symbol {return false}
953 + if lhs.ordertype != rhs.ordertype {return false}
954 + if lhs.side != rhs.side {return false}
955 + if lhs.price != rhs.price {return false}
956 + if lhs.quantity != rhs.quantity {return false}
957 + if lhs.timeinforce != rhs.timeinforce {return false}
958 + if lhs.unknownFields != rhs.unknownFields {return false}
959 + return true
960 + }
961 +}
962 +
963 +extension TW_Binance_Proto_CancelTradeOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
964 + public static let protoMessageName: String = _protobuf_package + ".CancelTradeOrder"
965 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
966 + 1: .same(proto: "sender"),
967 + 2: .same(proto: "symbol"),
968 + 3: .same(proto: "refid"),
969 + ]
970 +
971 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
972 + while let fieldNumber = try decoder.nextFieldNumber() {
973 + // The use of inline closures is to circumvent an issue where the compiler
974 + // allocates stack space for every case branch when no optimizations are
975 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
976 + switch fieldNumber {
977 + case 1: try { try decoder.decodeSingularBytesField(value: &self.sender) }()
978 + case 2: try { try decoder.decodeSingularStringField(value: &self.symbol) }()
979 + case 3: try { try decoder.decodeSingularStringField(value: &self.refid) }()
980 + default: break
981 + }
982 + }
983 + }
984 +
985 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
986 + if !self.sender.isEmpty {
987 + try visitor.visitSingularBytesField(value: self.sender, fieldNumber: 1)
988 + }
989 + if !self.symbol.isEmpty {
990 + try visitor.visitSingularStringField(value: self.symbol, fieldNumber: 2)
991 + }
992 + if !self.refid.isEmpty {
993 + try visitor.visitSingularStringField(value: self.refid, fieldNumber: 3)
994 + }
995 + try unknownFields.traverse(visitor: &visitor)
996 + }
997 +
998 + public static func ==(lhs: TW_Binance_Proto_CancelTradeOrder, rhs: TW_Binance_Proto_CancelTradeOrder) -> Bool {
999 + if lhs.sender != rhs.sender {return false}
1000 + if lhs.symbol != rhs.symbol {return false}
1001 + if lhs.refid != rhs.refid {return false}
1002 + if lhs.unknownFields != rhs.unknownFields {return false}
1003 + return true
1004 + }
1005 +}
1006 +
1007 +extension TW_Binance_Proto_SendOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1008 + public static let protoMessageName: String = _protobuf_package + ".SendOrder"
1009 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1010 + 1: .same(proto: "inputs"),
1011 + 2: .same(proto: "outputs"),
1012 + ]
1013 +
1014 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1015 + while let fieldNumber = try decoder.nextFieldNumber() {
1016 + // The use of inline closures is to circumvent an issue where the compiler
1017 + // allocates stack space for every case branch when no optimizations are
1018 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1019 + switch fieldNumber {
1020 + case 1: try { try decoder.decodeRepeatedMessageField(value: &self.inputs) }()
1021 + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputs) }()
1022 + default: break
1023 + }
1024 + }
1025 + }
1026 +
1027 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1028 + if !self.inputs.isEmpty {
1029 + try visitor.visitRepeatedMessageField(value: self.inputs, fieldNumber: 1)
1030 + }
1031 + if !self.outputs.isEmpty {
1032 + try visitor.visitRepeatedMessageField(value: self.outputs, fieldNumber: 2)
1033 + }
1034 + try unknownFields.traverse(visitor: &visitor)
1035 + }
1036 +
1037 + public static func ==(lhs: TW_Binance_Proto_SendOrder, rhs: TW_Binance_Proto_SendOrder) -> Bool {
1038 + if lhs.inputs != rhs.inputs {return false}
1039 + if lhs.outputs != rhs.outputs {return false}
1040 + if lhs.unknownFields != rhs.unknownFields {return false}
1041 + return true
1042 + }
1043 +}
1044 +
1045 +extension TW_Binance_Proto_SendOrder.Token: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1046 + public static let protoMessageName: String = TW_Binance_Proto_SendOrder.protoMessageName + ".Token"
1047 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1048 + 1: .same(proto: "denom"),
1049 + 2: .same(proto: "amount"),
1050 + ]
1051 +
1052 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1053 + while let fieldNumber = try decoder.nextFieldNumber() {
1054 + // The use of inline closures is to circumvent an issue where the compiler
1055 + // allocates stack space for every case branch when no optimizations are
1056 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1057 + switch fieldNumber {
1058 + case 1: try { try decoder.decodeSingularStringField(value: &self.denom) }()
1059 + case 2: try { try decoder.decodeSingularInt64Field(value: &self.amount) }()
1060 + default: break
1061 + }
1062 + }
1063 + }
1064 +
1065 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1066 + if !self.denom.isEmpty {
1067 + try visitor.visitSingularStringField(value: self.denom, fieldNumber: 1)
1068 + }
1069 + if self.amount != 0 {
1070 + try visitor.visitSingularInt64Field(value: self.amount, fieldNumber: 2)
1071 + }
1072 + try unknownFields.traverse(visitor: &visitor)
1073 + }
1074 +
1075 + public static func ==(lhs: TW_Binance_Proto_SendOrder.Token, rhs: TW_Binance_Proto_SendOrder.Token) -> Bool {
1076 + if lhs.denom != rhs.denom {return false}
1077 + if lhs.amount != rhs.amount {return false}
1078 + if lhs.unknownFields != rhs.unknownFields {return false}
1079 + return true
1080 + }
1081 +}
1082 +
1083 +extension TW_Binance_Proto_SendOrder.Input: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1084 + public static let protoMessageName: String = TW_Binance_Proto_SendOrder.protoMessageName + ".Input"
1085 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1086 + 1: .same(proto: "address"),
1087 + 2: .same(proto: "coins"),
1088 + ]
1089 +
1090 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1091 + while let fieldNumber = try decoder.nextFieldNumber() {
1092 + // The use of inline closures is to circumvent an issue where the compiler
1093 + // allocates stack space for every case branch when no optimizations are
1094 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1095 + switch fieldNumber {
1096 + case 1: try { try decoder.decodeSingularBytesField(value: &self.address) }()
1097 + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.coins) }()
1098 + default: break
1099 + }
1100 + }
1101 + }
1102 +
1103 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1104 + if !self.address.isEmpty {
1105 + try visitor.visitSingularBytesField(value: self.address, fieldNumber: 1)
1106 + }
1107 + if !self.coins.isEmpty {
1108 + try visitor.visitRepeatedMessageField(value: self.coins, fieldNumber: 2)
1109 + }
1110 + try unknownFields.traverse(visitor: &visitor)
1111 + }
1112 +
1113 + public static func ==(lhs: TW_Binance_Proto_SendOrder.Input, rhs: TW_Binance_Proto_SendOrder.Input) -> Bool {
1114 + if lhs.address != rhs.address {return false}
1115 + if lhs.coins != rhs.coins {return false}
1116 + if lhs.unknownFields != rhs.unknownFields {return false}
1117 + return true
1118 + }
1119 +}
1120 +
1121 +extension TW_Binance_Proto_SendOrder.Output: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1122 + public static let protoMessageName: String = TW_Binance_Proto_SendOrder.protoMessageName + ".Output"
1123 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1124 + 1: .same(proto: "address"),
1125 + 2: .same(proto: "coins"),
1126 + ]
1127 +
1128 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1129 + while let fieldNumber = try decoder.nextFieldNumber() {
1130 + // The use of inline closures is to circumvent an issue where the compiler
1131 + // allocates stack space for every case branch when no optimizations are
1132 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1133 + switch fieldNumber {
1134 + case 1: try { try decoder.decodeSingularBytesField(value: &self.address) }()
1135 + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.coins) }()
1136 + default: break
1137 + }
1138 + }
1139 + }
1140 +
1141 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1142 + if !self.address.isEmpty {
1143 + try visitor.visitSingularBytesField(value: self.address, fieldNumber: 1)
1144 + }
1145 + if !self.coins.isEmpty {
1146 + try visitor.visitRepeatedMessageField(value: self.coins, fieldNumber: 2)
1147 + }
1148 + try unknownFields.traverse(visitor: &visitor)
1149 + }
1150 +
1151 + public static func ==(lhs: TW_Binance_Proto_SendOrder.Output, rhs: TW_Binance_Proto_SendOrder.Output) -> Bool {
1152 + if lhs.address != rhs.address {return false}
1153 + if lhs.coins != rhs.coins {return false}
1154 + if lhs.unknownFields != rhs.unknownFields {return false}
1155 + return true
1156 + }
1157 +}
1158 +
1159 +extension TW_Binance_Proto_HTLTOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1160 + public static let protoMessageName: String = _protobuf_package + ".HTLTOrder"
1161 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1162 + 1: .same(proto: "from"),
1163 + 2: .same(proto: "to"),
1164 + 3: .standard(proto: "recipient_other_chain"),
1165 + 4: .standard(proto: "sender_other_chain"),
1166 + 5: .standard(proto: "random_number_hash"),
1167 + 6: .same(proto: "timestamp"),
1168 + 7: .same(proto: "amount"),
1169 + 8: .standard(proto: "expected_income"),
1170 + 9: .standard(proto: "height_span"),
1171 + 10: .standard(proto: "cross_chain"),
1172 + ]
1173 +
1174 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1175 + while let fieldNumber = try decoder.nextFieldNumber() {
1176 + // The use of inline closures is to circumvent an issue where the compiler
1177 + // allocates stack space for every case branch when no optimizations are
1178 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1179 + switch fieldNumber {
1180 + case 1: try { try decoder.decodeSingularBytesField(value: &self.from) }()
1181 + case 2: try { try decoder.decodeSingularBytesField(value: &self.to) }()
1182 + case 3: try { try decoder.decodeSingularStringField(value: &self.recipientOtherChain) }()
1183 + case 4: try { try decoder.decodeSingularStringField(value: &self.senderOtherChain) }()
1184 + case 5: try { try decoder.decodeSingularBytesField(value: &self.randomNumberHash) }()
1185 + case 6: try { try decoder.decodeSingularInt64Field(value: &self.timestamp) }()
1186 + case 7: try { try decoder.decodeRepeatedMessageField(value: &self.amount) }()
1187 + case 8: try { try decoder.decodeSingularStringField(value: &self.expectedIncome) }()
1188 + case 9: try { try decoder.decodeSingularInt64Field(value: &self.heightSpan) }()
1189 + case 10: try { try decoder.decodeSingularBoolField(value: &self.crossChain) }()
1190 + default: break
1191 + }
1192 + }
1193 + }
1194 +
1195 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1196 + if !self.from.isEmpty {
1197 + try visitor.visitSingularBytesField(value: self.from, fieldNumber: 1)
1198 + }
1199 + if !self.to.isEmpty {
1200 + try visitor.visitSingularBytesField(value: self.to, fieldNumber: 2)
1201 + }
1202 + if !self.recipientOtherChain.isEmpty {
1203 + try visitor.visitSingularStringField(value: self.recipientOtherChain, fieldNumber: 3)
1204 + }
1205 + if !self.senderOtherChain.isEmpty {
1206 + try visitor.visitSingularStringField(value: self.senderOtherChain, fieldNumber: 4)
1207 + }
1208 + if !self.randomNumberHash.isEmpty {
1209 + try visitor.visitSingularBytesField(value: self.randomNumberHash, fieldNumber: 5)
1210 + }
1211 + if self.timestamp != 0 {
1212 + try visitor.visitSingularInt64Field(value: self.timestamp, fieldNumber: 6)
1213 + }
1214 + if !self.amount.isEmpty {
1215 + try visitor.visitRepeatedMessageField(value: self.amount, fieldNumber: 7)
1216 + }
1217 + if !self.expectedIncome.isEmpty {
1218 + try visitor.visitSingularStringField(value: self.expectedIncome, fieldNumber: 8)
1219 + }
1220 + if self.heightSpan != 0 {
1221 + try visitor.visitSingularInt64Field(value: self.heightSpan, fieldNumber: 9)
1222 + }
1223 + if self.crossChain != false {
1224 + try visitor.visitSingularBoolField(value: self.crossChain, fieldNumber: 10)
1225 + }
1226 + try unknownFields.traverse(visitor: &visitor)
1227 + }
1228 +
1229 + public static func ==(lhs: TW_Binance_Proto_HTLTOrder, rhs: TW_Binance_Proto_HTLTOrder) -> Bool {
1230 + if lhs.from != rhs.from {return false}
1231 + if lhs.to != rhs.to {return false}
1232 + if lhs.recipientOtherChain != rhs.recipientOtherChain {return false}
1233 + if lhs.senderOtherChain != rhs.senderOtherChain {return false}
1234 + if lhs.randomNumberHash != rhs.randomNumberHash {return false}
1235 + if lhs.timestamp != rhs.timestamp {return false}
1236 + if lhs.amount != rhs.amount {return false}
1237 + if lhs.expectedIncome != rhs.expectedIncome {return false}
1238 + if lhs.heightSpan != rhs.heightSpan {return false}
1239 + if lhs.crossChain != rhs.crossChain {return false}
1240 + if lhs.unknownFields != rhs.unknownFields {return false}
1241 + return true
1242 + }
1243 +}
1244 +
1245 +extension TW_Binance_Proto_DepositHTLTOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1246 + public static let protoMessageName: String = _protobuf_package + ".DepositHTLTOrder"
1247 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1248 + 1: .same(proto: "from"),
1249 + 2: .same(proto: "amount"),
1250 + 3: .standard(proto: "swap_id"),
1251 + ]
1252 +
1253 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1254 + while let fieldNumber = try decoder.nextFieldNumber() {
1255 + // The use of inline closures is to circumvent an issue where the compiler
1256 + // allocates stack space for every case branch when no optimizations are
1257 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1258 + switch fieldNumber {
1259 + case 1: try { try decoder.decodeSingularBytesField(value: &self.from) }()
1260 + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.amount) }()
1261 + case 3: try { try decoder.decodeSingularBytesField(value: &self.swapID) }()
1262 + default: break
1263 + }
1264 + }
1265 + }
1266 +
1267 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1268 + if !self.from.isEmpty {
1269 + try visitor.visitSingularBytesField(value: self.from, fieldNumber: 1)
1270 + }
1271 + if !self.amount.isEmpty {
1272 + try visitor.visitRepeatedMessageField(value: self.amount, fieldNumber: 2)
1273 + }
1274 + if !self.swapID.isEmpty {
1275 + try visitor.visitSingularBytesField(value: self.swapID, fieldNumber: 3)
1276 + }
1277 + try unknownFields.traverse(visitor: &visitor)
1278 + }
1279 +
1280 + public static func ==(lhs: TW_Binance_Proto_DepositHTLTOrder, rhs: TW_Binance_Proto_DepositHTLTOrder) -> Bool {
1281 + if lhs.from != rhs.from {return false}
1282 + if lhs.amount != rhs.amount {return false}
1283 + if lhs.swapID != rhs.swapID {return false}
1284 + if lhs.unknownFields != rhs.unknownFields {return false}
1285 + return true
1286 + }
1287 +}
1288 +
1289 +extension TW_Binance_Proto_ClaimHTLOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1290 + public static let protoMessageName: String = _protobuf_package + ".ClaimHTLOrder"
1291 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1292 + 1: .same(proto: "from"),
1293 + 2: .standard(proto: "swap_id"),
1294 + 3: .standard(proto: "random_number"),
1295 + ]
1296 +
1297 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1298 + while let fieldNumber = try decoder.nextFieldNumber() {
1299 + // The use of inline closures is to circumvent an issue where the compiler
1300 + // allocates stack space for every case branch when no optimizations are
1301 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1302 + switch fieldNumber {
1303 + case 1: try { try decoder.decodeSingularBytesField(value: &self.from) }()
1304 + case 2: try { try decoder.decodeSingularBytesField(value: &self.swapID) }()
1305 + case 3: try { try decoder.decodeSingularBytesField(value: &self.randomNumber) }()
1306 + default: break
1307 + }
1308 + }
1309 + }
1310 +
1311 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1312 + if !self.from.isEmpty {
1313 + try visitor.visitSingularBytesField(value: self.from, fieldNumber: 1)
1314 + }
1315 + if !self.swapID.isEmpty {
1316 + try visitor.visitSingularBytesField(value: self.swapID, fieldNumber: 2)
1317 + }
1318 + if !self.randomNumber.isEmpty {
1319 + try visitor.visitSingularBytesField(value: self.randomNumber, fieldNumber: 3)
1320 + }
1321 + try unknownFields.traverse(visitor: &visitor)
1322 + }
1323 +
1324 + public static func ==(lhs: TW_Binance_Proto_ClaimHTLOrder, rhs: TW_Binance_Proto_ClaimHTLOrder) -> Bool {
1325 + if lhs.from != rhs.from {return false}
1326 + if lhs.swapID != rhs.swapID {return false}
1327 + if lhs.randomNumber != rhs.randomNumber {return false}
1328 + if lhs.unknownFields != rhs.unknownFields {return false}
1329 + return true
1330 + }
1331 +}
1332 +
1333 +extension TW_Binance_Proto_RefundHTLTOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1334 + public static let protoMessageName: String = _protobuf_package + ".RefundHTLTOrder"
1335 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1336 + 1: .same(proto: "from"),
1337 + 2: .standard(proto: "swap_id"),
1338 + ]
1339 +
1340 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1341 + while let fieldNumber = try decoder.nextFieldNumber() {
1342 + // The use of inline closures is to circumvent an issue where the compiler
1343 + // allocates stack space for every case branch when no optimizations are
1344 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1345 + switch fieldNumber {
1346 + case 1: try { try decoder.decodeSingularBytesField(value: &self.from) }()
1347 + case 2: try { try decoder.decodeSingularBytesField(value: &self.swapID) }()
1348 + default: break
1349 + }
1350 + }
1351 + }
1352 +
1353 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1354 + if !self.from.isEmpty {
1355 + try visitor.visitSingularBytesField(value: self.from, fieldNumber: 1)
1356 + }
1357 + if !self.swapID.isEmpty {
1358 + try visitor.visitSingularBytesField(value: self.swapID, fieldNumber: 2)
1359 + }
1360 + try unknownFields.traverse(visitor: &visitor)
1361 + }
1362 +
1363 + public static func ==(lhs: TW_Binance_Proto_RefundHTLTOrder, rhs: TW_Binance_Proto_RefundHTLTOrder) -> Bool {
1364 + if lhs.from != rhs.from {return false}
1365 + if lhs.swapID != rhs.swapID {return false}
1366 + if lhs.unknownFields != rhs.unknownFields {return false}
1367 + return true
1368 + }
1369 +}
1370 +
1371 +extension TW_Binance_Proto_TransferOut: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1372 + public static let protoMessageName: String = _protobuf_package + ".TransferOut"
1373 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1374 + 1: .same(proto: "from"),
1375 + 2: .same(proto: "to"),
1376 + 3: .same(proto: "amount"),
1377 + 4: .standard(proto: "expire_time"),
1378 + ]
1379 +
1380 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1381 + while let fieldNumber = try decoder.nextFieldNumber() {
1382 + // The use of inline closures is to circumvent an issue where the compiler
1383 + // allocates stack space for every case branch when no optimizations are
1384 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1385 + switch fieldNumber {
1386 + case 1: try { try decoder.decodeSingularBytesField(value: &self.from) }()
1387 + case 2: try { try decoder.decodeSingularBytesField(value: &self.to) }()
1388 + case 3: try { try decoder.decodeSingularMessageField(value: &self._amount) }()
1389 + case 4: try { try decoder.decodeSingularInt64Field(value: &self.expireTime) }()
1390 + default: break
1391 + }
1392 + }
1393 + }
1394 +
1395 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1396 + // The use of inline closures is to circumvent an issue where the compiler
1397 + // allocates stack space for every if/case branch local when no optimizations
1398 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1399 + // https://github.com/apple/swift-protobuf/issues/1182
1400 + if !self.from.isEmpty {
1401 + try visitor.visitSingularBytesField(value: self.from, fieldNumber: 1)
1402 + }
1403 + if !self.to.isEmpty {
1404 + try visitor.visitSingularBytesField(value: self.to, fieldNumber: 2)
1405 + }
1406 + try { if let v = self._amount {
1407 + try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
1408 + } }()
1409 + if self.expireTime != 0 {
1410 + try visitor.visitSingularInt64Field(value: self.expireTime, fieldNumber: 4)
1411 + }
1412 + try unknownFields.traverse(visitor: &visitor)
1413 + }
1414 +
1415 + public static func ==(lhs: TW_Binance_Proto_TransferOut, rhs: TW_Binance_Proto_TransferOut) -> Bool {
1416 + if lhs.from != rhs.from {return false}
1417 + if lhs.to != rhs.to {return false}
1418 + if lhs._amount != rhs._amount {return false}
1419 + if lhs.expireTime != rhs.expireTime {return false}
1420 + if lhs.unknownFields != rhs.unknownFields {return false}
1421 + return true
1422 + }
1423 +}
1424 +
1425 +extension TW_Binance_Proto_SideChainDelegate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1426 + public static let protoMessageName: String = _protobuf_package + ".SideChainDelegate"
1427 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1428 + 1: .standard(proto: "delegator_addr"),
1429 + 2: .standard(proto: "validator_addr"),
1430 + 3: .same(proto: "delegation"),
1431 + 4: .standard(proto: "chain_id"),
1432 + ]
1433 +
1434 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1435 + while let fieldNumber = try decoder.nextFieldNumber() {
1436 + // The use of inline closures is to circumvent an issue where the compiler
1437 + // allocates stack space for every case branch when no optimizations are
1438 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1439 + switch fieldNumber {
1440 + case 1: try { try decoder.decodeSingularBytesField(value: &self.delegatorAddr) }()
1441 + case 2: try { try decoder.decodeSingularBytesField(value: &self.validatorAddr) }()
1442 + case 3: try { try decoder.decodeSingularMessageField(value: &self._delegation) }()
1443 + case 4: try { try decoder.decodeSingularStringField(value: &self.chainID) }()
1444 + default: break
1445 + }
1446 + }
1447 + }
1448 +
1449 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1450 + // The use of inline closures is to circumvent an issue where the compiler
1451 + // allocates stack space for every if/case branch local when no optimizations
1452 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1453 + // https://github.com/apple/swift-protobuf/issues/1182
1454 + if !self.delegatorAddr.isEmpty {
1455 + try visitor.visitSingularBytesField(value: self.delegatorAddr, fieldNumber: 1)
1456 + }
1457 + if !self.validatorAddr.isEmpty {
1458 + try visitor.visitSingularBytesField(value: self.validatorAddr, fieldNumber: 2)
1459 + }
1460 + try { if let v = self._delegation {
1461 + try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
1462 + } }()
1463 + if !self.chainID.isEmpty {
1464 + try visitor.visitSingularStringField(value: self.chainID, fieldNumber: 4)
1465 + }
1466 + try unknownFields.traverse(visitor: &visitor)
1467 + }
1468 +
1469 + public static func ==(lhs: TW_Binance_Proto_SideChainDelegate, rhs: TW_Binance_Proto_SideChainDelegate) -> Bool {
1470 + if lhs.delegatorAddr != rhs.delegatorAddr {return false}
1471 + if lhs.validatorAddr != rhs.validatorAddr {return false}
1472 + if lhs._delegation != rhs._delegation {return false}
1473 + if lhs.chainID != rhs.chainID {return false}
1474 + if lhs.unknownFields != rhs.unknownFields {return false}
1475 + return true
1476 + }
1477 +}
1478 +
1479 +extension TW_Binance_Proto_SideChainRedelegate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1480 + public static let protoMessageName: String = _protobuf_package + ".SideChainRedelegate"
1481 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1482 + 1: .standard(proto: "delegator_addr"),
1483 + 2: .standard(proto: "validator_src_addr"),
1484 + 3: .standard(proto: "validator_dst_addr"),
1485 + 4: .same(proto: "amount"),
1486 + 5: .standard(proto: "chain_id"),
1487 + ]
1488 +
1489 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1490 + while let fieldNumber = try decoder.nextFieldNumber() {
1491 + // The use of inline closures is to circumvent an issue where the compiler
1492 + // allocates stack space for every case branch when no optimizations are
1493 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1494 + switch fieldNumber {
1495 + case 1: try { try decoder.decodeSingularBytesField(value: &self.delegatorAddr) }()
1496 + case 2: try { try decoder.decodeSingularBytesField(value: &self.validatorSrcAddr) }()
1497 + case 3: try { try decoder.decodeSingularBytesField(value: &self.validatorDstAddr) }()
1498 + case 4: try { try decoder.decodeSingularMessageField(value: &self._amount) }()
1499 + case 5: try { try decoder.decodeSingularStringField(value: &self.chainID) }()
1500 + default: break
1501 + }
1502 + }
1503 + }
1504 +
1505 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1506 + // The use of inline closures is to circumvent an issue where the compiler
1507 + // allocates stack space for every if/case branch local when no optimizations
1508 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1509 + // https://github.com/apple/swift-protobuf/issues/1182
1510 + if !self.delegatorAddr.isEmpty {
1511 + try visitor.visitSingularBytesField(value: self.delegatorAddr, fieldNumber: 1)
1512 + }
1513 + if !self.validatorSrcAddr.isEmpty {
1514 + try visitor.visitSingularBytesField(value: self.validatorSrcAddr, fieldNumber: 2)
1515 + }
1516 + if !self.validatorDstAddr.isEmpty {
1517 + try visitor.visitSingularBytesField(value: self.validatorDstAddr, fieldNumber: 3)
1518 + }
1519 + try { if let v = self._amount {
1520 + try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
1521 + } }()
1522 + if !self.chainID.isEmpty {
1523 + try visitor.visitSingularStringField(value: self.chainID, fieldNumber: 5)
1524 + }
1525 + try unknownFields.traverse(visitor: &visitor)
1526 + }
1527 +
1528 + public static func ==(lhs: TW_Binance_Proto_SideChainRedelegate, rhs: TW_Binance_Proto_SideChainRedelegate) -> Bool {
1529 + if lhs.delegatorAddr != rhs.delegatorAddr {return false}
1530 + if lhs.validatorSrcAddr != rhs.validatorSrcAddr {return false}
1531 + if lhs.validatorDstAddr != rhs.validatorDstAddr {return false}
1532 + if lhs._amount != rhs._amount {return false}
1533 + if lhs.chainID != rhs.chainID {return false}
1534 + if lhs.unknownFields != rhs.unknownFields {return false}
1535 + return true
1536 + }
1537 +}
1538 +
1539 +extension TW_Binance_Proto_SideChainUndelegate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1540 + public static let protoMessageName: String = _protobuf_package + ".SideChainUndelegate"
1541 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1542 + 1: .standard(proto: "delegator_addr"),
1543 + 2: .standard(proto: "validator_addr"),
1544 + 3: .same(proto: "amount"),
1545 + 4: .standard(proto: "chain_id"),
1546 + ]
1547 +
1548 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1549 + while let fieldNumber = try decoder.nextFieldNumber() {
1550 + // The use of inline closures is to circumvent an issue where the compiler
1551 + // allocates stack space for every case branch when no optimizations are
1552 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1553 + switch fieldNumber {
1554 + case 1: try { try decoder.decodeSingularBytesField(value: &self.delegatorAddr) }()
1555 + case 2: try { try decoder.decodeSingularBytesField(value: &self.validatorAddr) }()
1556 + case 3: try { try decoder.decodeSingularMessageField(value: &self._amount) }()
1557 + case 4: try { try decoder.decodeSingularStringField(value: &self.chainID) }()
1558 + default: break
1559 + }
1560 + }
1561 + }
1562 +
1563 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1564 + // The use of inline closures is to circumvent an issue where the compiler
1565 + // allocates stack space for every if/case branch local when no optimizations
1566 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1567 + // https://github.com/apple/swift-protobuf/issues/1182
1568 + if !self.delegatorAddr.isEmpty {
1569 + try visitor.visitSingularBytesField(value: self.delegatorAddr, fieldNumber: 1)
1570 + }
1571 + if !self.validatorAddr.isEmpty {
1572 + try visitor.visitSingularBytesField(value: self.validatorAddr, fieldNumber: 2)
1573 + }
1574 + try { if let v = self._amount {
1575 + try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
1576 + } }()
1577 + if !self.chainID.isEmpty {
1578 + try visitor.visitSingularStringField(value: self.chainID, fieldNumber: 4)
1579 + }
1580 + try unknownFields.traverse(visitor: &visitor)
1581 + }
1582 +
1583 + public static func ==(lhs: TW_Binance_Proto_SideChainUndelegate, rhs: TW_Binance_Proto_SideChainUndelegate) -> Bool {
1584 + if lhs.delegatorAddr != rhs.delegatorAddr {return false}
1585 + if lhs.validatorAddr != rhs.validatorAddr {return false}
1586 + if lhs._amount != rhs._amount {return false}
1587 + if lhs.chainID != rhs.chainID {return false}
1588 + if lhs.unknownFields != rhs.unknownFields {return false}
1589 + return true
1590 + }
1591 +}
1592 +
1593 +extension TW_Binance_Proto_SideChainStakeMigration: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1594 + public static let protoMessageName: String = _protobuf_package + ".SideChainStakeMigration"
1595 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1596 + 1: .standard(proto: "validator_src_addr"),
1597 + 2: .standard(proto: "validator_dst_addr"),
1598 + 3: .standard(proto: "delegator_addr"),
1599 + 4: .standard(proto: "refund_addr"),
1600 + 5: .same(proto: "amount"),
1601 + ]
1602 +
1603 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1604 + while let fieldNumber = try decoder.nextFieldNumber() {
1605 + // The use of inline closures is to circumvent an issue where the compiler
1606 + // allocates stack space for every case branch when no optimizations are
1607 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1608 + switch fieldNumber {
1609 + case 1: try { try decoder.decodeSingularBytesField(value: &self.validatorSrcAddr) }()
1610 + case 2: try { try decoder.decodeSingularBytesField(value: &self.validatorDstAddr) }()
1611 + case 3: try { try decoder.decodeSingularBytesField(value: &self.delegatorAddr) }()
1612 + case 4: try { try decoder.decodeSingularBytesField(value: &self.refundAddr) }()
1613 + case 5: try { try decoder.decodeSingularMessageField(value: &self._amount) }()
1614 + default: break
1615 + }
1616 + }
1617 + }
1618 +
1619 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1620 + // The use of inline closures is to circumvent an issue where the compiler
1621 + // allocates stack space for every if/case branch local when no optimizations
1622 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
1623 + // https://github.com/apple/swift-protobuf/issues/1182
1624 + if !self.validatorSrcAddr.isEmpty {
1625 + try visitor.visitSingularBytesField(value: self.validatorSrcAddr, fieldNumber: 1)
1626 + }
1627 + if !self.validatorDstAddr.isEmpty {
1628 + try visitor.visitSingularBytesField(value: self.validatorDstAddr, fieldNumber: 2)
1629 + }
1630 + if !self.delegatorAddr.isEmpty {
1631 + try visitor.visitSingularBytesField(value: self.delegatorAddr, fieldNumber: 3)
1632 + }
1633 + if !self.refundAddr.isEmpty {
1634 + try visitor.visitSingularBytesField(value: self.refundAddr, fieldNumber: 4)
1635 + }
1636 + try { if let v = self._amount {
1637 + try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
1638 + } }()
1639 + try unknownFields.traverse(visitor: &visitor)
1640 + }
1641 +
1642 + public static func ==(lhs: TW_Binance_Proto_SideChainStakeMigration, rhs: TW_Binance_Proto_SideChainStakeMigration) -> Bool {
1643 + if lhs.validatorSrcAddr != rhs.validatorSrcAddr {return false}
1644 + if lhs.validatorDstAddr != rhs.validatorDstAddr {return false}
1645 + if lhs.delegatorAddr != rhs.delegatorAddr {return false}
1646 + if lhs.refundAddr != rhs.refundAddr {return false}
1647 + if lhs._amount != rhs._amount {return false}
1648 + if lhs.unknownFields != rhs.unknownFields {return false}
1649 + return true
1650 + }
1651 +}
1652 +
1653 +extension TW_Binance_Proto_TimeLockOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1654 + public static let protoMessageName: String = _protobuf_package + ".TimeLockOrder"
1655 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1656 + 1: .standard(proto: "from_address"),
1657 + 2: .same(proto: "description"),
1658 + 3: .same(proto: "amount"),
1659 + 4: .standard(proto: "lock_time"),
1660 + ]
1661 +
1662 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1663 + while let fieldNumber = try decoder.nextFieldNumber() {
1664 + // The use of inline closures is to circumvent an issue where the compiler
1665 + // allocates stack space for every case branch when no optimizations are
1666 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1667 + switch fieldNumber {
1668 + case 1: try { try decoder.decodeSingularBytesField(value: &self.fromAddress) }()
1669 + case 2: try { try decoder.decodeSingularStringField(value: &self.description_p) }()
1670 + case 3: try { try decoder.decodeRepeatedMessageField(value: &self.amount) }()
1671 + case 4: try { try decoder.decodeSingularInt64Field(value: &self.lockTime) }()
1672 + default: break
1673 + }
1674 + }
1675 + }
1676 +
1677 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1678 + if !self.fromAddress.isEmpty {
1679 + try visitor.visitSingularBytesField(value: self.fromAddress, fieldNumber: 1)
1680 + }
1681 + if !self.description_p.isEmpty {
1682 + try visitor.visitSingularStringField(value: self.description_p, fieldNumber: 2)
1683 + }
1684 + if !self.amount.isEmpty {
1685 + try visitor.visitRepeatedMessageField(value: self.amount, fieldNumber: 3)
1686 + }
1687 + if self.lockTime != 0 {
1688 + try visitor.visitSingularInt64Field(value: self.lockTime, fieldNumber: 4)
1689 + }
1690 + try unknownFields.traverse(visitor: &visitor)
1691 + }
1692 +
1693 + public static func ==(lhs: TW_Binance_Proto_TimeLockOrder, rhs: TW_Binance_Proto_TimeLockOrder) -> Bool {
1694 + if lhs.fromAddress != rhs.fromAddress {return false}
1695 + if lhs.description_p != rhs.description_p {return false}
1696 + if lhs.amount != rhs.amount {return false}
1697 + if lhs.lockTime != rhs.lockTime {return false}
1698 + if lhs.unknownFields != rhs.unknownFields {return false}
1699 + return true
1700 + }
1701 +}
1702 +
1703 +extension TW_Binance_Proto_TimeRelockOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1704 + public static let protoMessageName: String = _protobuf_package + ".TimeRelockOrder"
1705 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1706 + 1: .standard(proto: "from_address"),
1707 + 2: .same(proto: "id"),
1708 + 3: .same(proto: "description"),
1709 + 4: .same(proto: "amount"),
1710 + 5: .standard(proto: "lock_time"),
1711 + ]
1712 +
1713 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1714 + while let fieldNumber = try decoder.nextFieldNumber() {
1715 + // The use of inline closures is to circumvent an issue where the compiler
1716 + // allocates stack space for every case branch when no optimizations are
1717 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1718 + switch fieldNumber {
1719 + case 1: try { try decoder.decodeSingularBytesField(value: &self.fromAddress) }()
1720 + case 2: try { try decoder.decodeSingularInt64Field(value: &self.id) }()
1721 + case 3: try { try decoder.decodeSingularStringField(value: &self.description_p) }()
1722 + case 4: try { try decoder.decodeRepeatedMessageField(value: &self.amount) }()
1723 + case 5: try { try decoder.decodeSingularInt64Field(value: &self.lockTime) }()
1724 + default: break
1725 + }
1726 + }
1727 + }
1728 +
1729 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1730 + if !self.fromAddress.isEmpty {
1731 + try visitor.visitSingularBytesField(value: self.fromAddress, fieldNumber: 1)
1732 + }
1733 + if self.id != 0 {
1734 + try visitor.visitSingularInt64Field(value: self.id, fieldNumber: 2)
1735 + }
1736 + if !self.description_p.isEmpty {
1737 + try visitor.visitSingularStringField(value: self.description_p, fieldNumber: 3)
1738 + }
1739 + if !self.amount.isEmpty {
1740 + try visitor.visitRepeatedMessageField(value: self.amount, fieldNumber: 4)
1741 + }
1742 + if self.lockTime != 0 {
1743 + try visitor.visitSingularInt64Field(value: self.lockTime, fieldNumber: 5)
1744 + }
1745 + try unknownFields.traverse(visitor: &visitor)
1746 + }
1747 +
1748 + public static func ==(lhs: TW_Binance_Proto_TimeRelockOrder, rhs: TW_Binance_Proto_TimeRelockOrder) -> Bool {
1749 + if lhs.fromAddress != rhs.fromAddress {return false}
1750 + if lhs.id != rhs.id {return false}
1751 + if lhs.description_p != rhs.description_p {return false}
1752 + if lhs.amount != rhs.amount {return false}
1753 + if lhs.lockTime != rhs.lockTime {return false}
1754 + if lhs.unknownFields != rhs.unknownFields {return false}
1755 + return true
1756 + }
1757 +}
1758 +
1759 +extension TW_Binance_Proto_TimeUnlockOrder: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1760 + public static let protoMessageName: String = _protobuf_package + ".TimeUnlockOrder"
1761 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1762 + 1: .standard(proto: "from_address"),
1763 + 2: .same(proto: "id"),
1764 + ]
1765 +
1766 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1767 + while let fieldNumber = try decoder.nextFieldNumber() {
1768 + // The use of inline closures is to circumvent an issue where the compiler
1769 + // allocates stack space for every case branch when no optimizations are
1770 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1771 + switch fieldNumber {
1772 + case 1: try { try decoder.decodeSingularBytesField(value: &self.fromAddress) }()
1773 + case 2: try { try decoder.decodeSingularInt64Field(value: &self.id) }()
1774 + default: break
1775 + }
1776 + }
1777 + }
1778 +
1779 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1780 + if !self.fromAddress.isEmpty {
1781 + try visitor.visitSingularBytesField(value: self.fromAddress, fieldNumber: 1)
1782 + }
1783 + if self.id != 0 {
1784 + try visitor.visitSingularInt64Field(value: self.id, fieldNumber: 2)
1785 + }
1786 + try unknownFields.traverse(visitor: &visitor)
1787 + }
1788 +
1789 + public static func ==(lhs: TW_Binance_Proto_TimeUnlockOrder, rhs: TW_Binance_Proto_TimeUnlockOrder) -> Bool {
1790 + if lhs.fromAddress != rhs.fromAddress {return false}
1791 + if lhs.id != rhs.id {return false}
1792 + if lhs.unknownFields != rhs.unknownFields {return false}
1793 + return true
1794 + }
1795 +}
1796 +
1797 +extension TW_Binance_Proto_SigningInput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1798 + public static let protoMessageName: String = _protobuf_package + ".SigningInput"
1799 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1800 + 1: .standard(proto: "chain_id"),
1801 + 2: .standard(proto: "account_number"),
1802 + 3: .same(proto: "sequence"),
1803 + 4: .same(proto: "source"),
1804 + 5: .same(proto: "memo"),
1805 + 6: .standard(proto: "private_key"),
1806 + 8: .standard(proto: "trade_order"),
1807 + 9: .standard(proto: "cancel_trade_order"),
1808 + 10: .standard(proto: "send_order"),
1809 + 13: .standard(proto: "htlt_order"),
1810 + 14: .standard(proto: "depositHTLT_order"),
1811 + 15: .standard(proto: "claimHTLT_order"),
1812 + 16: .standard(proto: "refundHTLT_order"),
1813 + 20: .standard(proto: "transfer_out_order"),
1814 + 21: .standard(proto: "side_delegate_order"),
1815 + 22: .standard(proto: "side_redelegate_order"),
1816 + 23: .standard(proto: "side_undelegate_order"),
1817 + 24: .standard(proto: "time_lock_order"),
1818 + 25: .standard(proto: "time_relock_order"),
1819 + 26: .standard(proto: "time_unlock_order"),
1820 + 27: .standard(proto: "side_stake_migration_order"),
1821 + ]
1822 +
1823 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1824 + while let fieldNumber = try decoder.nextFieldNumber() {
1825 + // The use of inline closures is to circumvent an issue where the compiler
1826 + // allocates stack space for every case branch when no optimizations are
1827 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
1828 + switch fieldNumber {
1829 + case 1: try { try decoder.decodeSingularStringField(value: &self.chainID) }()
1830 + case 2: try { try decoder.decodeSingularInt64Field(value: &self.accountNumber) }()
1831 + case 3: try { try decoder.decodeSingularInt64Field(value: &self.sequence) }()
1832 + case 4: try { try decoder.decodeSingularInt64Field(value: &self.source) }()
1833 + case 5: try { try decoder.decodeSingularStringField(value: &self.memo) }()
1834 + case 6: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }()
1835 + case 8: try {
1836 + var v: TW_Binance_Proto_TradeOrder?
1837 + var hadOneofValue = false
1838 + if let current = self.orderOneof {
1839 + hadOneofValue = true
1840 + if case .tradeOrder(let m) = current {v = m}
1841 + }
1842 + try decoder.decodeSingularMessageField(value: &v)
1843 + if let v = v {
1844 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1845 + self.orderOneof = .tradeOrder(v)
1846 + }
1847 + }()
1848 + case 9: try {
1849 + var v: TW_Binance_Proto_CancelTradeOrder?
1850 + var hadOneofValue = false
1851 + if let current = self.orderOneof {
1852 + hadOneofValue = true
1853 + if case .cancelTradeOrder(let m) = current {v = m}
1854 + }
1855 + try decoder.decodeSingularMessageField(value: &v)
1856 + if let v = v {
1857 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1858 + self.orderOneof = .cancelTradeOrder(v)
1859 + }
1860 + }()
1861 + case 10: try {
1862 + var v: TW_Binance_Proto_SendOrder?
1863 + var hadOneofValue = false
1864 + if let current = self.orderOneof {
1865 + hadOneofValue = true
1866 + if case .sendOrder(let m) = current {v = m}
1867 + }
1868 + try decoder.decodeSingularMessageField(value: &v)
1869 + if let v = v {
1870 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1871 + self.orderOneof = .sendOrder(v)
1872 + }
1873 + }()
1874 + case 13: try {
1875 + var v: TW_Binance_Proto_HTLTOrder?
1876 + var hadOneofValue = false
1877 + if let current = self.orderOneof {
1878 + hadOneofValue = true
1879 + if case .htltOrder(let m) = current {v = m}
1880 + }
1881 + try decoder.decodeSingularMessageField(value: &v)
1882 + if let v = v {
1883 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1884 + self.orderOneof = .htltOrder(v)
1885 + }
1886 + }()
1887 + case 14: try {
1888 + var v: TW_Binance_Proto_DepositHTLTOrder?
1889 + var hadOneofValue = false
1890 + if let current = self.orderOneof {
1891 + hadOneofValue = true
1892 + if case .depositHtltOrder(let m) = current {v = m}
1893 + }
1894 + try decoder.decodeSingularMessageField(value: &v)
1895 + if let v = v {
1896 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1897 + self.orderOneof = .depositHtltOrder(v)
1898 + }
1899 + }()
1900 + case 15: try {
1901 + var v: TW_Binance_Proto_ClaimHTLOrder?
1902 + var hadOneofValue = false
1903 + if let current = self.orderOneof {
1904 + hadOneofValue = true
1905 + if case .claimHtltOrder(let m) = current {v = m}
1906 + }
1907 + try decoder.decodeSingularMessageField(value: &v)
1908 + if let v = v {
1909 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1910 + self.orderOneof = .claimHtltOrder(v)
1911 + }
1912 + }()
1913 + case 16: try {
1914 + var v: TW_Binance_Proto_RefundHTLTOrder?
1915 + var hadOneofValue = false
1916 + if let current = self.orderOneof {
1917 + hadOneofValue = true
1918 + if case .refundHtltOrder(let m) = current {v = m}
1919 + }
1920 + try decoder.decodeSingularMessageField(value: &v)
1921 + if let v = v {
1922 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1923 + self.orderOneof = .refundHtltOrder(v)
1924 + }
1925 + }()
1926 + case 20: try {
1927 + var v: TW_Binance_Proto_TransferOut?
1928 + var hadOneofValue = false
1929 + if let current = self.orderOneof {
1930 + hadOneofValue = true
1931 + if case .transferOutOrder(let m) = current {v = m}
1932 + }
1933 + try decoder.decodeSingularMessageField(value: &v)
1934 + if let v = v {
1935 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1936 + self.orderOneof = .transferOutOrder(v)
1937 + }
1938 + }()
1939 + case 21: try {
1940 + var v: TW_Binance_Proto_SideChainDelegate?
1941 + var hadOneofValue = false
1942 + if let current = self.orderOneof {
1943 + hadOneofValue = true
1944 + if case .sideDelegateOrder(let m) = current {v = m}
1945 + }
1946 + try decoder.decodeSingularMessageField(value: &v)
1947 + if let v = v {
1948 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1949 + self.orderOneof = .sideDelegateOrder(v)
1950 + }
1951 + }()
1952 + case 22: try {
1953 + var v: TW_Binance_Proto_SideChainRedelegate?
1954 + var hadOneofValue = false
1955 + if let current = self.orderOneof {
1956 + hadOneofValue = true
1957 + if case .sideRedelegateOrder(let m) = current {v = m}
1958 + }
1959 + try decoder.decodeSingularMessageField(value: &v)
1960 + if let v = v {
1961 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1962 + self.orderOneof = .sideRedelegateOrder(v)
1963 + }
1964 + }()
1965 + case 23: try {
1966 + var v: TW_Binance_Proto_SideChainUndelegate?
1967 + var hadOneofValue = false
1968 + if let current = self.orderOneof {
1969 + hadOneofValue = true
1970 + if case .sideUndelegateOrder(let m) = current {v = m}
1971 + }
1972 + try decoder.decodeSingularMessageField(value: &v)
1973 + if let v = v {
1974 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1975 + self.orderOneof = .sideUndelegateOrder(v)
1976 + }
1977 + }()
1978 + case 24: try {
1979 + var v: TW_Binance_Proto_TimeLockOrder?
1980 + var hadOneofValue = false
1981 + if let current = self.orderOneof {
1982 + hadOneofValue = true
1983 + if case .timeLockOrder(let m) = current {v = m}
1984 + }
1985 + try decoder.decodeSingularMessageField(value: &v)
1986 + if let v = v {
1987 + if hadOneofValue {try decoder.handleConflictingOneOf()}
1988 + self.orderOneof = .timeLockOrder(v)
1989 + }
1990 + }()
1991 + case 25: try {
1992 + var v: TW_Binance_Proto_TimeRelockOrder?
1993 + var hadOneofValue = false
1994 + if let current = self.orderOneof {
1995 + hadOneofValue = true
1996 + if case .timeRelockOrder(let m) = current {v = m}
1997 + }
1998 + try decoder.decodeSingularMessageField(value: &v)
1999 + if let v = v {
2000 + if hadOneofValue {try decoder.handleConflictingOneOf()}
2001 + self.orderOneof = .timeRelockOrder(v)
2002 + }
2003 + }()
2004 + case 26: try {
2005 + var v: TW_Binance_Proto_TimeUnlockOrder?
2006 + var hadOneofValue = false
2007 + if let current = self.orderOneof {
2008 + hadOneofValue = true
2009 + if case .timeUnlockOrder(let m) = current {v = m}
2010 + }
2011 + try decoder.decodeSingularMessageField(value: &v)
2012 + if let v = v {
2013 + if hadOneofValue {try decoder.handleConflictingOneOf()}
2014 + self.orderOneof = .timeUnlockOrder(v)
2015 + }
2016 + }()
2017 + case 27: try {
2018 + var v: TW_Binance_Proto_SideChainStakeMigration?
2019 + var hadOneofValue = false
2020 + if let current = self.orderOneof {
2021 + hadOneofValue = true
2022 + if case .sideStakeMigrationOrder(let m) = current {v = m}
2023 + }
2024 + try decoder.decodeSingularMessageField(value: &v)
2025 + if let v = v {
2026 + if hadOneofValue {try decoder.handleConflictingOneOf()}
2027 + self.orderOneof = .sideStakeMigrationOrder(v)
2028 + }
2029 + }()
2030 + default: break
2031 + }
2032 + }
2033 + }
2034 +
2035 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
2036 + // The use of inline closures is to circumvent an issue where the compiler
2037 + // allocates stack space for every if/case branch local when no optimizations
2038 + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
2039 + // https://github.com/apple/swift-protobuf/issues/1182
2040 + if !self.chainID.isEmpty {
2041 + try visitor.visitSingularStringField(value: self.chainID, fieldNumber: 1)
2042 + }
2043 + if self.accountNumber != 0 {
2044 + try visitor.visitSingularInt64Field(value: self.accountNumber, fieldNumber: 2)
2045 + }
2046 + if self.sequence != 0 {
2047 + try visitor.visitSingularInt64Field(value: self.sequence, fieldNumber: 3)
2048 + }
2049 + if self.source != 0 {
2050 + try visitor.visitSingularInt64Field(value: self.source, fieldNumber: 4)
2051 + }
2052 + if !self.memo.isEmpty {
2053 + try visitor.visitSingularStringField(value: self.memo, fieldNumber: 5)
2054 + }
2055 + if !self.privateKey.isEmpty {
2056 + try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 6)
2057 + }
2058 + switch self.orderOneof {
2059 + case .tradeOrder?: try {
2060 + guard case .tradeOrder(let v)? = self.orderOneof else { preconditionFailure() }
2061 + try visitor.visitSingularMessageField(value: v, fieldNumber: 8)
2062 + }()
2063 + case .cancelTradeOrder?: try {
2064 + guard case .cancelTradeOrder(let v)? = self.orderOneof else { preconditionFailure() }
2065 + try visitor.visitSingularMessageField(value: v, fieldNumber: 9)
2066 + }()
2067 + case .sendOrder?: try {
2068 + guard case .sendOrder(let v)? = self.orderOneof else { preconditionFailure() }
2069 + try visitor.visitSingularMessageField(value: v, fieldNumber: 10)
2070 + }()
2071 + case .htltOrder?: try {
2072 + guard case .htltOrder(let v)? = self.orderOneof else { preconditionFailure() }
2073 + try visitor.visitSingularMessageField(value: v, fieldNumber: 13)
2074 + }()
2075 + case .depositHtltOrder?: try {
2076 + guard case .depositHtltOrder(let v)? = self.orderOneof else { preconditionFailure() }
2077 + try visitor.visitSingularMessageField(value: v, fieldNumber: 14)
2078 + }()
2079 + case .claimHtltOrder?: try {
2080 + guard case .claimHtltOrder(let v)? = self.orderOneof else { preconditionFailure() }
2081 + try visitor.visitSingularMessageField(value: v, fieldNumber: 15)
2082 + }()
2083 + case .refundHtltOrder?: try {
2084 + guard case .refundHtltOrder(let v)? = self.orderOneof else { preconditionFailure() }
2085 + try visitor.visitSingularMessageField(value: v, fieldNumber: 16)
2086 + }()
2087 + case .transferOutOrder?: try {
2088 + guard case .transferOutOrder(let v)? = self.orderOneof else { preconditionFailure() }
2089 + try visitor.visitSingularMessageField(value: v, fieldNumber: 20)
2090 + }()
2091 + case .sideDelegateOrder?: try {
2092 + guard case .sideDelegateOrder(let v)? = self.orderOneof else { preconditionFailure() }
2093 + try visitor.visitSingularMessageField(value: v, fieldNumber: 21)
2094 + }()
2095 + case .sideRedelegateOrder?: try {
2096 + guard case .sideRedelegateOrder(let v)? = self.orderOneof else { preconditionFailure() }
2097 + try visitor.visitSingularMessageField(value: v, fieldNumber: 22)
2098 + }()
2099 + case .sideUndelegateOrder?: try {
2100 + guard case .sideUndelegateOrder(let v)? = self.orderOneof else { preconditionFailure() }
2101 + try visitor.visitSingularMessageField(value: v, fieldNumber: 23)
2102 + }()
2103 + case .timeLockOrder?: try {
2104 + guard case .timeLockOrder(let v)? = self.orderOneof else { preconditionFailure() }
2105 + try visitor.visitSingularMessageField(value: v, fieldNumber: 24)
2106 + }()
2107 + case .timeRelockOrder?: try {
2108 + guard case .timeRelockOrder(let v)? = self.orderOneof else { preconditionFailure() }
2109 + try visitor.visitSingularMessageField(value: v, fieldNumber: 25)
2110 + }()
2111 + case .timeUnlockOrder?: try {
2112 + guard case .timeUnlockOrder(let v)? = self.orderOneof else { preconditionFailure() }
2113 + try visitor.visitSingularMessageField(value: v, fieldNumber: 26)
2114 + }()
2115 + case .sideStakeMigrationOrder?: try {
2116 + guard case .sideStakeMigrationOrder(let v)? = self.orderOneof else { preconditionFailure() }
2117 + try visitor.visitSingularMessageField(value: v, fieldNumber: 27)
2118 + }()
2119 + case nil: break
2120 + }
2121 + try unknownFields.traverse(visitor: &visitor)
2122 + }
2123 +
2124 + public static func ==(lhs: TW_Binance_Proto_SigningInput, rhs: TW_Binance_Proto_SigningInput) -> Bool {
2125 + if lhs.chainID != rhs.chainID {return false}
2126 + if lhs.accountNumber != rhs.accountNumber {return false}
2127 + if lhs.sequence != rhs.sequence {return false}
2128 + if lhs.source != rhs.source {return false}
2129 + if lhs.memo != rhs.memo {return false}
2130 + if lhs.privateKey != rhs.privateKey {return false}
2131 + if lhs.orderOneof != rhs.orderOneof {return false}
2132 + if lhs.unknownFields != rhs.unknownFields {return false}
2133 + return true
2134 + }
2135 +}
2136 +
2137 +extension TW_Binance_Proto_SigningOutput: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
2138 + public static let protoMessageName: String = _protobuf_package + ".SigningOutput"
2139 + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
2140 + 1: .same(proto: "encoded"),
2141 + 2: .same(proto: "error"),
2142 + 3: .standard(proto: "error_message"),
2143 + 4: .same(proto: "signature"),
2144 + 5: .standard(proto: "signature_json"),
2145 + ]
2146 +
2147 + public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
2148 + while let fieldNumber = try decoder.nextFieldNumber() {
2149 + // The use of inline closures is to circumvent an issue where the compiler
2150 + // allocates stack space for every case branch when no optimizations are
2151 + // enabled. https://github.com/apple/swift-protobuf/issues/1034
2152 + switch fieldNumber {
2153 + case 1: try { try decoder.decodeSingularBytesField(value: &self.encoded) }()
2154 + case 2: try { try decoder.decodeSingularEnumField(value: &self.error) }()
2155 + case 3: try { try decoder.decodeSingularStringField(value: &self.errorMessage) }()
2156 + case 4: try { try decoder.decodeSingularBytesField(value: &self.signature) }()
2157 + case 5: try { try decoder.decodeSingularStringField(value: &self.signatureJson) }()
2158 + default: break
2159 + }
2160 + }
2161 + }
2162 +
2163 + public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
2164 + if !self.encoded.isEmpty {
2165 + try visitor.visitSingularBytesField(value: self.encoded, fieldNumber: 1)
2166 + }
2167 + if self.error != .ok {
2168 + try visitor.visitSingularEnumField(value: self.error, fieldNumber: 2)
2169 + }
2170 + if !self.errorMessage.isEmpty {
2171 + try visitor.visitSingularStringField(value: self.errorMessage, fieldNumber: 3)

Diff truncated — file too large.