{"id":50365334,"url":"https://github.com/citadel-tech/coinswap-swift","last_synced_at":"2026-05-30T03:30:29.908Z","repository":{"id":357622737,"uuid":"1236307000","full_name":"citadel-tech/coinswap-swift","owner":"citadel-tech","description":"Coinswap Swift demo app.","archived":false,"fork":false,"pushed_at":"2026-05-13T14:22:49.000Z","size":13,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T16:32:03.980Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/citadel-tech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T06:11:41.000Z","updated_at":"2026-05-13T14:57:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/citadel-tech/coinswap-swift","commit_stats":null,"previous_names":["citadel-tech/coinswap-swift"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/citadel-tech/coinswap-swift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citadel-tech%2Fcoinswap-swift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citadel-tech%2Fcoinswap-swift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citadel-tech%2Fcoinswap-swift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citadel-tech%2Fcoinswap-swift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/citadel-tech","download_url":"https://codeload.github.com/citadel-tech/coinswap-swift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citadel-tech%2Fcoinswap-swift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33679305,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-30T03:30:29.147Z","updated_at":"2026-05-30T03:30:29.899Z","avatar_url":"https://github.com/citadel-tech.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Coinswap Swift\n\nSwift bindings for the Coinswap Bitcoin privacy protocol\n\n\u003c/div\u003e\n\n## Overview\n\n`coinswap-swift` packages the shared UniFFI taker API as a Swift Package backed by `coinswap_ffi.xcframework`.\n\n## Supported Platforms\n\n| Platform | Support |\n| --- | --- |\n| iOS | arm64 devices, iOS simulator arm64/x86_64 |\n| macOS | arm64 and x86_64 |\n\nThe Swift package declares iOS 13+ and macOS 10.15+ deployment targets.\n\n## Build and Package\n\n```bash\n# Dev build (fast, debug; builds host arch + iOS device + iOS simulator)\nbash ./build-xcframework-dev.sh\n\n# Workflow build (configured for github CI only; builds x86_64 Mac-Intel)\nbash ./build-xcframework-ci.sh\n\n# Release build (release-smaller profile; builds all Apple targets)\nbash ./build-xcframework.sh\nswift build\n```\n\nOutputs for production build:\n- `Sources/Coinswap/Coinswap.swift` - Swift bindings\n- `CoinswapFFI.h` and `module.modulemap` - C headers\n- `libcoinswap_ffi.a` - native static lib\n- `coinswap_ffi.xcframework` - packaged slices (macOS, iOS device, iOS simulator). \n- Each platform slice has the aforementioned C header and static lib files.\n\n### Installation\nAdd the package to your app:\n\nXcode: File \u003e Add Packages... and select the `coinswap-swift` folder.\n\nPackage.swift:\n```swift\n.package(path: \"../coinswap-swift\")\n```\n\nThen depend on `Coinswap` and `import Coinswap` in your app.\n\n## App Scaffolds\n\nStarter SwiftUI apps live in separate folders:\n\n- `apps/ios` (iOS 15+)\n- `apps/macos` (macOS 12+)\n\nEach app is a small SwiftPM executable that depends on this local package. Open the folder in Xcode and run it, then wire your RPC + Tor config into the view model.\n\n```bash\ncd apps/ios\nopen -a Xcode .\n```\n\n```bash\ncd apps/macos\nopen -a Xcode .\n```\n\n## Basic Usage\n\n```swift\nimport Foundation\nimport Coinswap\n\n// Bitcoin Core RPC settings used by the taker.\nlet rpcConfig = RpcConfig(\n    url: \"http://127.0.0.1:18442\",                 // Bitcoin Core RPC endpoint\n    username: \"user\",                              // Bitcoin Core RPC username\n    password: \"password\",                          // Bitcoin Core RPC password\n    walletName: \"taker_wallet\"                     // Bitcoin Core wallet name\n)\n\n// Create or load the taker wallet.\nlet taker = try Taker.`init`(\n    dataDir: \"/path/to/data\",                      // taker data directory; nil uses the default taker dir\n    walletFileName: \"taker_wallet\",                // taker wallet file to load or create\n    rpcConfig: rpcConfig,                            // Bitcoin Core RPC settings\n    controlPort: 9051,                               // Tor control port\n    torAuthPassword: \"coinswap\",                   // Tor control password\n    zmqAddr: \"tcp://127.0.0.1:28332\",              // Bitcoin Core ZMQ endpoint\n    password: \"\"                                    // optional wallet encryption password\n)\n\n// Configure logging, sync wallet state, and wait for the offer book.\ntry taker.setupLogging(\n    dataDir: \"/path/to/data\",                      // directory used for file logging\n    logLevel: \"info\"                               // trace | debug | info | warn | error\n)\ntry taker.syncAndSave()\ntry taker.syncOfferbookAndWait()\n\n// Inspect balances and derive a new receive address.\nlet balances = try taker.getBalances()\nlet receiveAddress = try taker.getNextExternalAddress(\n    addressType: AddressType(\n        addrType: \"P2WPKH\"                         // external address format to derive\n    )\n)\n\nprint(\"regular: \\(balances.regular) sats\")\nprint(\"swap: \\(balances.swap) sats\")\nprint(\"contract: \\(balances.contract) sats\")\nprint(\"fidelity: \\(balances.fidelity) sats\")\nprint(\"spendable: \\(balances.spendable) sats\")\nprint(\"receive to: \\(receiveAddress.address)\")\n\n// Build the swap request exactly as the taker API expects it.\nlet swapParams = SwapParams(\n    protocol: nil,                                  // optional protocol hint; nil uses the backend default\n    sendAmount: 1_000_000,                          // total sats to swap\n    makerCount: 2,                                  // number of maker hops\n    txCount: 1,                                     // number of funding transaction splits\n    requiredConfirms: 1,                            // minimum funding confirmations\n    manuallySelectedOutpoints: nil,                 // optional explicit wallet UTXOs\n    preferredMakers: nil                            // optional maker addresses to prefer\n)\n\n// Prepare the swap first, then start it with the returned swap id.\nlet swapId = try taker.prepareCoinswap(\n    swapParams: swapParams                          // fully populated swap request\n)\nlet report = try taker.startCoinswap(\n    swapId: swapId                                  // identifier returned by prepareCoinswap\n)\n\nprint(\"swap id: \\(report.swapId)\")\nprint(\"status: \\(report.status)\")\nprint(\"outgoing amount: \\(report.outgoingAmount) sats\")\nprint(\"fee paid: \\(abs(report.feePaidOrEarned)) sats\")\n```\n\n## API Reference\n\n### RpcConfig\n\n```swift\nlet rpcConfig = RpcConfig(\n    url: rpcUrl,                                    // Bitcoin Core RPC endpoint\n    username: rpcUsername,                          // Bitcoin Core RPC username\n    password: rpcPassword,                          // Bitcoin Core RPC password\n    walletName: walletName                          // Bitcoin Core wallet name\n)\n```\n\n### SwapParams\n\n```swift\nlet swapParams = SwapParams(\n    protocol: protocolHint,                         // optional protocol hint string\n    sendAmount: sendAmountSats,                     // total sats to swap\n    makerCount: makerCount,                         // number of maker hops\n    txCount: txCount,                               // number of funding transaction splits\n    requiredConfirms: requiredConfirms,             // minimum funding confirmations\n    manuallySelectedOutpoints: outpoints,           // optional explicit wallet UTXOs\n    preferredMakers: preferredMakers                // optional maker addresses to prefer\n)\n```\n\n### Taker\n\n```swift\nlet taker = try Taker.`init`(\n    dataDir: dataDir,                               // taker data directory\n    walletFileName: walletFileName,                 // taker wallet file to load or create\n    rpcConfig: rpcConfig,                           // Bitcoin Core RPC settings\n    controlPort: controlPort,                       // Tor control port\n    torAuthPassword: torAuthPassword,               // Tor control password\n    zmqAddr: zmqAddr,                               // Bitcoin Core ZMQ endpoint\n    password: password                              // optional wallet encryption password\n)\n\ntry taker.setupLogging(dataDir: dataDir, logLevel: logLevel)                           // configure taker logging\nlet swapId = try taker.prepareCoinswap(swapParams: swapParams)                         // prepare a swap and return the swap id\nlet report = try taker.startCoinswap(swapId: swapId)                                   // execute a prepared swap\nlet txs = try taker.getTransactions(count: count, skip: skip)                          // recent wallet transactions\nlet internal = try taker.getNextInternalAddresses(count: count, addressType: addressType) // derive internal HD addresses\nlet external = try taker.getNextExternalAddress(addressType: addressType)              // derive an external receive address\nlet utxos = try taker.listAllUtxoSpendInfo()                                           // wallet UTXOs plus spend metadata\ntry taker.backup(destinationPath: destinationPath, password: backupPassword)           // write a wallet backup JSON file\ntry taker.lockUnspendableUtxos()                                                       // lock fidelity and live-contract UTXOs\nlet txid = try taker.sendToAddress(address: address, amount: amount, feeRate: feeRate, manuallySelectedOutpoints: outpoints) // send sats to an external address\nlet balances = try taker.getBalances()                                                 // read wallet balances\ntry taker.syncAndSave()                                                                // sync wallet state and persist it\ntry taker.syncOfferbookAndWait()                                                       // block until the offer book is synchronized\nlet offerBook = try taker.fetchOffers()                                                // read the current offer book\nlet renderedOffer = try taker.displayOffer(makerOffer: offer)                          // format a maker offer for display\nlet walletName = try taker.getWalletName()                                             // read the wallet name\ntry taker.recoverActiveSwap()                                                          // resume recovery for a failed active swap\nlet makers = try taker.fetchAllMakers()                                                // read maker addresses across all states\n```\n\n### AddressType, Balances, and SwapReport\n\n```swift\nlet addressType = AddressType(\n    addrType: \"P2WPKH\"                         // external address format to derive\n)\n\nbalances.regular                                // single-signature seed balance in sats\nbalances.swap                                   // swap-coin balance in sats\nbalances.contract                               // live contract balance in sats\nbalances.fidelity                               // fidelity bond balance in sats\nbalances.spendable                              // regular + swap balance in sats\n\nreport.swapId                                   // unique swap identifier\nreport.role                                     // report creator, usually Taker\nreport.status                                   // swap terminal state\nreport.swapDurationSeconds                      // execution duration in seconds\nreport.recoveryDurationSeconds                  // recovery duration in seconds\nreport.startTimestamp                           // unix start timestamp\nreport.endTimestamp                             // unix end timestamp\nreport.network                                  // bitcoin network name\nreport.errorMessage                             // error detail, if present\nreport.incomingAmount                           // sats received by the taker\nreport.outgoingAmount                           // sats sent by the taker\nreport.feePaidOrEarned                          // negative when paid, positive when earned\nreport.fundingTxids                             // funding txids grouped by hop\nreport.recoveryTxids                            // recovery txids, if any\nreport.timelock                                 // contract timelock in blocks\nreport.makersCount                              // maker hop count used in the swap\nreport.makerAddresses                           // maker addresses used in the route\nreport.totalMakerFees                           // aggregate maker fees in sats\nreport.miningFee                                // mining fees in sats\nreport.feePercentage                            // total fee as a percentage of amount\nreport.makerFeeInfo                             // per-maker fee breakdown\nreport.inputUtxos                               // input UTXO amounts in sats\nreport.outputChangeAmounts                      // output change amounts in sats\nreport.outputSwapAmounts                        // output swap amounts in sats\nreport.outputChangeUtxos                        // change outputs with amount and address\nreport.outputSwapUtxos                          // swap outputs with amount and address\n```\n\n## Testing\n\n```bash\ncd ../ffi-commons\n./ffi-docker-setup setup\n./ffi-docker-setup start 4\n\ncd ../coinswap-swift\nswift test\n\ncd ../ffi-commons\n./ffi-docker-setup stop\n```\n\n## Requirements\n\n- Xcode 14+.\n- Swift 5.7+.\n- Bitcoin Core with RPC enabled, fully synced, non-pruned, and `-txindex` enabled.\n- Tor daemon for live taker workflows.\n\n## Support\n\n- [Main Coinswap Repository](https://github.com/citadel-tech/coinswap)\n- [FFI Commons](../ffi-commons)\n\n## License\n\nMIT License - see [LICENSE](../LICENSE) for details\n\u003e\u003e\u003e\u003e\u003e\u003e\u003e b4d3f12 (IOS and Mac apps starter code with tmp build scripts)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcitadel-tech%2Fcoinswap-swift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcitadel-tech%2Fcoinswap-swift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcitadel-tech%2Fcoinswap-swift/lists"}