viz-swift-lib is a low-level, highly flexible Swift library for interacting with the VIZ blockchain.
It provides building blocks for:
- creating operations
- composing transactions
- computing transaction digests
- signing transactions with
secp256k1 - broadcasting transactions to the network
The library does not impose any architecture and does not hide protocol details, making it suitable for:
- mobile wallets
- backend services
- bots
- experimental and research projects
Unlike high-level SDKs, viz-swift-lib focuses on:
- Full control — you explicitly create operations, transactions, and signatures
- Composability — multiple operations can be combined in a single transaction
- Security — private keys and signing always remain under your control
- Cross-platform — works on Apple platforms and Linux
If you understand how the VIZ blockchain works, this library does not abstract or restrict anything.
Add the following to your Package.swift:
dependencies: [
.package(
url: "https://github.com/viz-blockchain/viz-swift-lib.git",
.upToNextMinor(from: "0.1.0")
)
]Or in Xcode: File → Add Packages → Enter the repository URL.
import VIZ
let client = VIZ.Client(address: URL(string: "https://node.viz.cx")!)let request = VIZ.API.GetAccounts(names: ["alice"])
let accounts = try await client.send(request)
if let account = accounts.first {
print("Balance: \(account.balance)")
print("Energy: \(account.energy)")
print("Vesting Shares: \(account.vestingShares)")
}// Get dynamic global properties for transaction reference
let props = try await client.send(VIZ.API.GetDynamicGlobalProperties())
// Create a private key from seed
guard let privateKey = VIZ.PrivateKey(seed: "alice" + "active" + "password") else {
throw Error.invalidKey
}
// Create a transfer operation
let transfer = VIZ.Operation.Transfer(
from: "alice",
to: "bob",
amount: VIZ.Asset(10.0, .viz),
memo: "Thanks for everything!"
)
// Build the transaction
let transaction = VIZ.Transaction(
refBlockNum: UInt16(props.headBlockNumber & 0xFFFF),
refBlockPrefix: props.headBlockId.prefix,
expiration: props.time.addingTimeInterval(60),
operations: [transfer]
)
// Sign and broadcast
let signedTx = try transaction.sign(usingKey: privateKey)
let broadcast = VIZ.API.BroadcastTransaction(transaction: signedTx)
let confirmation = try await client.send(broadcast)
print("Transaction ID: \(confirmation.id.base58EncodedString() ?? "")")let award = VIZ.Operation.Award(
initiator: "alice",
receiver: "bob",
energy: 1000, // 10% energy
customSequence: 0,
memo: "Great content!",
beneficiaries: [
VIZ.Operation.Beneficiary(account: "charlie", weight: 1000)
]
)
let transaction = VIZ.Transaction(
refBlockNum: UInt16(props.headBlockNumber & 0xFFFF),
refBlockPrefix: props.headBlockId.prefix,
expiration: props.time.addingTimeInterval(60),
operations: [award]
)
let signedTx = try transaction.sign(usingKey: regularKey)// Generate keys for the new account
let masterKey = VIZ.PrivateKey(seed: "newuser" + "master" + "password")!
let activeKey = VIZ.PrivateKey(seed: "newuser" + "active" + "password")!
let regularKey = VIZ.PrivateKey(seed: "newuser" + "regular" + "password")!
let memoKey = VIZ.PrivateKey(seed: "newuser" + "memo" + "password")!
let accountCreate = VIZ.Operation.AccountCreate(
fee: VIZ.Asset(1.0, .viz),
creator: "alice",
newAccountName: "newuser",
master: VIZ.Authority(keyAuths: [VIZ.Authority.Auth(masterKey.createPublic())]),
active: VIZ.Authority(keyAuths: [VIZ.Authority.Auth(activeKey.createPublic())]),
regular: VIZ.Authority(keyAuths: [VIZ.Authority.Auth(regularKey.createPublic())]),
memoKey: memoKey.createPublic(),
jsonMetadata: ""
)let delegate = VIZ.Operation.DelegateVestingShares(
delegator: "alice",
delegatee: "bob",
vestingShares: VIZ.Asset(1000.0, .vests)
)let history = VIZ.API.GetAccountHistory(
account: "alice",
from: -1,
limit: 100
)
let operations = try await client.send(history)
for item in operations {
print("Block: \(item.value.block)")
print("Operation: \(item.value.operation)")
print("Timestamp: \(item.value.timestamp)")
}// Generate a private key from account name and password
let privateKey = VIZ.PrivateKey(seed: "username" + "active" + "password")!
// Derive the public key
let publicKey = privateKey.createPublic()
print("Public Key: \(publicKey.address)")
print("Private Key (WIF): \(privateKey.wif)")// From WIF format
let privateKey = VIZ.PrivateKey("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3")!
// From raw bytes
let keyData = Data(/* 33 bytes with network ID */)
let privateKey = VIZ.PrivateKey(keyData)let message = "Hello VIZ".data(using: .utf8)!.sha256Digest
let signature = try privateKey.sign(message: message)
let publicKey = signature.recover(message: message, prefix: .mainNet)
print("Recovered public key: \(publicKey?.address ?? "none")")// Create assets
let vizTokens = VIZ.Asset(100.5, .viz) // 100.500 VIZ
let vestingShares = VIZ.Asset(1000.0, .vests) // 1000.000000 VESTS
// Parse from string
let asset = VIZ.Asset("50.000 VIZ")!
// Access amount with proper precision
print(asset.resolvedAmount) // 50.0
print(asset.description) // "50.000 VIZ"Create delegated signing requests using viz:// URLs:
// Create a signing URL with an operation
let transfer = VIZ.Operation.Transfer(
from: "__signer",
to: "bob",
amount: VIZ.Asset(5.0, .viz),
memo: "Payment"
)
let params = VIZ.VIZURL.Params(
signer: "alice",
callback: "https://myapp.com/callback?tx={{id}}&sig={{sig}}",
noBroadcast: false
)
let signingURL = VIZ.VIZURL(operation: transfer, params: params)!
print(signingURL.description)
// Resolve the URL to a transaction
let options = VIZ.VIZURL.ResolveOptions(
refBlockNum: UInt16(props.headBlockNumber & 0xFFFF),
refBlockPrefix: props.headBlockId.prefix,
expiration: props.time.addingTimeInterval(60),
signer: "alice"
)
let transaction = try signingURL.resolve(with: options)The library supports all VIZ blockchain operations including:
- Account management (create, update, recovery)
- Witness operations (voting, updates)
- Content operations (custom json, awards)
- Economic operations (transfers, conversions, escrow)
- And many more...
All types conform to VIZEncodable for efficient binary serialization:
let encoder = VIZ.VIZEncoder()
try transaction.binaryEncode(to: encoder)
let binaryData = encoder.dataDefine complex signing authorities with weights:
let authority = VIZ.Authority(
weightThreshold: 2,
accountAuths: [
VIZ.Authority.Auth("alice", weight: 1),
VIZ.Authority.Auth("bob", weight: 1)
],
keyAuths: [
VIZ.Authority.Auth(publicKey, weight: 1)
]
)The library uses Swift's structured error handling:
do {
let result = try await client.send(request)
} catch VIZ.Client.Error.responseError(let code, let message) {
print("RPC Error \(code): \(message)")
} catch VIZ.Client.Error.networkError(let message, let error) {
print("Network Error: \(message)")
} catch {
print("Unexpected error: \(error)")
}- Swift 5.5 or later
- iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+ / Linux
- secp256k1 - ECDSA signatures and secret/public key operations on curve secp256k1
- OrderedDictionary - Ordered dictionary data structure lightweight implementation
Contributions are welcome! Please feel free to submit a Pull Request.
To run all tests simply run swift test, this will run both the unit- and integration-tests. To run them separately use the --filter flag, e.g. swift test --filter IntegrationTests
Development of the library is best done with Xcode, to generate a .xcodeproj you need to run swift package generate-xcodeproj.
To enable test coverage display go "Scheme > Manage Schemes..." menu item and edit the "viz-swift-lib" scheme, select the Test configuration and under the Options tab enable "Gather coverage for some targets" and add the viz-swift-lib target.
After adding adding more unit tests the swift test --generate-linuxmain command has to be run and the XCTestManifest changes committed for the tests to be run on Linux.
This library is available under the MIT license. See the LICENSE file for more info.
For questions and support, please visit the VIZ.cx community.