Contents

kingpin-apps/swift-cardano-explorers

Link transactions, addresses, stake accounts, pools, governance and native assets to Cardano block explorers — every explorer listed at explorer.cardano.org, on the networks each one covers.

Installation

dependencies: [
    .package(url: "https://github.com/Kingpin-Apps/swift-cardano-explorers.git", from: "0.1.0"),
],
targets: [
    .target(name: "MyApp", dependencies: [
        .product(name: "SwiftCardanoExplorers", package: "swift-cardano-explorers"),
    ]),
]

It depends only on swift-cardano-core (0.5.0 or later) and swift-nacl.

Explorers

| Explorer | Mainnet | Preprod | Preview | Pages | |---|:-:|:-:|:-:|---| | AdaStat | ✓ | | | everything but committee members | | Cardanoscan | ✓ | ✓ | ✓ | everything | | Cexplorer | ✓ | ✓ | ✓ | everything | | DRepTalk | ✓ | ✓ | | DReps, governance actions | | eUTxO | ✓ | | | transactions, blocks | | Pool PM | ✓ | | | addresses, accounts, pools, DReps, policies, assets | | PoolTool | ✓ | | | accounts, pools |

The URL each explorer gets for each kind of page is in the Explorer Coverage article. Every format was checked against the live sites with real mainnet items.

Usage

Linking

Give an ExplorerItem, as a swift-cardano-core value, and a network:

import SwiftCardanoCore
import SwiftCardanoExplorers

let pool = ExplorerItem.pool(try PoolOperator(from: "pool1…"))

BlockchainExplorer.cardanoScan.link(for: pool, on: .mainnet)  // https://cardanoscan.io/pool/pool1…
BlockchainExplorer.poolTool.link(for: pool, on: .mainnet)     // https://pooltool.io/pool/<hex>
BlockchainExplorer.poolTool.link(for: pool, on: .preview)     // nil: PoolTool is mainnet only

link(for:on:) returns nil where there is no page. url(for:on:) throws an ExplorerError that says why:

try BlockchainExplorer.cexplorer.url(for: .block(.number(14_003_180)), on: .mainnet)
// ExplorerError: Cexplorer links blocks by hash, not number.

The items:

.transaction(TransactionId)
.address(Address)
.account(Address)              // a stake address, or any address with a stake part
.block(.number(n)), .block(.bodyHash(hash))
.epoch(EpochNumber)
.pool(PoolOperator)
.drep(DRep)                    // written as CIP-129, drep1y…
.governanceAction(GovActionID)
.committeeMember(CommitteeColdCredential)
.policy(PolicyID)
.asset(policy: PolicyID, name: AssetName)

A setting, with a fallback

struct ExplorerSetting: View {
    @AppStorage("blockchainExplorer") private var explorer = BlockchainExplorer.cexplorer

    var body: some View {
        Picker("Explorer", selection: $explorer) {
            ForEach(BlockchainExplorer.allCases) { Text($0.name).tag($0) }
        }
    }
}

Not every explorer has every page on every network, so fall back to one that does, and say which:

func opening(_ item: ExplorerItem, on network: Network, preferring chosen: BlockchainExplorer)
    -> (BlockchainExplorer, URL)?
{
    for explorer in [chosen, .cardanoScan, .cexplorer] {
        if let url = explorer.link(for: item, on: network) { return (explorer, url) }
    }
    return nil
}

BlockchainExplorer.supporting(.drep, on: .preprod)  // [.cardanoScan, .cexplorer, .drepTalk]

Reading a pasted link

if let link = ExplorerLink(URL(string: "https://preprod.cardanoscan.io/transaction/01e9…")!),
   case .transaction(let id) = link.item {
    fetch(id, on: link.network)  // .preprod
}

Assets linked by fingerprint, and accounts linked by credential hash, cannot be read back: neither says everything the item needs.

Asset fingerprints

try assetName.fingerprint(policy: policyID)  // "asset1…", per CIP-14

Your own explorer

Conform a type to BlockchainExplorable, give its name, sites and supported kinds, and write the view… methods it has; the rest throw unsupportedItem:

struct MyExplorer: BlockchainExplorable {
    let network: Network
    let name = "My Explorer"
    let networkUrls = NetworkURLs(mainnet: URL(string: "https://myexplorer.io")!)
    let supportedItems: Set<ExplorerItem.Kind> = [.transaction]

    func viewTransaction(transactionId: TransactionId) throws -> URL {
        try baseURL.appendingPathComponent("tx").appendingPathComponent(transactionId.payload.toHex)
    }
}

Documentation

The full documentation, with articles on getting started, choosing an explorer, coverage, reading links and adding explorers, is on the Swift Package Index. To build it locally, use Xcode's Product › Build Documentation.

Contributing

To add an explorer, add its type under Sources/SwiftCardanoExplorers/Explorers/, a case to BlockchainExplorer, and golden URLs to the tests: real mainnet items whose links you have opened and seen the right page. The tests check that every explorer links each kind it claims and no other, and that every link reads back through ExplorerLink.

swift test

License

MIT. See LICENSE.

Package Metadata

Repository: kingpin-apps/swift-cardano-explorers

Default branch: main

README: README.md