stellar-ios-mac-sdk
Soneso 开源stellar SDK 用于 iOS 和 Mac,提供构建事务和连接到 Horizon 的 API。
安装
CocoaPods
CocoaPods 是用于 Cocoa 项目的依赖项管理器。您可以使用以下命令安装它
$ gem install cocoapods
要使用 CocoaPods 将 stellar SDK 集成到您的 Xcode 项目中,请在您的 Podfile
中指定它
use_frameworks!
target '<Your Target Name>' do
pod 'stellar-ios-mac-sdk', '~> 2.3.6'
end
然后,运行以下命令
$ pod repo update
$ pod install
Carthage
Carthage 是一个去中心化的依赖管理器,构建您的依赖并提供二进制框架。
您可以使用以下命令,通过 Homebrew 安装 Carthage:
$ brew update
$ brew install carthage
要使用 Carthage 将 stellar-ios-mac-sdk 集成到您的 Xcode 项目中,请在您的 Cartfile
中指定它
github "soneso/stellar-ios-mac-sdk" ~> 2.3.6
运行 carthage update
构建框架,并将构建的 stellar-ios-mac-sdk.framework
拖放到您的 Xcode 项目中。
Swift Package Manager
.package(name: "stellarsdk", url: "[email protected]:Soneso/stellar-ios-mac-sdk.git", from: "2.3.6"),
手动
将 SDK 项目作为一个子项目添加,并将 SDK 作为目标依赖。以下是我们推荐的步骤:
- 克隆这个仓库(作为一个子模块或在不同的目录中,由您决定);
- 将
stellarsdk.xcodeproj
拖动作为一个子项目; - 在您的主
.xcodeproj
文件中,选择所需的目标; - 转到 构建阶段,展开目标依赖,并为 iOS 添加
stellarsdk
,为 OSX 添加stellarsdk-macOS
; - 在 Swift 中
import stellarsdk
并开始使用它!
快速入门
1. 创建Stellar密钥对
1.1 随机生成
// create a completely new and unique pair of keys.
let keyPair = try! KeyPair.generateRandomKeyPair()
print("Account Id: " + keyPair.accountId)
// GCFXHS4GXL6BVUCXBWXGTITROWLVYXQKQLF4YH5O5JT3YZXCYPAFBJZB
print("Secret Seed: " + keyPair.secretSeed)
// SAV76USXIJOBMEQXPANUOQM6F5LIOTLPDIDVRJBFFE2MDJXG24TAPUU7
1.2 确定性生成
Stellar生态系统提案《SEP-005 Stellar账户密钥推导方法》描述了Stellar账户密钥推导的方法。这提高了密钥存储以及在不同钱包和应用之间移动密钥的效率。
生成助记词
let mnemonic = Wallet.generate24WordMnemonic()
print("generated 24 words mnemonic: \(mnemonic)")
// bench hurt jump file august wise shallow faculty impulse spring exact slush thunder author capable act festival slice deposit sauce coconut afford frown better
生成密钥对
let keyPair0 = try! Wallet.createKeyPair(mnemonic: mnemonic, passphrase: nil, index: 0)
let keyPair1 = try! Wallet.createKeyPair(mnemonic: mnemonic, passphrase: nil, index: 1)
print("key pair 0 accountId: \(keyPair0.accountId)")
// key pair 0 accountId: GC3MMSXBWHL6CPOAVERSJITX7BH76YU252WGLUOM5CJX3E7UCYZBTPJQ
print("key pair 0 secretSeed: \(keyPair0.secretSeed!)")
// key pair 0 secretSeed: SAEWIVK3VLNEJ3WEJRZXQGDAS5NVG2BYSYDFRSH4GKVTS5RXNVED5AX7
使用通行短语生成密钥对
let keyPair0 = try! Wallet.createKeyPair(mnemonic: mnemonic, passphrase: "p4ssphr4se", index: 0)
let keyPair1 = try! Wallet.createKeyPair(mnemonic: mnemonic, passphrase: "p4ssphr4se", index: 0)
BIP和主密钥生成
let bip39Seed = Mnemonic.createSeed(mnemonic: mnemonic)
let masterPrivateKey = Ed25519Derivation(seed: bip39Seed)
let purpose = masterPrivateKey.derived(at: 44)
let coinType = purpose.derived(at: 148)
let account0 = coinType.derived(at: 0)
let keyPair0 = try! KeyPair.init(seed: Seed(bytes: account0.raw.bytes))
let account1 = coinType.derived(at: 1)
let keyPair1 = try! KeyPair.init(seed: Seed(bytes: account1.raw.bytes))
2. 创建账户
在生成密钥对后,您已经得到了地址,但直到有人至少转1 lumen至此,它才会被激活。
2.1 测试网
如果您想在Stellar测试网络中玩耍,SDK可以询问Friendbot为您创建账户,如下所示
// To create a test account, sdk.accounts.createTestAccount will send Friendbot the public key you created
sdk.accounts.createTestAccount(accountId: keyPair.accountId) { (response) -> (Void) in
switch response {
case .success(let details):
print(details)
case .failure(let error):
print(error.localizedDescription)
}
}
另请参阅:详细代码示例
2.2 公共网
另一方面,如果您想在公共网中创建账户,您应该从交易所购买一些Stellar Lumens。参见Stellar Lumens购买指南。当您将Lumens提入您的账户时,交易所将自动为您创建账户。但是,如果您想从您自己的另一个账户创建账户,您可以运行以下代码
// build the operation
let createAccount = try CreateAccountOperation(sourceAccountId: nil,
destinationAccountId: destinationAccountId,
startBalance: 2.0)
// build the transaction
let transaction = try Transaction(sourceAccount: accountResponse,
operations: [createAccount],
memo: Memo.none)
// sign the transaction
try transaction.sign(keyPair: sourceAccountKeyPair, network: Network.testnet)
// submit the transaction
try sdk.transactions.submitTransaction(transaction: transaction) { (response) -> (Void) in
switch response {
case .success(_):
//...
case .failure(let error):
// ...
}
}
另请参阅:详细代码示例
3. 检查账户
3.1 基本信息
创建账户后,我们可以查看账户的基本信息。
sdk.accounts.getAccountDetails(accountId: keyPair.accountId) { (response) -> (Void) in
switch response {
case .success(let accountDetails):
// You can check the `balance`, `sequence`, `flags`, `signers`, `data` etc.
for balance in accountDetails.balances {
switch balance.assetType {
case AssetTypeAsString.NATIVE:
print("balance: \(balance.balance) XLM")
default:
print("balance: \(balance.balance) \(balance.assetCode!) issuer: \(balance.assetIssuer!)")
}
}
print("sequence number: \(accountDetails.sequenceNumber)")
for signer in accountDetails.signers {
print("signer public key: \(signer.key)")
}
print("auth required: \(accountDetails.flags.authRequired)")
print("auth revocable: \(accountDetails.flags.authRevocable)")
for (key, value) in accountDetails.data {
print("data key: \(key) value: \(value.base64Decoded() ?? "")")
}
case .failure(let error):
print(error.localizedDescription)
}
}
另请参阅:详细代码示例
3.2 检查支付
您可以按照以下方式检查最近的支付:
sdk.payments.getPayments(order:Order.descending, limit:10) { response in
switch response {
case .success(let paymentsResponse):
for payment in paymentsResponse.records {
if let nextPayment = payment as? PaymentOperationResponse {
if (nextPayment.assetType == AssetTypeAsString.NATIVE) {
print("received: \(nextPayment.amount) lumen" )
} else {
print("received: \(nextPayment.amount) \(nextPayment.assetCode!)" )
}
print("from: \(nextPayment.from)" )
}
else if let nextPayment = payment as? AccountCreatedOperationResponse {
//...
}
}
case .failure(let error):
print(error.localizedDescription)
}
}
参阅:详细代码示例
您可以使用limit
、order
和cursor
参数来自定义查询。您还可以获取账户、账本和交易的最新支付。
例如,获取账户的支付:
sdk.payments.getPayments(forAccount:keyPair.accountId, order:Order.descending, limit:10)
参阅:详细代码示例
Horizon支持SSE推送数据。您可以使用它如下:
首先在某个地方定义您的流项以保留引用
var streamItem:OperationsStreamItem? = nil
然后创建、分配并使用它
streamItem = sdk.payments.stream(for: .paymentsForAccount(account: destinationAccountId, cursor: nil))
streamItem.onReceive { (response) -> (Void) in
switch response {
case .open:
break
case .response(let id, let operationResponse):
if let paymentResponse = operationResponse as? PaymentOperationResponse {
switch paymentResponse.assetType {
case AssetTypeAsString.NATIVE:
print("Payment of \(paymentResponse.amount) XLM from \(paymentResponse.sourceAccount) received - id \(id)" )
default:
print("Payment of \(paymentResponse.amount) \(paymentResponse.assetCode!) from \(paymentResponse.sourceAccount) received - id \(id)" )
}
}
case .error(let err):
print(err?.localizedDescription ?? "Error")
}
}
稍后您可以关闭流项
streamItem.close()
参阅:详细代码示例
3.3 检查其他人
与支付类似,您可以通过以下方式检查资产
、交易
、影响
、要约
、操作
、账本
等:
sdk.assets.getAssets()
sdk.transactions.getTransactions()
sdk.effects.getEffects()
sdk.offers.getOffers()
sdk.operations.getOperations()
// add so on ...
4. 构建和提交交易
示例:“发送支付”
// create the payment operation
let paymentOperation = PaymentOperation(sourceAccountId: sourceAccountId,
destinationAccountId: destinationAccountId,
asset: Asset(type: AssetType.ASSET_TYPE_NATIVE)!,
amount: 1.5)
// create the transaction containing the payment operation
let transaction = try Transaction(sourceAccount: accountResponse,
operations: [paymentOperation],
memo: Memo.none)
// sign the transaction
try transaction.sign(keyPair: sourceAccountKeyPair, network: Network.testnet)
// submit the transaction
try sdk.transactions.submitTransaction(transaction: transaction) { (response) -> (Void) in
switch response {
case .success(_):
// ...
default:
// ...
}
}
参阅:详细代码示例
从XDR字符串获取事务签名 envelope
let xdrString = "AAAAAJ/Ax+axve53/7sXfQY0fI6jzBeHEcPl0Vsg1C2tqyRbAAAAZAAAAAAAAAAAAAAAAQAAAABb2L/OAAAAAFvYwPoAAAAAAAAAAQAAAAEAAAAAo7FW8r8Nj+SMwPPeAoL4aUkLob7QU68+9Y8CAia5k78AAAAKAAAAN0NJcDhiSHdnU2hUR042ZDE3bjg1ZlFGRVBKdmNtNFhnSWhVVFBuUUF4cUtORVd4V3JYIGF1dGgAAAAAAQAAAEDh/7kQjZbcXypISjto5NtGLuaDGrfL/F08apZQYp38JNMNQ9p/e1Fy0z23WOg/Ic+e91+hgbdTude6+1+i0V41AAAAAAAAAAGtqyRbAAAAQNeY1rEwPynWnVXaaE/XWeuRnOHS/479J+Eu7s5OplSlF41xB7E8u9WzEItaOs167xuOVcLZUKBCBF1fnfzMEQg="
do {
let envelope = try TransactionEnvelopeXDR(xdr:xdrString)
let envelopeString = envelope.xdrEncoded
} catch {
print("Invalid xdr string")
}
参阅:详细代码示例
从XDR字符串获取事务对象
let xdrString = "AAAAAJ/Ax+axve53/7sXfQY0fI6jzBeHEcPl0Vsg1C2tqyRbAAAAZAAAAAAAAAAAAAAAAQAAAABb2L/OAAAAAFvYwPoAAAAAAAAAAQAAAAEAAAAAo7FW8r8Nj+SMwPPeAoL4aUkLob7QU68+9Y8CAia5k78AAAAKAAAAN0NJcDhiSHdnU2hUR042ZDE3bjg1ZlFGRVBKdmNtNFhnSWhVVFBuUUF4cUtORVd4V3JYIGF1dGgAAAAAAQAAAEDh/7kQjZbcXypISjto5NtGLuaDGrfL/F08apZQYp38JNMNQ9p/e1Fy0z23WOg/Ic+e91+hgbdTude6+1+i0V41AAAAAA=="
do {
// Get the transaction object
let transaction = try Transaction(xdr:xdrString)
// Convert your transaction back to xdr
let transactionString = transaction.xdrEncoded
} catch {
print("Invalid xdr string")
}
5. 使用联盟服务器
在SEP-002中定义的Stellar联盟协议将Stellar地址映射为有关给定用户的更多信息。这是Stellar客户端软件解析类似邮箱地址的方法,如
name*yourdomain.com
转换成账户ID,例如
GCCVPYFOHY7ZB7557JKENAX62LUAPLMGIWNZJAFV2MITK6T32V37KEJU
Stellar地址提供了一种使用跨不同域和提供商互操作语法的简单方式,供用户分享付款详情。
5.1 获取域的联盟服务器地址
获取您的域名联盟
Federation.forDomain(domain: "https://YOUR_DOMAIN") { (response) -> (Void) in
switch response {
case .success(let federation):
//use the federation object to map your infos
case .failure(_):
//something went wrong
}
}
5.2 解析联盟地址到账户ID
解析您的地址
let federation = Federation(federationAddress: "https://YOUR_FEDERATION_SERVER")
federation.resolve(address: "bob*YOUR_DOMAIN") { (response) -> (Void) in
switch response {
case .success(let federationResponse):
if let accountId = federationResponse.accountId {
// use the account id
} else {
// there is no account id corresponding to the given address
}
case .failure(_):
// something went wrong
}
}
6. 锚定点与客户端互操作性
Stellar生态系统提案SEP-006定义了代表用户与锚点和钱包交互的标准方式。通过允许钱包和其他客户端直接与锚点交互,而无需用户离开钱包访问锚点的网站,从而提高了用户体验。
该协议要求锚点在其TRANSFER_SERVER上实现端点。锚点必须在stellar.toml中定义其传输服务器位置。这是钱包知道在哪里找到锚点服务器的方法。
示例:TRANSFER_SERVER="https://api.example.com"
6.1 获取特定域的TransferServerService
获取您域名的TransferServerService
TransferServerService.forDomain(domain: "https://YOUR_DOMAIN") { (response) -> (Void) in
switch response {
case .success(let transferServerService):
// use the transferServerService object to call other operations
case .failure(_):
// something went wrong
}
}
6.2 使用锚点存入外部资产
存入是指用户将外部代币(通过比特币的BTC、通过银行转账的USD等)发送到由锚点持有的地址。作为交换,锚点通过Stellar网络向用户的Stellar账户发送等量的代币(扣除费用)。存款端点允许钱包从锚点获取存款信息,因此用户可以发起存款。它还允许锚点指定用户必须通过/customer端点提交的附加信息(如果需要),以便能够存入。
let request = DepositRequest(assetCode: "BTC", account: "GAK7I2E6PVBFF27NU5MRY6UXGDWAJT4PF2AH46NUWLFJFFVLOZIEIO4Q")
transferServerService.deposit(request: request) { (response) -> (Void) in
switch response {
case .success(let response):
// deposit was sent with success
case .failure(_):
// something went wrong
}
}
6.3 从锚点提取资产
此操作允许用户通过Stellar资产的锚点将当前位于Stellar网络上的资产(BTC、USD、股票等)兑换成真实资产。提取端点允许钱包从锚点获取提取信息,因此用户可以获取发起提取所需的所有信息。它还允许锚点指定用户必须通过/customer端点提交的附加信息(如果需要),以便能够提取。
let request = WithdrawRequest(type: "crypto", assetCode: "BTC", dest: "GAK7I2E6PVBFF27NU5MRY6UXGDWAJT4PF2AH46NUWLFJFFVLOZIEIO4Q")
transferServerService.withdraw(request: request) { (response) -> (Void) in
switch response {
case .success(let info):
// the withdraw operation completed successfully
case .failure(_):
// something went wrong
}
}
6.4 向用户传达抵押存款与取款费用结构
允许抵押方向钱包和客户端传达其TRANSFER_SERVER所支持的基本信息。
transferServerService.info { (response) -> (Void) in
switch response {
case .success(let info):
// info returned successfully
case .failure(_):
// something went wrong
}
}
6.5 使用交易历史端点
交易历史端点帮助抵押方为使用外部钱包的用户提供更好的体验。通过它,钱包可以在处理过程中显示存款和取款状态以及与抵押方过去的交易记录。这仅适用于向抵押方存款或从抵押方取款的交易。
let request = AnchorTransactionsRequest(assetCode: "BTC", account: "GAK7I2E6PVBFF27NU5MRY6UXGDWAJT4PF2AH46NUWLFJFFVLOZIEIO4Q")
transferServerService.getTransactions(request: request) { (response) -> (Void) in
switch response {
case .success(let transactions):
// the past transactions returned successfully
case .failure(_):
// something went wrong
}
}
6.7 删除客户的所有KYC信息
删除抵押方存储的某客户的全部个人信息。[账号]是要删除的客户Stellar账户ID (G...)。此请求必须通过SEP-10进行身份验证,以证明其来自即将被删除账户的所有者。
transferServerService.deleteCustomerInfo(account: "GAK7I2E6PVBFF27NU5MRY6UXGDWAJT4PF2AH46NUWLFJFFVLOZIEIO4Q") { (response) -> (Void) in
switch response {
case .success:
// all information for the given account was deleted successfully
case .failure(_):
// something went wrong
}
}
7. 促进委托签名的URI方案
《Stellar生态系统提案》SEP-007 介绍了一种URI方案,可以用来生成一个URI,该URI将作为请求用于签署交易。该URI(请求)通常由用户受信任的钱包签名,其中存储了用户的密钥。
7.1 为签署交易生成URI。
生成一个URI,用作签署交易的请求。该URI(请求)通常会由用户受信任的钱包签名,用户在那里存储了密钥。
// create the payment operation
let paymentOperation = try! PaymentOperation(sourceAccountId: sourceAccountId,
destinationAccountId: destinationAccountId,
asset: Asset(type: AssetType.ASSET_TYPE_NATIVE)!,
amount: 1.5)
// create the transaction containing the payment operation
let transaction = try! Transaction(sourceAccount: accountResponse,
operations: [paymentOperation],
memo: Memo.none)
// create the URIScheme object
let uriSchemeBuilder = URIScheme()
// get the URI with your transactionXDR
// more params can be added to the url, check method definition
let uriScheme = uriSchemeBuilder.getSignTransactionURI(transactionXDR: transaction.transactionXDR, callBack: "your_callback_api.com")
print (uriScheme);
参阅:[详细代码示例](https://github.com/Soneso/stellar-ios-mac-sdk/blob/master/stellarsdk/stellarsdkTests/docs/QuickStartTest.swift#L372)
7.2 为支付操作生成URI
生成一个URI,用作为请求特定地址特定的资产,无论付款人使用的源资产是什么。
let uriSchemeBuilder = URIScheme()
// more params can be added to the url, check method definition
let uriScheme = uriSchemeBuilder.getPayOperationURI(destination: "GAK7I2E6PVBFF27NU5MRY6UXGDWAJT4PF2AH46NUWLFJFFVLOZIEIO4Q", amount: 100, assetCode: "BTC", assetIssuer:"GC2PIUYXSD23UVLR5LZJPUMDREQ3VTM23XVMERNCHBRTRVFKWJUSRON5", callBack: "your_callback_api.com")
print (uriScheme);
参阅:[详细代码示例](https://github.com/Soneso/stellar-ios-mac-sdk/blob/master/stellarsdk/stellarsdkTests/docs/QuickStartTest.swift#L424)
7.3 从给定的URI签署交易并发送到网络
签署来自URI的交易,并发送到回调URL(如果存在)或stellar网络。
uriBuilder.signTransaction(forURL: uri, signerKeyPair: keyPair, transactionConfirmation: { (transaction) -> (Bool) in
// here the transaction from the uri can be checked and confirmed if the signing should continue
return true
}) { (response) -> (Void) in
switch response {
case .success:
// the transaction was successfully signed
case .failure(error: let error):
// the transaction wasn't valid or it didn't pass the confirmation
}
8. Stellar Web认证
本 SEP 规定了客户端(例如钱包或交易所)代表持有 Stellar 账户的用户创建身份验证 Web 会话的标准方式。钱包可能需要与任何需要 Stellar 账户所有权验证的 Web 服务进行身份验证,例如,按照 SEP-6 描述的方式以身份验证的方式上传 KYC 信息到锚节点。Stellar Web 身份验证在 SEP-0010 中进行描述。
8.1 获取 JWT 令牌。
与服务器进行身份验证并获取 JWT 令牌。
// Hold a strong reference to this to avoid being deallocated
let webAuthenticator = WebAuthenticator(authEndpoint: "http://your_api.stellar.org/auth", network: .testnet, serverSigningKey: "GBWMCCC3NHSKLAOJDBKKYW7SSH2PFTTNVFKWSGLWGDLEBKLOVP5JLBBP", serverHomeDomain: "yourserverhomedomain.com" )
if let keyPair = try? KeyPair(secretSeed: "SBAYNYLQFXVLVAHW4BXDQYNJLMDQMZ5NQDDOHVJD3PTBAUIJRNRK5LGX") {
webAuthenticator.jwtToken(forKeyPair: keyPair) { (response) -> (Void) in
switch response {
case .success(let jwtToken):
// use the token to do your calls
case .failure(let error):
// handle the error
}
}
}
}
8.2 从 stellar.toml 创建 WebAuthenticator
通过加载特定域的 stellar.toml 文件中的 Web 认证端点和服务器签名密钥来创建 WebAuthenticator。
let webAuthenticator = WebAuthenticator.from(domain:"yourserverhomedomain.com", network: .testnet)
现在可以使用 Web Authenticator 获取 JWT 令牌(见:8.1)
9. Txrep:Stellar 交易的易于阅读的低级别表示
Txrep:Stellar 交易的易于阅读的低级别表示在 SEP-0011 中进行描述。
有关更详细的信息,请参阅我们的 Txrep 示例
文档和示例
您可以在 docs 文件夹中找到更多文档和示例。
示例
我们的SDK被开源的LOBSTR Vault使用。您可以在这里找到LOBSTR Vault的源代码。
我们的SDK也被LOBSTR 钱包使用。
实现了Stellar生态系统提案(SEPs)
- SEP-0001 - Stellar Info文件(TOML格式)
- SEP-0002 - 联邦协议
- SEP-0005 - Stellar账户的密钥派生方法
- SEP-0006 - Anchor/客户端互操作性
- SEP-0007 - 促进委托签名尿剂的URI方案
- SEP-0009 - 标准KYC /AML字段
- SEP-0010 - Stellar Web身份验证
- SEP-0011 - Txrep
- SEP-0012 - Anchor/客户端客户信息传输
Soroban支持
此SDK为Soroban提供了实验性支持。
如何贡献
请阅读我们的贡献指南。
然后请签署贡献许可协议。
许可
stellar-ios-mac-sdk遵循Apache-2.0许可协议。有关详细信息,请参阅LICENSE文件。
捐赠
请将lumen发送到:GANSYJ64BTHYFM6BAJEWXYLVSZVSHYZFPW4DIQDWJL5BOT6O6GUE7JM5