Use UnifiedSpendingKey for shielding and Spending (#535)
[#534] Use UnifiedSpendingKey for shielding and Spending This commit implements the use of Unified Spending Keys for shielding and spending as well as rolling Unified Addresses. Users should obtain addresses by rolling them from the SDK. USKs replace Sapling Extended Spending keys and TransparentAccountPrivKeys when shielding or spending Closes #534 Co-authored-by: Kris Nuttycombe <kris@nutty.land> * Fix rebase issues * PR Suggestion. Make `lastError` an Optional * Fix test `testReOrgRemovesOutboundTxAndIsNeverMined` Co-authored-by: Kris Nuttycombe <kris@nutty.land>
This commit is contained in:
parent
10a884ba60
commit
7806b5114f
|
@ -7,7 +7,6 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0D1BE4512581585C00F78BE3 /* DerivationToolViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1BE4502581585C00F78BE3 /* DerivationToolViewController.swift */; };
|
||||
0D1BE47F2581937100F78BE3 /* GetUTXOsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1BE47E2581937100F78BE3 /* GetUTXOsViewController.swift */; };
|
||||
0D49A18C241698A800CC0649 /* SampleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D49A18B241698A800CC0649 /* SampleLogger.swift */; };
|
||||
0D4EBA312396CFD70041B507 /* SendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4EBA302396CFD70041B507 /* SendViewController.swift */; };
|
||||
|
@ -33,7 +32,6 @@
|
|||
0DA1C4C627D11D9500E5006E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D907F152322CC5900D641FE /* AppDelegate.swift */; };
|
||||
0DA1C4C727D11D9500E5006E /* SaplingParametersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6CE8BC252E3C4A0005D707 /* SaplingParametersViewController.swift */; };
|
||||
0DA1C4C827D11D9500E5006E /* GetUTXOsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1BE47E2581937100F78BE3 /* GetUTXOsViewController.swift */; };
|
||||
0DA1C4C927D11D9500E5006E /* DerivationToolViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1BE4502581585C00F78BE3 /* DerivationToolViewController.swift */; };
|
||||
0DA1C4CB27D11D9500E5006E /* SampleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D49A18B241698A800CC0649 /* SampleLogger.swift */; };
|
||||
0DA1C4CC27D11D9500E5006E /* TransactionsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DA58B952397F2CB004596EA /* TransactionsDataSource.swift */; };
|
||||
0DA1C4CD27D11D9500E5006E /* PaginatedTransactionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DF53E6623A438F100D7249C /* PaginatedTransactionsViewController.swift */; };
|
||||
|
@ -72,7 +70,6 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0D1BE4502581585C00F78BE3 /* DerivationToolViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DerivationToolViewController.swift; sourceTree = "<group>"; };
|
||||
0D1BE47E2581937100F78BE3 /* GetUTXOsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetUTXOsViewController.swift; sourceTree = "<group>"; };
|
||||
0D49A18B241698A800CC0649 /* SampleLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLogger.swift; sourceTree = "<group>"; };
|
||||
0D4EBA302396CFD70041B507 /* SendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -143,14 +140,6 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0D1BE44F2581583D00F78BE3 /* Derivation Tool */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D1BE4502581585C00F78BE3 /* DerivationToolViewController.swift */,
|
||||
);
|
||||
path = "Derivation Tool";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D1BE47D2581933C00F78BE3 /* Get UTXOs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -227,7 +216,6 @@
|
|||
children = (
|
||||
0D76121426B1D5D7001CA417 /* Constants */,
|
||||
0D1BE47D2581933C00F78BE3 /* Get UTXOs */,
|
||||
0D1BE44F2581583D00F78BE3 /* Derivation Tool */,
|
||||
0D6CE8BB252E3C1A0005D707 /* Sapling Parameters */,
|
||||
0DBF8F9323A80F0E0010B85F /* Transaction Detail */,
|
||||
0DF53E6523A438BA00D7249C /* Paginated Transactions */,
|
||||
|
@ -530,7 +518,6 @@
|
|||
0D907F162322CC5900D641FE /* AppDelegate.swift in Sources */,
|
||||
0D6CE8BD252E3C4A0005D707 /* SaplingParametersViewController.swift in Sources */,
|
||||
0D1BE47F2581937100F78BE3 /* GetUTXOsViewController.swift in Sources */,
|
||||
0D1BE4512581585C00F78BE3 /* DerivationToolViewController.swift in Sources */,
|
||||
0D49A18C241698A800CC0649 /* SampleLogger.swift in Sources */,
|
||||
0DA58B962397F2CB004596EA /* TransactionsDataSource.swift in Sources */,
|
||||
0DF53E6723A438F100D7249C /* PaginatedTransactionsViewController.swift in Sources */,
|
||||
|
@ -562,7 +549,6 @@
|
|||
0DA1C4C627D11D9500E5006E /* AppDelegate.swift in Sources */,
|
||||
0DA1C4C727D11D9500E5006E /* SaplingParametersViewController.swift in Sources */,
|
||||
0DA1C4C827D11D9500E5006E /* GetUTXOsViewController.swift in Sources */,
|
||||
0DA1C4C927D11D9500E5006E /* DerivationToolViewController.swift in Sources */,
|
||||
0DA1C4CB27D11D9500E5006E /* SampleLogger.swift in Sources */,
|
||||
0DA1C4CC27D11D9500E5006E /* TransactionsDataSource.swift in Sources */,
|
||||
0DA1C4CD27D11D9500E5006E /* PaginatedTransactionsViewController.swift in Sources */,
|
||||
|
|
|
@ -1,151 +1,149 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "grpc-swift",
|
||||
"repositoryURL": "https://github.com/grpc/grpc-swift.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "466cc881f1760ed8c0e685900ed62dab7846a571",
|
||||
"version": "1.8.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "KRActivityIndicatorView",
|
||||
"repositoryURL": "https://github.com/krimpedance/KRActivityIndicatorView.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "bcb0e841d6de0cd343a32bd5056580a56d06c0bc",
|
||||
"version": "3.0.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "KRProgressHUD",
|
||||
"repositoryURL": "https://github.com/krimpedance/KRProgressHUD.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "265142816d8f8ea93840accaf4ac7c49998e77c2",
|
||||
"version": "3.4.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "MnemonicSwift",
|
||||
"repositoryURL": "https://github.com/zcash-hackworks/MnemonicSwift.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "716a2c32ac2bbd8a1499ac834077df42b75edc85",
|
||||
"version": "2.2.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "NotificationBubbles",
|
||||
"repositoryURL": "https://github.com/pacu/NotificationBubbles.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "ae6d47f3a415c9eec5daa8e04d040c0e68654f00",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "PaginatedTableView",
|
||||
"repositoryURL": "https://github.com/dh-ecc/PaginatedTableView",
|
||||
"state": {
|
||||
"branch": "master",
|
||||
"revision": "a3fd9f079d6c9ac3095ee3ef2369a68c29ba04db",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SQLite.swift",
|
||||
"repositoryURL": "https://github.com/stephencelis/SQLite.swift.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "60a65015f6402b7c34b9a924f755ca0a73afeeaa",
|
||||
"version": "0.13.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-crypto",
|
||||
"repositoryURL": "https://github.com/apple/swift-crypto.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "d9825fa541df64b1a7b182178d61b9a82730d01f",
|
||||
"version": "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-log",
|
||||
"repositoryURL": "https://github.com/apple/swift-log.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
|
||||
"version": "1.4.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "51c3fc2e4a0fcdf4a25089b288dd65b73df1b0ef",
|
||||
"version": "2.37.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-extras",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-extras.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f73ca5ee9c6806800243f1ac415fcf82de9a4c91",
|
||||
"version": "1.10.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-http2",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-http2.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "108ac15087ea9b79abb6f6742699cf31de0e8772",
|
||||
"version": "1.22.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-ssl",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "52a486ff6de9bc3e26bf634c5413c41c5fa89ca5",
|
||||
"version": "2.17.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-transport-services",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-transport-services.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "8ab824b140d0ebcd87e9149266ddc353e3705a3e",
|
||||
"version": "1.11.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftProtobuf",
|
||||
"repositoryURL": "https://github.com/apple/swift-protobuf.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "e1499bc69b9040b29184f7f2996f7bab467c1639",
|
||||
"version": "1.19.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "libzcashlc",
|
||||
"repositoryURL": "https://github.com/zcash-hackworks/zcash-light-client-ffi",
|
||||
"state": {
|
||||
"branch": "bin/librustzcash_0_7",
|
||||
"revision": "823f864a7952073fb9718cf75610691756e34d59",
|
||||
"version": null
|
||||
}
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "grpc-swift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/grpc/grpc-swift.git",
|
||||
"state" : {
|
||||
"revision" : "466cc881f1760ed8c0e685900ed62dab7846a571",
|
||||
"version" : "1.8.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"identity" : "kractivityindicatorview",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/krimpedance/KRActivityIndicatorView.git",
|
||||
"state" : {
|
||||
"revision" : "bcb0e841d6de0cd343a32bd5056580a56d06c0bc",
|
||||
"version" : "3.0.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "krprogresshud",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/krimpedance/KRProgressHUD.git",
|
||||
"state" : {
|
||||
"revision" : "265142816d8f8ea93840accaf4ac7c49998e77c2",
|
||||
"version" : "3.4.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "mnemonicswift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zcash-hackworks/MnemonicSwift.git",
|
||||
"state" : {
|
||||
"revision" : "716a2c32ac2bbd8a1499ac834077df42b75edc85",
|
||||
"version" : "2.2.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "notificationbubbles",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pacu/NotificationBubbles.git",
|
||||
"state" : {
|
||||
"revision" : "ae6d47f3a415c9eec5daa8e04d040c0e68654f00",
|
||||
"version" : "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "paginatedtableview",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/dh-ecc/PaginatedTableView",
|
||||
"state" : {
|
||||
"branch" : "master",
|
||||
"revision" : "a3fd9f079d6c9ac3095ee3ef2369a68c29ba04db"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "sqlite.swift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/stephencelis/SQLite.swift.git",
|
||||
"state" : {
|
||||
"revision" : "60a65015f6402b7c34b9a924f755ca0a73afeeaa",
|
||||
"version" : "0.13.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-crypto",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-crypto.git",
|
||||
"state" : {
|
||||
"revision" : "d9825fa541df64b1a7b182178d61b9a82730d01f",
|
||||
"version" : "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-log",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-log.git",
|
||||
"state" : {
|
||||
"revision" : "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
|
||||
"version" : "1.4.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio.git",
|
||||
"state" : {
|
||||
"revision" : "51c3fc2e4a0fcdf4a25089b288dd65b73df1b0ef",
|
||||
"version" : "2.37.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-extras",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-extras.git",
|
||||
"state" : {
|
||||
"revision" : "f73ca5ee9c6806800243f1ac415fcf82de9a4c91",
|
||||
"version" : "1.10.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-http2",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-http2.git",
|
||||
"state" : {
|
||||
"revision" : "108ac15087ea9b79abb6f6742699cf31de0e8772",
|
||||
"version" : "1.22.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-ssl",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-ssl.git",
|
||||
"state" : {
|
||||
"revision" : "52a486ff6de9bc3e26bf634c5413c41c5fa89ca5",
|
||||
"version" : "2.17.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-transport-services",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-transport-services.git",
|
||||
"state" : {
|
||||
"revision" : "8ab824b140d0ebcd87e9149266ddc353e3705a3e",
|
||||
"version" : "1.11.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-protobuf",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||
"state" : {
|
||||
"revision" : "e1499bc69b9040b29184f7f2996f7bab467c1639",
|
||||
"version" : "1.19.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "zcash-light-client-ffi",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
|
||||
"state" : {
|
||||
"branch" : "bin/librustzcash_0_7",
|
||||
"revision" : "14d5b977a076775447a0630387596c21cacbd09a"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
||||
|
|
|
@ -33,8 +33,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
if let wallet = wallet {
|
||||
return wallet
|
||||
} else {
|
||||
let unifiedFullViewingKeys = try! DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
.deriveUnifiedFullViewingKeysFromSeed(DemoAppConfig.seed, numberOfAccounts: 1)
|
||||
let ufvk = try! DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
.deriveUnifiedSpendingKey(seed: DemoAppConfig.seed, accountIndex: 0)
|
||||
.deriveFullViewingKey()
|
||||
|
||||
let wallet = Initializer(
|
||||
cacheDbURL: try! cacheDbURLHelper(),
|
||||
|
@ -44,7 +45,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
network: kZcashNetwork,
|
||||
spendParamsURL: try! spendParamsURLHelper(),
|
||||
outputParamsURL: try! outputParamsURLHelper(),
|
||||
viewingKeys: unifiedFullViewingKeys,
|
||||
viewingKeys: [ufvk],
|
||||
walletBirthday: DemoAppConfig.birthdayHeight,
|
||||
loggerProxy: loggerProxy
|
||||
)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21208.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Ewq-Xy-xHb">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Ewq-Xy-xHb">
|
||||
<device id="retina6_0" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21191"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
|
@ -12,7 +14,7 @@
|
|||
<objects>
|
||||
<tableViewController storyboardIdentifier="MainTableViewController" id="SI9-Nk-8cq" customClass="MainTableViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="EVy-1I-VtG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<sections>
|
||||
|
@ -274,19 +276,16 @@
|
|||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<segue destination="urD-um-X0E" kind="show" id="5XW-nP-b85"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="qHq-xq-jFS" style="IBUITableViewCellStyleDefault" id="XHY-aU-r1N">
|
||||
<rect key="frame" x="0.0" y="617.66668319702148" width="600" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="617.66668319702148" width="600" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="XHY-aU-r1N" id="fbk-CU-wgr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" text="Get UTXOs For transparent Address" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="qHq-xq-jFS">
|
||||
<rect key="frame" x="8" y="0.0" width="398" height="43.5"/>
|
||||
<rect key="frame" x="8" y="0.0" width="374" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
|
@ -323,7 +322,7 @@
|
|||
<objects>
|
||||
<viewController id="6wc-2b-HvC" customClass="PaginatedTransactionsViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="7UD-Cl-PlM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="7kA-7f-dpe" customClass="PaginatedTableView" customModule="PaginatedTableView">
|
||||
|
@ -385,7 +384,7 @@
|
|||
<objects>
|
||||
<tableViewController id="Ya7-uX-3Bq" customClass="TransactionsTableViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Btf-Ps-SgQ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<prototypes>
|
||||
|
@ -433,7 +432,7 @@
|
|||
<objects>
|
||||
<tableViewController id="E2F-Pe-9WA" customClass="TransactionDetailViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="GZf-SE-Mi3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<sections>
|
||||
|
@ -610,7 +609,7 @@
|
|||
<objects>
|
||||
<viewController title="Send Funds" id="6mH-Rv-HBn" customClass="SendViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="mzn-Gc-de9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="TpC-jA-EZ0">
|
||||
|
@ -815,7 +814,7 @@
|
|||
<objects>
|
||||
<viewController title="Get Addreses" id="Rx9-1X-8Gi" customClass="GetAddressViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="5WU-Pu-1e9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="TGE-Nt-Y1I">
|
||||
|
@ -857,7 +856,7 @@
|
|||
</view>
|
||||
<navigationItem key="navigationItem" title="Get Address" largeTitleDisplayMode="always" id="Uvy-EM-bSo"/>
|
||||
<connections>
|
||||
<outlet property="spendingKeyLabel" destination="hl0-9u-TsZ" id="afF-Yq-bty"/>
|
||||
<outlet property="saplingAddress" destination="hl0-9u-TsZ" id="afF-Yq-bty"/>
|
||||
<outlet property="tAddressLabel" destination="ntO-Ig-rst" id="6ER-bQ-FVH"/>
|
||||
<outlet property="unifiedAddressLabel" destination="X0E-Ba-xxX" id="9es-sw-gO5"/>
|
||||
</connections>
|
||||
|
@ -871,7 +870,7 @@
|
|||
<objects>
|
||||
<viewController id="Nsd-EZ-dgy" customClass="SaplingParametersViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="cqf-Dv-Buo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalCentering" translatesAutoresizingMaskIntoConstraints="NO" id="mvO-Hh-h9H">
|
||||
|
@ -946,7 +945,7 @@
|
|||
<objects>
|
||||
<viewController id="eja-yc-RHW" customClass="SyncBlocksViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="3Ob-Wz-DM3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="dp8-P5-xEk">
|
||||
|
@ -1051,7 +1050,7 @@
|
|||
<objects>
|
||||
<viewController id="tq2-zN-roj" customClass="LatestHeightViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="tie-BL-1Ip">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Hj-Jx-J3i">
|
||||
|
@ -1094,7 +1093,7 @@
|
|||
<objects>
|
||||
<navigationController id="Ewq-Xy-xHb" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="AlK-mv-yla">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
|
@ -1110,7 +1109,7 @@
|
|||
<objects>
|
||||
<viewController id="r9r-pi-Z4o" customClass="GetBalanceViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="n2N-jn-4DV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="Cep-qY-yP1">
|
||||
|
@ -1172,217 +1171,12 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="1830" y="1623"/>
|
||||
</scene>
|
||||
<!--Derivation Tool View Controller-->
|
||||
<scene sceneID="tSJ-ZN-BDT">
|
||||
<objects>
|
||||
<viewController id="urD-um-X0E" customClass="DerivationToolViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="bAZ-rg-kmi">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0JM-NT-N87">
|
||||
<rect key="frame" x="0.0" y="44" width="600" height="556"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sgq-Qs-o8o">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="556"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="lJM-ik-oa2">
|
||||
<rect key="frame" x="93" y="-77.666666666666686" width="414" height="711.33333333333348"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Type your seed phrase" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GdL-W0-t1l">
|
||||
<rect key="frame" x="120.33333333333333" y="0.0" width="173.33333333333337" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="RTm-h4-DMc"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" text="enter a seed phrase" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="C59-0R-RxT">
|
||||
<rect key="frame" x="16" y="58" width="382" height="160"/>
|
||||
<color key="backgroundColor" systemColor="systemGray4Color"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="160" id="a2K-H3-i61"/>
|
||||
</constraints>
|
||||
<color key="textColor" systemColor="labelColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences" enablesReturnKeyAutomatically="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="urD-um-X0E" id="GJK-9Q-yzM"/>
|
||||
</connections>
|
||||
</textView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="valid or invalid addresss" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nDc-QP-WuU">
|
||||
<rect key="frame" x="144.33333333333334" y="236" width="125.66666666666666" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="Cr0-L9-uab"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yn0-gU-62P">
|
||||
<rect key="frame" x="88" y="278" width="238" height="48"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="48" id="T0a-BW-X9M"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="20"/>
|
||||
<state key="normal" title="Derive Keys and Addresses"/>
|
||||
<connections>
|
||||
<action selector="deriveButtonTapped:" destination="urD-um-X0E" eventType="touchUpInside" id="psH-2C-cT6"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Shielded Address" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iKP-Wh-tZo">
|
||||
<rect key="frame" x="140.66666666666666" y="344" width="132.99999999999997" height="40"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="teC-Db-nKa"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" text="this is your zAddress" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="s7h-kh-3VS">
|
||||
<rect key="frame" x="128.33333333333337" y="402" width="157.66666666666663" height="20.333333333333314"/>
|
||||
<gestureRecognizers/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="WdA-pD-38N" appends="YES" id="keb-ur-rAo"/>
|
||||
</connections>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Transparent Address" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FtJ-j8-xGc">
|
||||
<rect key="frame" x="128" y="440.33333333333337" width="158" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="wYY-yg-8Ab"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="this is your tAddress" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PHc-2R-paD">
|
||||
<rect key="frame" x="129.66666666666669" y="498.33333333333337" width="154.66666666666669" height="20.333333333333371"/>
|
||||
<gestureRecognizers/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="Wfp-JW-CWb" appends="YES" id="LsS-BP-Aow"/>
|
||||
</connections>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Extended Full viewing Key" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mCg-81-0lp">
|
||||
<rect key="frame" x="108.33333333333333" y="536.66666666666663" width="197.33333333333337" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="ceE-X1-a4Z"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="this is Extended Full viewing Key" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ckD-nG-axZ">
|
||||
<rect key="frame" x="84" y="594.66666666666663" width="246" height="20.333333333333371"/>
|
||||
<gestureRecognizers/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="mpR-7E-CQR" appends="YES" id="ghJ-vz-Omm"/>
|
||||
</connections>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Spending Key" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BU6-q8-Q1L">
|
||||
<rect key="frame" x="154.66666666666666" y="633" width="104.99999999999997" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="owC-eB-pNf"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This is your Spending Key" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="P0V-dh-PuR">
|
||||
<rect key="frame" x="109" y="691" width="196" height="20.333333333333371"/>
|
||||
<gestureRecognizers/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="pKS-94-Kus" appends="YES" id="4ah-N9-ImG"/>
|
||||
</connections>
|
||||
</label>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="HzG-VV-dlO"/>
|
||||
<constraints>
|
||||
<constraint firstItem="HzG-VV-dlO" firstAttribute="trailing" secondItem="C59-0R-RxT" secondAttribute="trailing" constant="16" id="Oyd-ke-rdl"/>
|
||||
<constraint firstItem="C59-0R-RxT" firstAttribute="leading" secondItem="HzG-VV-dlO" secondAttribute="leading" constant="16" id="QYw-hv-FDJ"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="lJM-ik-oa2" firstAttribute="centerX" secondItem="sgq-Qs-o8o" secondAttribute="centerX" id="eLx-Qp-3Tu"/>
|
||||
<constraint firstItem="lJM-ik-oa2" firstAttribute="centerY" secondItem="sgq-Qs-o8o" secondAttribute="centerY" id="fhI-j2-4Iv"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="sgq-Qs-o8o" firstAttribute="bottom" secondItem="0JM-NT-N87" secondAttribute="bottom" id="1B1-Wq-1sP"/>
|
||||
<constraint firstItem="sgq-Qs-o8o" firstAttribute="top" secondItem="0JM-NT-N87" secondAttribute="top" id="PXs-CQ-jqU"/>
|
||||
<constraint firstItem="sgq-Qs-o8o" firstAttribute="centerX" secondItem="0JM-NT-N87" secondAttribute="centerX" id="cf0-Ew-OFX"/>
|
||||
<constraint firstItem="sgq-Qs-o8o" firstAttribute="leading" secondItem="0JM-NT-N87" secondAttribute="leading" id="iry-BX-4gc"/>
|
||||
<constraint firstItem="sgq-Qs-o8o" firstAttribute="centerY" secondItem="0JM-NT-N87" secondAttribute="centerY" id="t8r-Ec-Ywh"/>
|
||||
<constraint firstItem="sgq-Qs-o8o" firstAttribute="trailing" secondItem="0JM-NT-N87" secondAttribute="trailing" id="zfK-HW-dLA"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="ofo-Ei-0uk"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="0JM-NT-N87" firstAttribute="bottom" secondItem="ofo-Ei-0uk" secondAttribute="bottom" id="1MB-Ep-koz"/>
|
||||
<constraint firstItem="0JM-NT-N87" firstAttribute="top" secondItem="ofo-Ei-0uk" secondAttribute="top" id="5mI-HM-G7U"/>
|
||||
<constraint firstItem="0JM-NT-N87" firstAttribute="leading" secondItem="ofo-Ei-0uk" secondAttribute="leading" id="c6q-tW-et9"/>
|
||||
<constraint firstItem="0JM-NT-N87" firstAttribute="trailing" secondItem="ofo-Ei-0uk" secondAttribute="trailing" id="iDA-8Z-7El"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="vRQ-Ab-vha"/>
|
||||
<connections>
|
||||
<outlet property="deriveButton" destination="Yn0-gU-62P" id="JjO-iM-iYT"/>
|
||||
<outlet property="extendedFullViewingKeyLabel" destination="ckD-nG-axZ" id="5R6-3U-lIY"/>
|
||||
<outlet property="seedTextLabel" destination="nDc-QP-WuU" id="Dz7-3V-D4c"/>
|
||||
<outlet property="seedTextView" destination="C59-0R-RxT" id="qgj-cx-r7p"/>
|
||||
<outlet property="shieldedAddressLabel" destination="s7h-kh-3VS" id="i1g-QC-ZxR"/>
|
||||
<outlet property="spendingKeyLabel" destination="P0V-dh-PuR" id="nvH-b2-e7F"/>
|
||||
<outlet property="transparentAddressLabel" destination="PHc-2R-paD" id="rVu-Cp-Unt"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="CFW-FJ-RIU" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
<tapGestureRecognizer id="WdA-pD-38N">
|
||||
<connections>
|
||||
<action selector="zAddressTapped:" destination="urD-um-X0E" id="16h-CN-BzF"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<tapGestureRecognizer id="Wfp-JW-CWb">
|
||||
<connections>
|
||||
<action selector="tAddressTapped:" destination="urD-um-X0E" id="5gE-DU-6cP"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<tapGestureRecognizer id="mpR-7E-CQR">
|
||||
<connections>
|
||||
<action selector="viewingKeyTapped:" destination="urD-um-X0E" id="sEe-26-GP2"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<tapGestureRecognizer id="pKS-94-Kus">
|
||||
<connections>
|
||||
<action selector="spendingKeyTapped:" destination="urD-um-X0E" id="8U5-Nd-9pO"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-10.144927536231885" y="684.375"/>
|
||||
</scene>
|
||||
<!--Get UTXOs for tAddr-->
|
||||
<scene sceneID="lqr-tV-bOy">
|
||||
<objects>
|
||||
<viewController title="Get UTXOs for tAddr" id="Ugl-B2-O3O" customClass="GetUTXOsViewController" customModule="ZcashLightClientSample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="FUM-Ak-cpK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="40" translatesAutoresizingMaskIntoConstraints="NO" id="Dcv-Hc-vFg">
|
||||
|
@ -1435,7 +1229,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pcE-rS-DWU">
|
||||
<rect key="frame" x="93" y="388" width="414" height="168"/>
|
||||
<rect key="frame" x="105" y="388" width="390" height="168"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
</subviews>
|
||||
|
@ -1494,9 +1288,6 @@
|
|||
<systemColor name="systemGray2Color">
|
||||
<color red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemGray4Color">
|
||||
<color red="0.81960784313725488" green="0.81960784313725488" blue="0.83921568627450982" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemRedColor">
|
||||
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
//
|
||||
// DerivationToolViewController.swift
|
||||
// ZcashLightClientSample
|
||||
//
|
||||
// Created by Francisco Gindre on 12/9/20.
|
||||
// Copyright © 2020 Electric Coin Company. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ZcashLightClientKit
|
||||
import MnemonicSwift
|
||||
class DerivationToolViewController: UIViewController {
|
||||
enum DerivationErrors: Error {
|
||||
case couldNotDeriveSpendingKeys(underlyingError: Error)
|
||||
case couldNotDeriveViewingKeys(underlyingError: Error)
|
||||
case unknown
|
||||
}
|
||||
|
||||
@IBOutlet weak var seedTextView: UITextView!
|
||||
@IBOutlet weak var seedTextLabel: UILabel!
|
||||
@IBOutlet weak var shieldedAddressLabel: UILabel!
|
||||
@IBOutlet weak var transparentAddressLabel: UILabel!
|
||||
@IBOutlet weak var spendingKeyLabel: UILabel!
|
||||
@IBOutlet weak var extendedFullViewingKeyLabel: UILabel!
|
||||
@IBOutlet weak var deriveButton: UIButton!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
deriveButton.isEnabled = isValidSeed(seedTextView.text)
|
||||
updateValidationUI()
|
||||
}
|
||||
|
||||
@IBAction func spendingKeyTapped(_ gesture: UIGestureRecognizer) {
|
||||
loggerProxy.event("spending key copied to clipboard")
|
||||
|
||||
UIPasteboard.general.string = self.spendingKeyLabel.text
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: "Spending Key Copied to clipboard",
|
||||
preferredStyle: UIAlertController.Style.alert
|
||||
)
|
||||
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func viewingKeyTapped(_ gesture: UIGestureRecognizer) {
|
||||
loggerProxy.event("extended full viewing key copied to clipboard")
|
||||
|
||||
UIPasteboard.general.string = self.extendedFullViewingKeyLabel.text
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: "extended full viewing key copied to clipboard",
|
||||
preferredStyle: UIAlertController.Style.alert
|
||||
)
|
||||
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func zAddressTapped(_ gesture: UIGestureRecognizer) {
|
||||
loggerProxy.event("zAddress copied to clipboard")
|
||||
|
||||
UIPasteboard.general.string = self.shieldedAddressLabel.text
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: "zAddress Copied to clipboard",
|
||||
preferredStyle: UIAlertController.Style.alert
|
||||
)
|
||||
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func tAddressTapped(_ gesture: UIGestureRecognizer) {
|
||||
loggerProxy.event("tAddress copied to clipboard")
|
||||
|
||||
UIPasteboard.general.string = self.transparentAddressLabel.text
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: "tAddress Copied to clipboard",
|
||||
preferredStyle: UIAlertController.Style.alert
|
||||
)
|
||||
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func deriveButtonTapped(_ sender: Any) {
|
||||
do {
|
||||
try deriveFrom(seedPhrase: seedTextView.text)
|
||||
} catch {
|
||||
fail(error)
|
||||
|
||||
clearLabels()
|
||||
}
|
||||
}
|
||||
|
||||
func deriveFrom(seedPhrase: String) throws {
|
||||
let seedBytes = try Mnemonic.deterministicSeedBytes(from: seedPhrase)
|
||||
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
|
||||
guard let spendingKey = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else {
|
||||
throw DerivationErrors.couldNotDeriveSpendingKeys(underlyingError: DerivationErrors.unknown)
|
||||
}
|
||||
|
||||
guard let viewingKey = try derivationTool.deriveUnifiedFullViewingKeysFromSeed(seedBytes, numberOfAccounts: 1).first else {
|
||||
throw DerivationErrors.couldNotDeriveViewingKeys(underlyingError: DerivationErrors.unknown)
|
||||
}
|
||||
|
||||
let unifiedAddress = try derivationTool.deriveUnifiedAddress(from: viewingKey)
|
||||
|
||||
let transparentAddress = try derivationTool.deriveTransparentAddress(seed: seedBytes)
|
||||
|
||||
updateLabels(
|
||||
spendingKey: spendingKey.stringEncoded,
|
||||
viewingKey: viewingKey.stringEncoded,
|
||||
shieldedAddress: unifiedAddress.stringEncoded,
|
||||
transaparentAddress: transparentAddress.stringEncoded
|
||||
)
|
||||
}
|
||||
|
||||
func updateLabels(
|
||||
spendingKey: String = "",
|
||||
viewingKey: String = "",
|
||||
shieldedAddress: String = "",
|
||||
transaparentAddress: String = ""
|
||||
) {
|
||||
spendingKeyLabel.text = spendingKey
|
||||
extendedFullViewingKeyLabel.text = viewingKey
|
||||
shieldedAddressLabel.text = shieldedAddress
|
||||
transparentAddressLabel.text = transaparentAddress
|
||||
}
|
||||
|
||||
func clearLabels() {
|
||||
updateLabels()
|
||||
}
|
||||
|
||||
func fail(_ error: Error) {
|
||||
let alert = UIAlertController(title: "Error", message: "\(error)", preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func setValidSeed() {
|
||||
seedTextLabel.text = "This is a valid seed phrase"
|
||||
seedTextLabel.textColor = UIColor.systemGreen
|
||||
}
|
||||
|
||||
func setInvalidSeed() {
|
||||
seedTextLabel.text = "Invalid seed phrase"
|
||||
seedTextLabel.textColor = UIColor.red
|
||||
}
|
||||
|
||||
func isValidSeed(_ seed: String) -> Bool {
|
||||
do {
|
||||
try Mnemonic.validate(mnemonic: seed)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func updateValidationUI() {
|
||||
guard isValidSeed(seedTextView.text) else {
|
||||
setInvalidSeed()
|
||||
return
|
||||
}
|
||||
setValidSeed()
|
||||
}
|
||||
}
|
||||
|
||||
extension DerivationToolViewController: UITextViewDelegate {
|
||||
func textViewDidEndEditing(_ textView: UITextView) {
|
||||
updateValidationUI()
|
||||
}
|
||||
|
||||
func textViewDidChange(_ textView: UITextView) {
|
||||
deriveButton.isEnabled = isValidSeed(textView.text)
|
||||
}
|
||||
}
|
|
@ -9,26 +9,28 @@
|
|||
import UIKit
|
||||
import ZcashLightClientKit
|
||||
class GetAddressViewController: UIViewController {
|
||||
@IBOutlet weak var unifiedAddressLabel: UILabel!
|
||||
@IBOutlet weak var tAddressLabel: UILabel!
|
||||
@IBOutlet weak var spendingKeyLabel: UILabel! // THIS SHOULD BE SUPER SECRET!!!!!
|
||||
|
||||
// THIS SHOULD NEVER BE STORED IN MEMORY
|
||||
// swiftlint:disable:next implicitly_unwrapped_optional
|
||||
var spendingKey: SaplingExtendedSpendingKey!
|
||||
@IBOutlet weak var unifiedAddressLabel: UILabel! // This is your Unified Address
|
||||
@IBOutlet weak var tAddressLabel: UILabel! // this is the transparent receiver of your UA above
|
||||
@IBOutlet weak var saplingAddress: UILabel! // this is the sapling receiver of your UA above
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
|
||||
// swiftlint:disable:next force_try force_unwrapping
|
||||
self.spendingKey = try! derivationTool.deriveSpendingKeys(seed: DemoAppConfig.seed, numberOfAccounts: 1).first!
|
||||
let synchronizer = SDKSynchronizer.shared
|
||||
|
||||
guard let uAddress = synchronizer.getUnifiedAddress(accountIndex: 0) else {
|
||||
unifiedAddressLabel.text = "could not derive UA"
|
||||
tAddressLabel.text = "could not derive tAddress"
|
||||
saplingAddress.text = "could not derive zAddress"
|
||||
return
|
||||
}
|
||||
|
||||
// you can either try to extract receivers from the UA itself or request the Synchronizer to do it for you. Certain UAs might not contain all the receivers you expect.
|
||||
unifiedAddressLabel.text = uAddress.stringEncoded
|
||||
|
||||
tAddressLabel.text = uAddress.transparentReceiver()?.stringEncoded ?? "could not extract transparent receiver from UA"
|
||||
saplingAddress.text = uAddress.saplingReceiver()?.stringEncoded ?? "could not extract sapling receiver from UA"
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
// swiftlint:disable:next line_length
|
||||
unifiedAddressLabel.text = (try? derivationTool.deriveUnifiedAddress(seed: DemoAppConfig.seed, accountIndex: 0))?.stringEncoded ?? "No Addresses found"
|
||||
tAddressLabel.text = (try? derivationTool.deriveTransparentAddress(seed: DemoAppConfig.seed))?.stringEncoded ?? "could not derive t-address"
|
||||
spendingKeyLabel.text = self.spendingKey.stringEncoded
|
||||
unifiedAddressLabel.addGestureRecognizer(
|
||||
UITapGestureRecognizer(
|
||||
target: self,
|
||||
|
@ -44,23 +46,23 @@ class GetAddressViewController: UIViewController {
|
|||
action: #selector(tAddressTapped(_:))
|
||||
)
|
||||
)
|
||||
spendingKeyLabel.addGestureRecognizer(
|
||||
saplingAddress.addGestureRecognizer(
|
||||
UITapGestureRecognizer(
|
||||
target: self,
|
||||
action: #selector(spendingKeyTapped(_:))
|
||||
)
|
||||
)
|
||||
spendingKeyLabel.isUserInteractionEnabled = true
|
||||
loggerProxy.info("Address: \(String(describing: Initializer.shared.getAddress()))")
|
||||
saplingAddress.isUserInteractionEnabled = true
|
||||
loggerProxy.info("Address: \(String(describing: uAddress))")
|
||||
}
|
||||
|
||||
@IBAction func spendingKeyTapped(_ gesture: UIGestureRecognizer) {
|
||||
loggerProxy.event("copied to clipboard")
|
||||
|
||||
UIPasteboard.general.string = self.spendingKey.stringEncoded
|
||||
UIPasteboard.general.string = self.saplingAddress.text
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: "Spending Key Copied to clipboard",
|
||||
message: "Sapling Address Copied to clipboard",
|
||||
preferredStyle: UIAlertController.Style.alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||
|
@ -84,8 +86,8 @@ class GetAddressViewController: UIViewController {
|
|||
|
||||
@IBAction func tAddressTapped(_ gesture: UIGestureRecognizer) {
|
||||
loggerProxy.event("copied to clipboard")
|
||||
UIPasteboard.general.string = try? DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
.deriveTransparentAddress(seed: DemoAppConfig.seed).stringEncoded
|
||||
|
||||
UIPasteboard.general.string = tAddressLabel.text
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
|
|
|
@ -23,14 +23,13 @@ class GetUTXOsViewController: UIViewController {
|
|||
}
|
||||
|
||||
func updateUI() {
|
||||
// swiftlint:disable:next force_try
|
||||
let tAddress = try! DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
.deriveTransparentAddress(seed: DemoAppConfig.seed)
|
||||
let synchronizer = SDKSynchronizer.shared
|
||||
let tAddress = synchronizer.getTransparentAddress(accountIndex: 0)?.stringEncoded ?? "no t-address found"
|
||||
|
||||
self.transparentAddressLabel.text = tAddress.stringEncoded
|
||||
self.transparentAddressLabel.text = tAddress
|
||||
|
||||
// swiftlint:disable:next force_try
|
||||
let balance = try! AppDelegate.shared.sharedSynchronizer.getTransparentBalance(accountIndex: 0)
|
||||
let balance = try! synchronizer.getTransparentBalance(accountIndex: 0)
|
||||
|
||||
self.totalBalanceLabel.text = NumberFormatter.zcashNumberFormatter.string(from: NSNumber(value: balance.total.amount))
|
||||
self.verifiedBalanceLabel.text = NumberFormatter.zcashNumberFormatter.string(from: NSNumber(value: balance.verified.amount))
|
||||
|
@ -38,18 +37,16 @@ class GetUTXOsViewController: UIViewController {
|
|||
|
||||
@IBAction func shieldFunds(_ sender: Any) {
|
||||
do {
|
||||
let seed = DemoAppConfig.seed
|
||||
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
|
||||
let transparentSecretKey = try derivationTool.deriveTransparentAccountPrivateKey(seed: seed, account: 0)
|
||||
let usk = try derivationTool.deriveUnifiedSpendingKey(seed: DemoAppConfig.seed, accountIndex: 0)
|
||||
|
||||
KRProgressHUD.showMessage("🛡 Shielding 🛡")
|
||||
|
||||
Task { @MainActor in
|
||||
let transaction = try await AppDelegate.shared.sharedSynchronizer.shieldFunds(
|
||||
transparentAccountPrivateKey: transparentSecretKey,
|
||||
memo: "shielding is fun!",
|
||||
from: 0
|
||||
memo: try Memo(string: "shielding is fun!")
|
||||
)
|
||||
KRProgressHUD.dismiss()
|
||||
self.messageLabel.text = "funds shielded \(transaction)"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import UIKit
|
||||
import ZcashLightClientKit
|
||||
import KRProgressHUD
|
||||
|
||||
class SendViewController: UIViewController {
|
||||
@IBOutlet weak var addressLabel: UILabel!
|
||||
@IBOutlet weak var amountLabel: UILabel!
|
||||
|
@ -213,8 +214,15 @@ class SendViewController: UIViewController {
|
|||
loggerProxy.warn("WARNING: Form is invalid")
|
||||
return
|
||||
}
|
||||
// swiftlint:disable:next line_length force_try
|
||||
guard let spendingKey = try! DerivationTool(networkType: kZcashNetwork.networkType).deriveSpendingKeys(seed: DemoAppConfig.seed, numberOfAccounts: 1).first else {
|
||||
|
||||
guard let spendingKey = try? DerivationTool(
|
||||
networkType: kZcashNetwork.networkType
|
||||
)
|
||||
.deriveUnifiedSpendingKey(
|
||||
seed: DemoAppConfig.seed,
|
||||
accountIndex: 0
|
||||
)
|
||||
else {
|
||||
loggerProxy.error("NO SPENDING KEY")
|
||||
return
|
||||
}
|
||||
|
@ -226,9 +234,9 @@ class SendViewController: UIViewController {
|
|||
let pendingTransaction = try await synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: zec,
|
||||
toAddress: recipient,
|
||||
memo: !self.memoField.text.isEmpty ? self.memoField.text : nil,
|
||||
from: 0
|
||||
// swiftlint:disable:next force_try
|
||||
toAddress: try! Recipient(recipient, network: kZcashNetwork.networkType),
|
||||
memo: try! self.memoField.text.asMemo()
|
||||
)
|
||||
KRProgressHUD.dismiss()
|
||||
loggerProxy.info("transaction created: \(pendingTransaction)")
|
||||
|
@ -364,3 +372,14 @@ extension SDKSynchronizer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional where Wrapped == String {
|
||||
func asMemo() throws -> Memo {
|
||||
switch self {
|
||||
case .some(let string):
|
||||
return try Memo(string: string)
|
||||
case .none:
|
||||
return .empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
186
Package.resolved
186
Package.resolved
|
@ -1,97 +1,95 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "grpc-swift",
|
||||
"repositoryURL": "https://github.com/grpc/grpc-swift.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "4c63368b7462305903507e8acebd77264c0fb695",
|
||||
"version": "1.8.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SQLite.swift",
|
||||
"repositoryURL": "https://github.com/stephencelis/SQLite.swift.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "4d543d811ee644fa4cc4bfa0be996b4dd6ba0f54",
|
||||
"version": "0.13.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-log",
|
||||
"repositoryURL": "https://github.com/apple/swift-log.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
|
||||
"version": "1.4.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "124119f0bb12384cef35aa041d7c3a686108722d",
|
||||
"version": "2.40.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-extras",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-extras.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "a75e92bde3683241c15df3dd905b7a6dcac4d551",
|
||||
"version": "1.12.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-http2",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-http2.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "108ac15087ea9b79abb6f6742699cf31de0e8772",
|
||||
"version": "1.22.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-ssl",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "42436a25ff32c390465567f5c089a9a8ce8d7baf",
|
||||
"version": "2.20.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-transport-services",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-transport-services.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "2cb54f91ddafc90832c5fa247faf5798d0a7c204",
|
||||
"version": "1.13.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftProtobuf",
|
||||
"repositoryURL": "https://github.com/apple/swift-protobuf.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "e1499bc69b9040b29184f7f2996f7bab467c1639",
|
||||
"version": "1.19.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "libzcashlc",
|
||||
"repositoryURL": "https://github.com/zcash-hackworks/zcash-light-client-ffi",
|
||||
"state": {
|
||||
"branch": "bin/librustzcash_0_7",
|
||||
"revision": "fcf3d4b652b67d6a9b9bdc8e5565eb8dd4b46145",
|
||||
"version": null
|
||||
}
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "grpc-swift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/grpc/grpc-swift.git",
|
||||
"state" : {
|
||||
"revision" : "4c63368b7462305903507e8acebd77264c0fb695",
|
||||
"version" : "1.8.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"identity" : "sqlite.swift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/stephencelis/SQLite.swift.git",
|
||||
"state" : {
|
||||
"revision" : "4d543d811ee644fa4cc4bfa0be996b4dd6ba0f54",
|
||||
"version" : "0.13.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-log",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-log.git",
|
||||
"state" : {
|
||||
"revision" : "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
|
||||
"version" : "1.4.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio.git",
|
||||
"state" : {
|
||||
"revision" : "124119f0bb12384cef35aa041d7c3a686108722d",
|
||||
"version" : "2.40.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-extras",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-extras.git",
|
||||
"state" : {
|
||||
"revision" : "a75e92bde3683241c15df3dd905b7a6dcac4d551",
|
||||
"version" : "1.12.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-http2",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-http2.git",
|
||||
"state" : {
|
||||
"revision" : "108ac15087ea9b79abb6f6742699cf31de0e8772",
|
||||
"version" : "1.22.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-ssl",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-ssl.git",
|
||||
"state" : {
|
||||
"revision" : "42436a25ff32c390465567f5c089a9a8ce8d7baf",
|
||||
"version" : "2.20.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-transport-services",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-transport-services.git",
|
||||
"state" : {
|
||||
"revision" : "2cb54f91ddafc90832c5fa247faf5798d0a7c204",
|
||||
"version" : "1.13.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-protobuf",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||
"state" : {
|
||||
"revision" : "e1499bc69b9040b29184f7f2996f7bab467c1639",
|
||||
"version" : "1.19.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "zcash-light-client-ffi",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
|
||||
"state" : {
|
||||
"branch" : "bin/librustzcash_0_7",
|
||||
"revision" : "e8fbb84c1bec44af9dbef7e27c85f25e8f51a5af"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ let package = Package(
|
|||
dependencies: [
|
||||
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.8.0"),
|
||||
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.13.0"),
|
||||
.package(name:"libzcashlc", url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", branch: "bin/librustzcash_0_7"),
|
||||
.package(name:"libzcashlc", url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", branch: "bin/librustzcash_0_7")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
|
|
@ -212,7 +212,6 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
|||
throw CompactBlockDownloadError.generalError(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func rewind(to height: BlockHeight) throws {
|
||||
try self.storage.rewind(to: height)
|
||||
|
|
|
@ -41,11 +41,11 @@ extension CompactBlockProcessor {
|
|||
}
|
||||
|
||||
guard rustBackend.decryptAndStoreTransaction(dbData: config.dataDb, txBytes: rawBytes, minedHeight: Int32(minedHeight), networkType: config.network.networkType) else {
|
||||
if let rustError = rustBackend.lastError() {
|
||||
throw EnhancementError.decryptError(error: rustError)
|
||||
}
|
||||
throw EnhancementError.unknownError
|
||||
throw EnhancementError.decryptError(
|
||||
error: rustBackend.lastError() ?? .genericError(message: "`decryptAndStoreTransaction` failed. No message available")
|
||||
)
|
||||
}
|
||||
|
||||
guard let confirmedTx = try transactionRepository.findConfirmedTransactionBy(rawId: transaction.transactionId) else {
|
||||
throw EnhancementError.txIdNotFound(txId: transaction.transactionId)
|
||||
}
|
||||
|
|
|
@ -536,7 +536,6 @@ public class CompactBlockProcessor {
|
|||
Stops the CompactBlockProcessor
|
||||
|
||||
Note: retry count is reset
|
||||
- Parameter cancelTasks: cancel the pending tasks. Defaults to true
|
||||
*/
|
||||
public func stop() {
|
||||
self.backoffTimer?.invalidate()
|
||||
|
@ -557,7 +556,11 @@ public class CompactBlockProcessor {
|
|||
|
||||
let lastDownloaded = try downloader.lastDownloadedBlockHeight()
|
||||
let height = Int32(height ?? lastDownloaded)
|
||||
let nearestHeight = rustBackend.getNearestRewindHeight(dbData: config.dataDb, height: height, networkType: self.config.network.networkType)
|
||||
let nearestHeight = rustBackend.getNearestRewindHeight(
|
||||
dbData: config.dataDb,
|
||||
height: height,
|
||||
networkType: self.config.network.networkType
|
||||
)
|
||||
|
||||
guard nearestHeight > 0 else {
|
||||
let error = rustBackend.lastError() ?? RustWeldingError.genericError(
|
||||
|
@ -1013,52 +1016,51 @@ extension CompactBlockProcessor.State: Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
// Transparent stuff
|
||||
|
||||
extension CompactBlockProcessor {
|
||||
public func utxoCacheBalance(tAddress: String) throws -> WalletBalance {
|
||||
try rustBackend.downloadedUtxoBalance(dbData: config.dataDb, address: tAddress, networkType: config.network.networkType)
|
||||
}
|
||||
}
|
||||
|
||||
extension CompactBlockProcessor {
|
||||
public func getUnifiedAddres(accountIndex: Int) -> UnifiedAddress? {
|
||||
// TODO: perform migrations on the account table to accommodate Unified Address or UFVK to to derive from.
|
||||
guard let address = try? accountRepository.findBy(account: accountIndex)?.address else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return try? UnifiedAddress(encoding: address, network: self.config.network.networkType)
|
||||
public func getUnifiedAddress(accountIndex: Int) -> UnifiedAddress? {
|
||||
try? rustBackend.getCurrentAddress(
|
||||
dbData: config.dataDb,
|
||||
account: Int32(accountIndex),
|
||||
networkType: config.network.networkType
|
||||
)
|
||||
}
|
||||
|
||||
public func getSaplingAddress(accountIndex: Int) -> SaplingAddress? {
|
||||
guard let zAddress = try? accountRepository.findBy(account: accountIndex)?.address else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return try? SaplingAddress(encoding: zAddress, network: self.config.network.networkType)
|
||||
getUnifiedAddress(accountIndex: accountIndex)?.saplingReceiver()
|
||||
}
|
||||
|
||||
public func getTransparentAddress(accountIndex: Int) -> TransparentAddress? {
|
||||
guard let tAddress = try? accountRepository.findBy(account: accountIndex)?.transparentAddress else { return nil }
|
||||
|
||||
return TransparentAddress(validatedEncoding: tAddress)
|
||||
|
||||
getUnifiedAddress(accountIndex: accountIndex)?.transparentReceiver()
|
||||
}
|
||||
|
||||
public func getTransparentBalance(accountIndex: Int) throws -> WalletBalance {
|
||||
guard let tAddress = try? accountRepository.findBy(account: accountIndex)?.transparentAddress else {
|
||||
guard accountIndex >= 0 else {
|
||||
throw CompactBlockProcessorError.invalidAccount
|
||||
}
|
||||
return try utxoCacheBalance(tAddress: tAddress)
|
||||
|
||||
return WalletBalance(
|
||||
verified: Zatoshi(
|
||||
try rustBackend.getVerifiedTransparentBalance(
|
||||
dbData: config.dataDb,
|
||||
account: Int32(accountIndex),
|
||||
networkType: config.network.networkType)
|
||||
),
|
||||
total: Zatoshi(
|
||||
try rustBackend.getTransparentBalance(
|
||||
dbData: config.dataDb,
|
||||
account: Int32(accountIndex),
|
||||
networkType: config.network.networkType
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension CompactBlockProcessor {
|
||||
func refreshUTXOs(tAddress: String, startHeight: BlockHeight) async throws -> RefreshedUTXOs {
|
||||
func refreshUTXOs(tAddress: TransparentAddress, startHeight: BlockHeight) async throws -> RefreshedUTXOs {
|
||||
let dataDb = self.config.dataDb
|
||||
|
||||
let stream: AsyncThrowingStream<UnspentTransactionOutputEntity, Error> = downloader.fetchUnspentTransactionOutputs(tAddress: tAddress, startHeight: startHeight)
|
||||
let stream: AsyncThrowingStream<UnspentTransactionOutputEntity, Error> = downloader.fetchUnspentTransactionOutputs(tAddress: tAddress.stringEncoded, startHeight: startHeight)
|
||||
var utxos: [UnspentTransactionOutputEntity] = []
|
||||
|
||||
do {
|
||||
|
|
|
@ -17,9 +17,19 @@ extension CompactBlockProcessor {
|
|||
try Task.checkCancellation()
|
||||
|
||||
setState(.fetching)
|
||||
|
||||
|
||||
do {
|
||||
let tAddresses = try accountRepository.getAll().map({ $0.transparentAddress })
|
||||
let tAddresses = try accountRepository.getAll()
|
||||
.map { $0.account }
|
||||
.map {
|
||||
try rustBackend.listTransparentReceivers(
|
||||
dbData: config.dataDb,
|
||||
account: Int32($0),
|
||||
networkType: config.network.networkType
|
||||
)
|
||||
}
|
||||
.flatMap({ $0 })
|
||||
|
||||
do {
|
||||
for tAddress in tAddresses {
|
||||
guard try rustBackend.clearUtxos(
|
||||
|
@ -28,19 +38,19 @@ extension CompactBlockProcessor {
|
|||
sinceHeight: config.walletBirthday - 1,
|
||||
networkType: config.network.networkType
|
||||
) >= 0 else {
|
||||
throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "attempted to clear utxos but -1 was returned")
|
||||
throw rustBackend.lastError() ?? .genericError(message: "clearUtxos failed. no error message available")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
throw FetchUTXOError.clearingFailed(error)
|
||||
}
|
||||
|
||||
|
||||
var utxos: [UnspentTransactionOutputEntity] = []
|
||||
let stream: AsyncThrowingStream<UnspentTransactionOutputEntity, Error> = downloader.fetchUnspentTransactionOutputs(tAddresses: tAddresses, startHeight: config.walletBirthday)
|
||||
let stream: AsyncThrowingStream<UnspentTransactionOutputEntity, Error> = downloader.fetchUnspentTransactionOutputs(tAddresses: tAddresses.map { $0.stringEncoded }, startHeight: config.walletBirthday)
|
||||
for try await transaction in stream {
|
||||
utxos.append(transaction)
|
||||
}
|
||||
|
||||
|
||||
var refreshed: [UnspentTransactionOutputEntity] = []
|
||||
var skipped: [UnspentTransactionOutputEntity] = []
|
||||
|
||||
|
@ -62,13 +72,13 @@ extension CompactBlockProcessor {
|
|||
}
|
||||
|
||||
let result = (inserted: refreshed, skipped: skipped)
|
||||
|
||||
|
||||
NotificationCenter.default.post(
|
||||
name: .blockProcessorStoredUTXOs,
|
||||
object: self,
|
||||
userInfo: [CompactBlockProcessorNotificationKey.refreshedUTXOs: result]
|
||||
)
|
||||
|
||||
|
||||
if Task.isCancelled {
|
||||
LoggerProxy.debug("Warning: fetchUnspentTxOutputs on range \(range) cancelled")
|
||||
} else {
|
||||
|
|
|
@ -10,41 +10,28 @@ import Foundation
|
|||
protocol AccountEntity {
|
||||
var account: Int { get set }
|
||||
var ufvk: String { get set }
|
||||
var address: String { get set }
|
||||
var transparentAddress: String { get set }
|
||||
}
|
||||
|
||||
struct Account: AccountEntity, Encodable, Decodable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case account
|
||||
case ufvk
|
||||
case address
|
||||
case transparentAddress = "transparent_address"
|
||||
}
|
||||
|
||||
var account: Int
|
||||
|
||||
var ufvk: String
|
||||
|
||||
var address: String
|
||||
|
||||
var transparentAddress: String
|
||||
}
|
||||
|
||||
extension Account: Hashable {
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(account)
|
||||
hasher.combine(ufvk)
|
||||
hasher.combine(address)
|
||||
hasher.combine(transparentAddress)
|
||||
}
|
||||
|
||||
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
guard
|
||||
lhs.account == rhs.account,
|
||||
lhs.ufvk == rhs.ufvk,
|
||||
lhs.address == rhs.address,
|
||||
lhs.transparentAddress == rhs.transparentAddress
|
||||
lhs.ufvk == rhs.ufvk
|
||||
else { return false }
|
||||
|
||||
return true
|
||||
|
@ -54,7 +41,6 @@ extension Account: Hashable {
|
|||
protocol AccountRepository {
|
||||
func getAll() throws -> [AccountEntity]
|
||||
func findBy(account: Int) throws -> AccountEntity?
|
||||
func findBy(address: String) throws -> AccountEntity?
|
||||
func update(_ account: AccountEntity) throws
|
||||
}
|
||||
|
||||
|
@ -63,9 +49,7 @@ import SQLite
|
|||
class AccountSQDAO: AccountRepository {
|
||||
enum TableColums {
|
||||
static let account = Expression<Int>("account")
|
||||
static let extfvk = Expression<String>("extfvk")
|
||||
static let address = Expression<String>("address")
|
||||
static let transparentAddress = Expression<String>("transparent_address")
|
||||
static let extfvk = Expression<String>("ufvk")
|
||||
}
|
||||
|
||||
let table = Table("accounts")
|
||||
|
@ -89,11 +73,6 @@ class AccountSQDAO: AccountRepository {
|
|||
return try dbProvider.connection().prepare(query).map({ try $0.decode() as Account }).first
|
||||
}
|
||||
|
||||
func findBy(address: String) throws -> AccountEntity? {
|
||||
let query = table.filter(TableColums.address == address).limit(1)
|
||||
return try dbProvider.connection().prepare(query).map({ try $0.decode() as Account }).first
|
||||
}
|
||||
|
||||
func update(_ account: AccountEntity) throws {
|
||||
guard let acc = account as? Account else {
|
||||
throw StorageError.updateFailed
|
||||
|
@ -149,21 +128,7 @@ class CachingAccountDao: AccountRepository {
|
|||
|
||||
return acc
|
||||
}
|
||||
|
||||
func findBy(address: String) throws -> AccountEntity? {
|
||||
if !cache.isEmpty, let account = cache.values.first(where: { $0.address == address }) {
|
||||
return account
|
||||
}
|
||||
|
||||
guard let account = try dao.findBy(address: address) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
cache[account.account] = account
|
||||
|
||||
return account
|
||||
}
|
||||
|
||||
func update(_ account: AccountEntity) throws {
|
||||
try dao.update(account)
|
||||
}
|
||||
|
|
|
@ -179,21 +179,20 @@ public class Initializer {
|
|||
self.walletBirthday = walletBirthday
|
||||
self.network = network
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize the wallet with the given seed and return the related private keys for each
|
||||
account specified or null if the wallet was previously initialized and block data exists on
|
||||
disk. When this method returns null, that signals that the wallet will need to retrieve the
|
||||
private keys from its own secure storage. In other words, the private keys are only given out
|
||||
once for each set of database files. Subsequent calls to [initialize] will only load the Rust
|
||||
library and return null.
|
||||
|
||||
'compactBlockCache.db' and 'transactionData.db' files are created by this function (if they
|
||||
do not already exist). These files can be given a prefix for scenarios where multiple wallets
|
||||
|
||||
- Parameters:
|
||||
- viewingKeys: Extended Full Viewing Keys to initialize the DBs with
|
||||
*/
|
||||
/// Initialize the wallet. The ZIP-32 seed bytes can optionally be passed to perform
|
||||
/// database migrations. most of the times the seed won't be needed. If they do and are
|
||||
/// not provided this will fail with `InitializationResult.seedRequired`. It could
|
||||
/// be the case that this method is invoked by a wallet that does not contain the seed phrase
|
||||
/// and is view-only, or by a wallet that does have the seed but the process does not have the
|
||||
/// consent of the OS to fetch the keys from the secure storage, like on background tasks.
|
||||
///
|
||||
/// 'cache.db' and 'data.db' files are created by this function (if they
|
||||
/// do not already exist). These files can be given a prefix for scenarios where multiple wallets
|
||||
///
|
||||
/// - Parameter seed: ZIP-32 Seed bytes for the wallet that will be initialized
|
||||
/// - Throws: `InitializerError.dataDbInitFailed` if the creation of the dataDb fails
|
||||
/// `InitializerError.accountInitFailed` if the account table can't be initialized.
|
||||
public func initialize(with seed: [UInt8]?) throws -> InitializationResult {
|
||||
do {
|
||||
try storage.createTable()
|
||||
|
@ -245,26 +244,9 @@ public class Initializer {
|
|||
} catch {
|
||||
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
||||
}
|
||||
|
||||
let migrationManager = MigrationManager(
|
||||
cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
|
||||
pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path),
|
||||
networkType: self.network.networkType
|
||||
)
|
||||
|
||||
try migrationManager.performMigration(ufvks: viewingKeys)
|
||||
|
||||
return .success
|
||||
}
|
||||
|
||||
/**
|
||||
get address from the given account index
|
||||
- Parameter account: the index of the account
|
||||
*/
|
||||
public func getAddress(index account: Int = 0) -> String? {
|
||||
try? accountRepository.findBy(account: account)?.address
|
||||
}
|
||||
|
||||
|
||||
/// get (unverified) balance from the given account index
|
||||
/// - Parameter account: the index of the account
|
||||
|
|
|
@ -14,6 +14,12 @@ public protocol StringEncoded {
|
|||
var stringEncoded: String { get }
|
||||
}
|
||||
|
||||
public struct UnifiedSpendingKey: Equatable, Undescribable {
|
||||
private(set) var network: NetworkType
|
||||
var bytes: [UInt8]
|
||||
public private(set) var account: UInt32
|
||||
}
|
||||
|
||||
/// Sapling Extended Spending Key
|
||||
public struct SaplingExtendedSpendingKey: Equatable, StringEncoded, Undescribable {
|
||||
var encoding: String
|
||||
|
@ -165,7 +171,6 @@ public struct UnifiedAddress: Equatable, StringEncoded {
|
|||
}
|
||||
}
|
||||
|
||||
var network: NetworkType
|
||||
var encoding: String
|
||||
|
||||
public var stringEncoded: String { encoding }
|
||||
|
@ -181,7 +186,6 @@ public struct UnifiedAddress: Equatable, StringEncoded {
|
|||
throw KeyEncodingError.invalidEncoding
|
||||
}
|
||||
|
||||
self.network = network
|
||||
self.encoding = encoding
|
||||
}
|
||||
|
||||
|
@ -190,7 +194,7 @@ public struct UnifiedAddress: Equatable, StringEncoded {
|
|||
/// couldn't be extracted
|
||||
public func availableReceiverTypecodes() throws -> [UnifiedAddress.ReceiverTypecodes] {
|
||||
do {
|
||||
return try DerivationTool(networkType: network).receiverTypecodesFromUnifiedAddress(self)
|
||||
return try DerivationTool.receiverTypecodesFromUnifiedAddress(self)
|
||||
} catch {
|
||||
throw Errors.couldNotExtractTypecodes
|
||||
}
|
||||
|
@ -232,7 +236,6 @@ public enum Recipient: Equatable, StringEncoded {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public struct WalletBalance: Equatable {
|
||||
public var verified: Zatoshi
|
||||
public var total: Zatoshi
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,100 +16,318 @@ enum RustWeldingError: Error {
|
|||
case malformedStringInput
|
||||
case noConsensusBranchId(height: Int32)
|
||||
case unableToDeriveKeys
|
||||
case invalidInput(message: String)
|
||||
case invalidRewind(suggestedHeight: Int32)
|
||||
}
|
||||
|
||||
enum ZcashRustBackendWeldingConstants {
|
||||
static let validChain: Int32 = -1
|
||||
}
|
||||
|
||||
/**
|
||||
Enumeration of potential return states for database initialization. If `seedRequired` is returned, the caller must
|
||||
re-attempt initialization providing the seed
|
||||
*/
|
||||
/// Enumeration of potential return states for database initialization. If `seedRequired`
|
||||
/// is returned, the caller must re-attempt initialization providing the seed
|
||||
public enum DbInitResult {
|
||||
case success
|
||||
case seedRequired
|
||||
}
|
||||
|
||||
protocol ZcashRustBackendWelding {
|
||||
/**
|
||||
gets the latest error if available. Clear the existing error
|
||||
*/
|
||||
/// clears the cached utxos for the given address from the specified height on for the
|
||||
/// provided addresses. This will clear all UTXOs for the address from the database.
|
||||
/// if there are unspent funds, the balance will be zero after clearing up UTXOs,
|
||||
/// needing to put them back again to restore the balance (if they weren't spent)
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - address: the address of the UTXO
|
||||
/// - sinceheight: clear the UXTOs from that address on
|
||||
/// - networkType: network type of this key
|
||||
/// - Returns: the amount of UTXOs cleared or -1 on error
|
||||
static func clearUtxos(
|
||||
dbData: URL,
|
||||
address: TransparentAddress,
|
||||
sinceHeight: BlockHeight,
|
||||
networkType: NetworkType
|
||||
) throws -> Int32
|
||||
|
||||
/// Adds the next available account-level spend authority, given the current set of [ZIP 316]
|
||||
/// account identifiers known, to the wallet database.
|
||||
///
|
||||
/// Returns the newly created [ZIP 316] account identifier, along with the binary encoding of the
|
||||
/// [`UnifiedSpendingKey`] for the newly created account. The caller should manage the memory of
|
||||
/// (and store) the returned spending keys in a secure fashion.
|
||||
///
|
||||
/// If `seed` was imported from a backup and this method is being used to restore a
|
||||
/// previous wallet state, you should use this method to add all of the desired
|
||||
/// accounts before scanning the chain from the seed's birthday height.
|
||||
///
|
||||
/// By convention, wallets should only allow a new account to be generated after funds
|
||||
/// have been received by the currently-available account (in order to enable
|
||||
/// automated account recovery).
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - seed: byte array of the zip32 seed
|
||||
/// - networkType: network type of this key
|
||||
/// - Returns: The `UnifiedSpendingKey` structs for the number of accounts created
|
||||
///
|
||||
static func createAccount(
|
||||
dbData: URL,
|
||||
seed: [UInt8],
|
||||
networkType: NetworkType
|
||||
) throws -> UnifiedSpendingKey
|
||||
|
||||
/// Creates a transaction to the given address from the given account
|
||||
/// - Parameter dbData: URL for the Data DB
|
||||
/// - Parameter usk: `UnifiedSpendingKey` for the account that controls the funds to be spent.
|
||||
/// - Parameter to: recipient address
|
||||
/// - Parameter value: transaction amount in Zatoshi
|
||||
/// - Parameter memo: the `Memo` for this transaction
|
||||
/// - Parameter spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
||||
/// - Parameter outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
||||
/// - Parameter networkType: network type of this key
|
||||
static func createToAddress(
|
||||
dbData: URL,
|
||||
usk: UnifiedSpendingKey,
|
||||
to address: String,
|
||||
value: Int64,
|
||||
memo: MemoBytes,
|
||||
spendParamsPath: String,
|
||||
outputParamsPath: String,
|
||||
networkType: NetworkType
|
||||
) -> Int64 // swiftlint:disable function_parameter_count
|
||||
|
||||
/// Scans a transaction for any information that can be decrypted by the accounts in the
|
||||
/// wallet, and saves it to the wallet.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - tx: the transaction to decrypt
|
||||
/// - minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID.
|
||||
/// - networkType: network type of this key
|
||||
/// returns false if fails to decrypt.
|
||||
static func decryptAndStoreTransaction(
|
||||
dbData: URL,
|
||||
txBytes: [UInt8],
|
||||
minedHeight: Int32,
|
||||
networkType: NetworkType
|
||||
) -> Bool
|
||||
|
||||
/// Derives and returns a unified spending key from the given seed for the given account ID.
|
||||
/// Returns the binary encoding of the spending key. The caller should manage the memory of (and store, if necessary) the returned spending key in a secure fashion.
|
||||
/// - Parameter seed: a Byte Array with the seed
|
||||
/// - Parameter accountIndex:account index that the key can spend from
|
||||
/// - Parameter networkType: network type of this key
|
||||
/// - Throws `.unableToDerive` when there's an error
|
||||
static func deriveUnifiedSpendingKey(
|
||||
from seed: [UInt8],
|
||||
accountIndex: Int32,
|
||||
networkType: NetworkType
|
||||
) throws -> UnifiedSpendingKey
|
||||
|
||||
/// get the (unverified) balance from the given account
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - account: index of the given account
|
||||
/// - networkType: network type of this key
|
||||
static func getBalance(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
networkType: NetworkType
|
||||
) -> Int64
|
||||
|
||||
/// Returns the most-recently-generated unified payment address for the specified account.
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - account: index of the given account
|
||||
/// - networkType: network type of this key
|
||||
static func getCurrentAddress(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
networkType: NetworkType
|
||||
) throws -> UnifiedAddress
|
||||
|
||||
/// Wallets might need to be rewound because of a reorg, or by user request.
|
||||
/// There are times where the wallet could get out of sync for many reasons and
|
||||
/// users might be asked to rescan their wallets in order to fix that. This function
|
||||
/// returns the nearest height where a rewind is possible. Currently pruning gets rid
|
||||
/// of sapling witnesses older than 100 blocks. So in order to reconstruct the witness
|
||||
/// tree that allows to spend notes from the given wallet the rewind can't be more than
|
||||
/// 100 blocks or back to the oldest unspent note that this wallet contains.
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - height: height you would like to rewind to.
|
||||
/// - networkType: network type of this key]
|
||||
/// - Returns: the blockheight of the nearest rewind height.
|
||||
///
|
||||
static func getNearestRewindHeight(
|
||||
dbData: URL,
|
||||
height: Int32,
|
||||
networkType: NetworkType
|
||||
) -> Int32
|
||||
|
||||
/// Returns a newly-generated unified payment address for the specified account, with the next available diversifier.
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - account: index of the given account
|
||||
/// - networkType: network type of this key
|
||||
static func getNextAvailableAddress(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
networkType: NetworkType
|
||||
) throws -> UnifiedAddress
|
||||
|
||||
/// get received memo from note
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - idNote: note_id of note where the memo is located
|
||||
/// - networkType: network type of this key
|
||||
@available(*, deprecated, message: "This function will be deprecated soon. Use `getReceivedMemo(dbData:idNote:networkType)` instead")
|
||||
static func getReceivedMemoAsUTF8(
|
||||
dbData: URL,
|
||||
idNote: Int64,
|
||||
networkType: NetworkType
|
||||
) -> String?
|
||||
|
||||
|
||||
/// get received memo from note
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - idNote: note_id of note where the memo is located
|
||||
/// - networkType: network type of this key
|
||||
static func getReceivedMemo(
|
||||
dbData: URL,
|
||||
idNote: Int64,
|
||||
networkType: NetworkType
|
||||
) -> Memo?
|
||||
|
||||
/// Returns the Sapling receiver within the given Unified Address, if any.
|
||||
/// - Parameter uAddr: a `UnifiedAddress`
|
||||
/// - Returns a `SaplingAddress` if any
|
||||
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
||||
static func getSaplingReceiver(for uAddr: UnifiedAddress) throws -> SaplingAddress?
|
||||
|
||||
/// get sent memo from note
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - idNote: note_id of note where the memo is located
|
||||
/// - networkType: network type of this key
|
||||
@available(*, deprecated, message: "This function will be deprecated soon. Use `getSentMemo(dbData:idNote:networkType)` instead")
|
||||
static func getSentMemoAsUTF8(
|
||||
dbData: URL,
|
||||
idNote: Int64,
|
||||
networkType: NetworkType
|
||||
) -> String?
|
||||
|
||||
/// get sent memo from note
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - idNote: note_id of note where the memo is located
|
||||
/// - networkType: network type of this key
|
||||
/// - Returns: a `Memo` if any
|
||||
static func getSentMemo(
|
||||
dbData: URL,
|
||||
idNote: Int64,
|
||||
networkType: NetworkType
|
||||
) -> Memo?
|
||||
|
||||
/// Get the verified cached transparent balance for the given address
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - account; the account index to query
|
||||
/// - networkType: network type of this key
|
||||
static func getTransparentBalance(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
networkType: NetworkType
|
||||
) throws -> Int64
|
||||
|
||||
/// Returns the transparent receiver within the given Unified Address, if any.
|
||||
// - Parameter uAddr: a `UnifiedAddress`
|
||||
/// - Returns a `TransparentAddress` if any
|
||||
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
||||
static func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress?
|
||||
|
||||
/// gets the latest error if available. Clear the existing error
|
||||
/// - Returns a `RustWeldingError` if exists
|
||||
static func lastError() -> RustWeldingError?
|
||||
|
||||
/**
|
||||
gets the latest error message from librustzcash. Does not clear existing error
|
||||
*/
|
||||
/// gets the latest error message from librustzcash. Does not clear existing error
|
||||
static func getLastError() -> String?
|
||||
|
||||
/**
|
||||
initializes the data db
|
||||
- Parameter dbData: location of the data db sql file
|
||||
*/
|
||||
static func initDataDb(dbData: URL, seed: [UInt8]?, networkType: NetworkType) throws -> DbInitResult
|
||||
|
||||
/**
|
||||
- Returns: true when the address is valid. Returns false in any other case
|
||||
- Throws: Error when the provided address belongs to another network
|
||||
*/
|
||||
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) throws -> Bool
|
||||
|
||||
/**
|
||||
- Returns: true when the address is valid and transparent. false in any other case
|
||||
- Throws: Error when the provided address belongs to another network
|
||||
*/
|
||||
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) throws -> Bool
|
||||
/// initialize the accounts table from a set of unified full viewing keys
|
||||
/// - Note: this function should only be used when restoring an existing seed phrase.
|
||||
/// when creating a new wallet, use `createAccount()` instead
|
||||
/// - Parameter dbData: location of the data db
|
||||
/// - Parameter ufvks: an array of UnifiedFullViewingKeys
|
||||
/// - Parameter networkType: network type of this key
|
||||
static func initAccountsTable(
|
||||
dbData: URL,
|
||||
ufvks: [UnifiedFullViewingKey],
|
||||
networkType: NetworkType
|
||||
) throws -> Bool
|
||||
|
||||
/// validates whether a string encoded address is a valid Unified Address.
|
||||
/// - Returns: true when the address is valid and transparent. false in any other case
|
||||
/// initializes the data db. This will performs any migrations needed on the sqlite file
|
||||
/// provided. Some migrations might need that callers provide the seed bytes.
|
||||
/// - Parameter dbData: location of the data db sql file
|
||||
/// - Parameter seed: ZIP-32 compliant seed bytes for this wallet
|
||||
/// - Parameter networkType: network type of this key
|
||||
/// - Returns: `DbInitResult.success` if the dataDb was initialized successfully
|
||||
/// or `DbInitResult.seedRequired` if the operation requires the seed to be passed
|
||||
/// in order to be completed successfully.
|
||||
static func initDataDb(
|
||||
dbData: URL,
|
||||
seed: [UInt8]?,
|
||||
networkType: NetworkType
|
||||
) throws -> DbInitResult
|
||||
|
||||
/// Validates the if the given string is a valid Sapling Address
|
||||
/// - Parameter address: UTF-8 encoded String to validate
|
||||
/// - Parameter networkType: network type of this key
|
||||
/// - Returns: true when the address is valid. Returns false in any other case
|
||||
/// - Throws: Error when the provided address belongs to another network
|
||||
static func isValidUnifiedAddress(_ address: String, networkType: NetworkType) throws -> Bool
|
||||
|
||||
/**
|
||||
- Returns: `true` when the Sapling Extended Full Viewing Key is valid. `false` in any other case
|
||||
- Throws: Error when there's another problem not related to validity of the string in question
|
||||
*/
|
||||
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) throws -> Bool
|
||||
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) -> Bool
|
||||
|
||||
/// Validates the if the given string is a valid Sapling Extended Full Viewing Key
|
||||
/// - Parameter key: UTF-8 encoded String to validate
|
||||
/// - Parameter networkType: network type of this key
|
||||
/// - Returns: `true` when the Sapling Extended Full Viewing Key is valid. `false` in any other case
|
||||
/// - Throws: Error when there's another problem not related to validity of the string in question
|
||||
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) -> Bool
|
||||
|
||||
/// Validates the if the given string is a valid Sapling Extended Spending Key
|
||||
/// - Returns: `true` when the Sapling Extended Spending Key is valid, false in any other case.
|
||||
/// - Throws: Error when the key is semantically valid but it belongs to another network
|
||||
/// - parameter key: String encoded Extendeed Spending Key
|
||||
/// - parameter networkType: `NetworkType` signaling testnet or mainnet
|
||||
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: NetworkType) throws -> Bool
|
||||
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: NetworkType) -> Bool
|
||||
|
||||
/**
|
||||
- Returns: true when the encoded string is a valid UFVK. false in any other case
|
||||
- Throws: Error when there's another problem not related to validity of the string in question
|
||||
*/
|
||||
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) throws -> Bool
|
||||
/// Validates the if the given string is a valid Transparent Address
|
||||
/// - Parameter address: UTF-8 encoded String to validate
|
||||
/// - Parameter networkType: network type of this key
|
||||
/// - Returns: true when the address is valid and transparent. false in any other case
|
||||
/// - Throws: Error when the provided address belongs to another network
|
||||
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) -> Bool
|
||||
|
||||
/**
|
||||
initialize the accounts table from a given seed and a number of accounts
|
||||
- Parameters:
|
||||
- dbData: location of the data db
|
||||
- seed: byte array of the zip32 seed
|
||||
- accounts: how many accounts you want to have
|
||||
*/
|
||||
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32, networkType: NetworkType) -> [SaplingExtendedSpendingKey]?
|
||||
|
||||
/**
|
||||
initialize the accounts table from a set of unified full viewing keys
|
||||
- Parameters:
|
||||
- dbData: location of the data db
|
||||
- ufvks: an array of UnifiedFullViewingKeys
|
||||
*/
|
||||
static func initAccountsTable(dbData: URL, ufvks: [UnifiedFullViewingKey], networkType: NetworkType) throws -> Bool
|
||||
/// validates whether a string encoded address is a valid Unified Address.
|
||||
/// - Parameter address: UTF-8 encoded String to validate
|
||||
/// - Parameter networkType: network type of this key
|
||||
/// - Returns: true when the address is valid and transparent. false in any other case
|
||||
/// - Throws: Error when the provided address belongs to another network
|
||||
static func isValidUnifiedAddress(_ address: String, networkType: NetworkType) -> Bool
|
||||
|
||||
/**
|
||||
initialize the blocks table from a given checkpoint (birthday)
|
||||
- Parameters:
|
||||
- dbData: location of the data db
|
||||
- height: represents the block height of the given checkpoint
|
||||
- hash: hash of the merkle tree
|
||||
- time: in milliseconds from reference
|
||||
- saplingTree: hash of the sapling tree
|
||||
*/
|
||||
// swiftlint:disable function_parameter_count
|
||||
/// verifies that the given string-encoded `UnifiedFullViewingKey` is valid.
|
||||
/// - Parameter ufvk: UTF-8 encoded String to validate
|
||||
/// - Parameter networkType: network type of this key
|
||||
/// - Returns: true when the encoded string is a valid UFVK. false in any other case
|
||||
/// - Throws: Error when there's another problem not related to validity of the string in question
|
||||
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) -> Bool
|
||||
|
||||
/// initialize the blocks table from a given checkpoint (heigh, hash, time, saplingTree and networkType)
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - height: represents the block height of the given checkpoint
|
||||
/// - hash: hash of the merkle tree
|
||||
/// - time: in milliseconds from reference
|
||||
/// - saplingTree: hash of the sapling tree
|
||||
/// - networkType: `NetworkType` signaling testnet or mainnet
|
||||
static func initBlocksTable(
|
||||
dbData: URL,
|
||||
height: Int32,
|
||||
|
@ -117,142 +335,113 @@ protocol ZcashRustBackendWelding {
|
|||
time: UInt32,
|
||||
saplingTree: String,
|
||||
networkType: NetworkType
|
||||
) throws
|
||||
) throws // swiftlint:disable function_parameter_count
|
||||
|
||||
/**
|
||||
gets the address from data db from the given account
|
||||
- Parameters:
|
||||
- dbData: location of the data db
|
||||
- account: index of the given account
|
||||
- Returns: an optional string with the address if found
|
||||
*/
|
||||
static func getAddress(dbData: URL, account: Int32, networkType: NetworkType) -> String?
|
||||
/// Returns a list of the transparent receivers for the diversified unified addresses that have
|
||||
/// been allocated for the provided account.
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - account: index of the given account
|
||||
/// - networkType: the network type
|
||||
static func listTransparentReceivers(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
networkType: NetworkType
|
||||
) throws -> [TransparentAddress]
|
||||
|
||||
/**
|
||||
get the (unverified) balance from the given account
|
||||
- Parameters:
|
||||
- dbData: location of the data db
|
||||
- account: index of the given account
|
||||
*/
|
||||
static func getBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64
|
||||
/// get the verified balance from the given account
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - account: index of the given account
|
||||
/// - networkType: the network type
|
||||
static func getVerifiedBalance(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
networkType: NetworkType
|
||||
) -> Int64
|
||||
|
||||
/**
|
||||
get the verified balance from the given account
|
||||
- Parameters:
|
||||
- dbData: location of the data db
|
||||
- account: index of the given account
|
||||
*/
|
||||
static func getVerifiedBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64
|
||||
|
||||
/// Get the verified cached transparent balance for the given account
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db
|
||||
/// - account: account index to query the balance for.
|
||||
/// - networkType: the network type
|
||||
static func getVerifiedTransparentBalance(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
networkType: NetworkType
|
||||
) throws -> Int64
|
||||
|
||||
/// Checks that the scanned blocks in the data database, when combined with the recent
|
||||
/// `CompactBlock`s in the cache database, form a valid chain.
|
||||
/// This function is built on the core assumption that the information provided in the
|
||||
/// cache database is more likely to be accurate than the previously-scanned information.
|
||||
/// This follows from the design (and trust) assumption that the `lightwalletd` server
|
||||
/// provides accurate block information as of the time it was requested.
|
||||
/// - Parameters:
|
||||
/// - dbCache: location of the cache db file
|
||||
/// - dbData: location of the data db file
|
||||
/// - networkType: the network type
|
||||
/// - Returns:
|
||||
/// - `-1` if the combined chain is valid.
|
||||
/// - `upper_bound` if the combined chain is invalid.
|
||||
/// - `upper_bound` is the height of the highest invalid block (on the assumption that the highest block in the cache database is correct).
|
||||
/// - `0` if there was an error during validation unrelated to chain validity.
|
||||
/// - Important: This function does not mutate either of the databases.
|
||||
static func validateCombinedChain(
|
||||
dbCache: URL,
|
||||
dbData: URL,
|
||||
networkType: NetworkType
|
||||
) -> Int32
|
||||
|
||||
/// Resets the state of the database to only contain block and transaction information up to the given height. clears up all derived data as well
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use getNearestRewindHeight when unsure
|
||||
/// - networkType: the network type
|
||||
static func rewindToHeight(
|
||||
dbData: URL,
|
||||
height: Int32,
|
||||
networkType: NetworkType
|
||||
) -> Bool
|
||||
|
||||
/**
|
||||
Get the verified cached transparent balance for the given address
|
||||
*/
|
||||
static func getVerifiedTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64
|
||||
|
||||
/**
|
||||
Get the verified cached transparent balance for the given address
|
||||
*/
|
||||
static func getTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64
|
||||
|
||||
/**
|
||||
get received memo from note
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- idNote: note_id of note where the memo is located
|
||||
*/
|
||||
@available(*, deprecated, message: "This function will be deprecated soon. Use `getReceivedMemo(dbData:idNote:networkType)` instead")
|
||||
static func getReceivedMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String?
|
||||
/// Scans new blocks added to the cache for any transactions received by the tracked
|
||||
/// accounts.
|
||||
/// This function pays attention only to cached blocks with heights greater than the
|
||||
/// highest scanned block in `db_data`. Cached blocks with lower heights are not verified
|
||||
/// against previously-scanned blocks. In particular, this function **assumes** that the
|
||||
/// caller is handling rollbacks.
|
||||
/// For brand-new light client databases, this function starts scanning from the Sapling
|
||||
/// activation height. This height can be fast-forwarded to a more recent block by calling
|
||||
/// [`initBlocksTable`] before this function.
|
||||
/// Scanned blocks are required to be height-sequential. If a block is missing from the
|
||||
/// cache, an error will be signalled.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - dbCache: location of the compact block cache db
|
||||
/// - dbData: location of the data db file
|
||||
/// - limit: scan up to limit blocks. pass 0 to set no limit.
|
||||
/// - networkType: the network type
|
||||
/// returns false if fails to scan.
|
||||
static func scanBlocks(
|
||||
dbCache: URL,
|
||||
dbData: URL,
|
||||
limit: UInt32,
|
||||
networkType: NetworkType
|
||||
) -> Bool
|
||||
|
||||
/**
|
||||
get received memo from note
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- idNote: note_id of note where the memo is located
|
||||
*/
|
||||
static func getReceivedMemo(dbData: URL, idNote: Int64, networkType: NetworkType) -> Memo?
|
||||
|
||||
/**
|
||||
get sent memo from note
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- idNote: note_id of note where the memo is located
|
||||
*/
|
||||
@available(*, deprecated, message: "This function will be deprecated soon. Use `getSentMemo(dbData:idNote:networkType)` instead")
|
||||
static func getSentMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String?
|
||||
|
||||
/**
|
||||
get sent memo from note
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- idNote: note_id of note where the memo is located
|
||||
*/
|
||||
static func getSentMemo(dbData: URL, idNote: Int64, networkType: NetworkType) -> Memo?
|
||||
|
||||
/**
|
||||
Checks that the scanned blocks in the data database, when combined with the recent
|
||||
`CompactBlock`s in the cache database, form a valid chain.
|
||||
This function is built on the core assumption that the information provided in the
|
||||
cache database is more likely to be accurate than the previously-scanned information.
|
||||
This follows from the design (and trust) assumption that the `lightwalletd` server
|
||||
provides accurate block information as of the time it was requested.
|
||||
- Returns:
|
||||
* `-1` if the combined chain is valid.
|
||||
* `upper_bound` if the combined chain is invalid.
|
||||
* `upper_bound` is the height of the highest invalid block (on the assumption that the highest block in the cache database is correct).
|
||||
* `0` if there was an error during validation unrelated to chain validity.
|
||||
- Important: This function does not mutate either of the databases.
|
||||
*/
|
||||
static func validateCombinedChain(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32
|
||||
|
||||
/**
|
||||
Returns the nearest height where a rewind is possible. Currently prunning gets rid of sapling witnesses older
|
||||
than 100 blocks. So in order to reconstruct the witness tree that allows to spend notes from the given wallet
|
||||
the rewind can't be more than 100 block or back to the oldest unspent note that this wallet contains.
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- height: height you would like to rewind to.
|
||||
*/
|
||||
static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32
|
||||
|
||||
/**
|
||||
rewinds the compact block storage to the given height. clears up all derived data as well
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use getNearestRewindHeight when unsure
|
||||
*/
|
||||
static func rewindToHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Bool
|
||||
|
||||
/**
|
||||
Scans new blocks added to the cache for any transactions received by the tracked
|
||||
accounts.
|
||||
This function pays attention only to cached blocks with heights greater than the
|
||||
highest scanned block in `db_data`. Cached blocks with lower heights are not verified
|
||||
against previously-scanned blocks. In particular, this function **assumes** that the
|
||||
caller is handling rollbacks.
|
||||
For brand-new light client databases, this function starts scanning from the Sapling
|
||||
activation height. This height can be fast-forwarded to a more recent block by calling
|
||||
[`zcashlc_init_blocks_table`] before this function.
|
||||
Scanned blocks are required to be height-sequential. If a block is missing from the
|
||||
cache, an error will be signalled.
|
||||
|
||||
- Parameters:
|
||||
- dbCache: location of the compact block cache db
|
||||
- dbData: location of the data db file
|
||||
- limit: scan up to limit blocks. pass 0 to set no limit.
|
||||
returns false if fails to scan.
|
||||
*/
|
||||
static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32, networkType: NetworkType) -> Bool
|
||||
|
||||
/**
|
||||
puts a UTXO into the data db database
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- txid: the txid bytes for the UTXO
|
||||
- index: the index of the UTXO
|
||||
- value: the value of the UTXO
|
||||
- height: the mined height for the UTXO
|
||||
- Returns: true if the operation succeded or false otherwise
|
||||
*/
|
||||
/// puts a UTXO into the data db database
|
||||
/// - Parameters:
|
||||
/// - dbData: location of the data db file
|
||||
/// - txid: the txid bytes for the UTXO
|
||||
/// - index: the index of the UTXO
|
||||
/// - script: the script of the UTXO
|
||||
/// - value: the value of the UTXO
|
||||
/// - height: the mined height for the UTXO
|
||||
/// - networkType: the network type
|
||||
/// - Returns: true if the operation succeded or false otherwise
|
||||
static func putUnspentTransparentOutput(
|
||||
dbData: URL,
|
||||
txid: [UInt8],
|
||||
|
@ -262,176 +451,48 @@ protocol ZcashRustBackendWelding {
|
|||
height: BlockHeight,
|
||||
networkType: NetworkType
|
||||
) throws -> Bool
|
||||
|
||||
/**
|
||||
clears the cached utxos for the given address from the specified height on
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- address: the address of the UTXO
|
||||
- sinceheight: clear the UXTOs from that address on
|
||||
- Returns: the amount of UTXOs cleared or -1 on error
|
||||
*/
|
||||
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32
|
||||
|
||||
/**
|
||||
Gets the balance of the previously downloaded UTXOs
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- address: the address of the UTXO
|
||||
- Returns: the wallet balance containing verified and total balance.
|
||||
- Throws: Rustwelding Error if something fails
|
||||
*/
|
||||
static func downloadedUtxoBalance(dbData: URL, address: String, networkType: NetworkType) throws -> WalletBalance
|
||||
|
||||
/**
|
||||
Scans a transaction for any information that can be decrypted by the accounts in the
|
||||
wallet, and saves it to the wallet.
|
||||
|
||||
- Parameters:
|
||||
- dbData: location of the data db file
|
||||
- tx: the transaction to decrypt
|
||||
- minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID.
|
||||
returns false if fails to decrypt.
|
||||
*/
|
||||
static func decryptAndStoreTransaction(
|
||||
dbData: URL,
|
||||
txBytes: [UInt8],
|
||||
minedHeight: Int32,
|
||||
networkType: NetworkType
|
||||
) -> Bool
|
||||
|
||||
/**
|
||||
Creates a transaction to the given address from the given account
|
||||
- Parameters:
|
||||
- dbData: URL for the Data DB
|
||||
- account: the account index that will originate the transaction
|
||||
- extsk: extended spending key string
|
||||
- to: recipient address
|
||||
- value: transaction amount in Zatoshi
|
||||
- memo: the memo string for this transaction
|
||||
- spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
||||
- outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
||||
*/
|
||||
// swiftlint:disable function_parameter_count
|
||||
static func createToAddress(
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
extsk: String,
|
||||
to address: String,
|
||||
value: Int64,
|
||||
memo: MemoBytes,
|
||||
spendParamsPath: String,
|
||||
outputParamsPath: String,
|
||||
networkType: NetworkType
|
||||
) -> Int64
|
||||
|
||||
/**
|
||||
Creates a transaction to shield all found UTXOs in cache db.
|
||||
- Parameters:
|
||||
- dbCache: URL for the Cache DB
|
||||
- dbData: URL for the Data DB
|
||||
- account: the account index that will originate the transaction
|
||||
- xprv: transparent account private key for the transparent funds that will be shielded.
|
||||
- memo: the memo string for this transaction
|
||||
- spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
||||
- outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
||||
*/
|
||||
// swiftlint:disable function_parameter_count
|
||||
/// Creates a transaction to shield all found UTXOs in cache db for the account the provided `UnifiedSpendingKey` has spend authority for.
|
||||
/// - Parameter dbCache: URL for the Cache DB
|
||||
/// - Parameter dbData: URL for the Data DB
|
||||
/// - Parameter usk: `UnifiedSpendingKey` that spend transparent funds and where the funds will be shielded to.
|
||||
/// - Parameter memo: the `Memo` for this transaction
|
||||
/// - Parameter spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
||||
/// - Parameter outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
||||
/// - Parameter networkType: the network type
|
||||
static func shieldFunds(
|
||||
dbCache: URL,
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
xprv: String,
|
||||
usk: UnifiedSpendingKey,
|
||||
memo: MemoBytes,
|
||||
spendParamsPath: String,
|
||||
outputParamsPath: String,
|
||||
networkType: NetworkType
|
||||
) -> Int64
|
||||
|
||||
/**
|
||||
Derives a full viewing key from a seed
|
||||
- Parameter spendingKey: a string containing the spending key
|
||||
- Returns: the derived key
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveSaplingExtendedFullViewingKey(_ spendingKey: SaplingExtendedSpendingKey, networkType: NetworkType) throws -> SaplingExtendedFullViewingKey?
|
||||
|
||||
/**
|
||||
Derives a set of full viewing keys from a seed
|
||||
- Parameter spendingKey: a string containing the spending key
|
||||
- Parameter accounts: the number of accounts you want to derive from this seed
|
||||
- Returns: an array containing the derived keys
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveSaplingExtendedFullViewingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [SaplingExtendedFullViewingKey]?
|
||||
|
||||
/**
|
||||
Derives a set of Extended Spending Keys from a seed
|
||||
- Parameter seed: a string containing the seed
|
||||
- Parameter accounts: the number of accounts you want to derive from this seed
|
||||
- Returns: an array containing the spending keys
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveSaplingExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [SaplingExtendedSpendingKey]?
|
||||
|
||||
/**
|
||||
Derives a unified address from a seed
|
||||
- Parameter seed: an array of bytes of the seed
|
||||
- Parameter accountIndex: the index of the account you want the address for
|
||||
- Returns: an optional String containing Unified Address
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveUnifiedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String?
|
||||
|
||||
/**
|
||||
Derives a unified address from a Unified Full Viewing Key
|
||||
- Parameter ufvk: a string containing the extended full viewing key
|
||||
- Returns: an optional String containing the Shielded address
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveUnifiedAddressFromViewingKey(_ ufvk: String, networkType: NetworkType) throws -> String?
|
||||
|
||||
|
||||
/// Derives a transparent address from seed bytes
|
||||
/// - Parameter seed: an array of bytes of the seed
|
||||
/// - Parameter account: account number
|
||||
/// - Parameter index: diversifier index
|
||||
/// - Returns: an optional String containing the transparent address
|
||||
/// - Throws: RustBackendError if fatal error occurs
|
||||
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String?
|
||||
|
||||
/**
|
||||
Derives a transparent account private key from Seed
|
||||
- Parameter seed: an array of bytes containing the seed
|
||||
- Returns: an optional String containing the transparent secret (private) key
|
||||
*/
|
||||
static func deriveTransparentAccountPrivateKeyFromSeed(seed: [UInt8], account: Int, networkType: NetworkType) throws -> String?
|
||||
|
||||
/**
|
||||
Derives a transparent address from a secret key
|
||||
- Parameter tsk: a hex string containing the Secret Key
|
||||
- Returns: an optional String containing the transparent address.
|
||||
*/
|
||||
static func deriveTransparentAddressFromAccountPrivateKey(_ tsk: String, index: Int, networkType: NetworkType) throws -> String?
|
||||
|
||||
/**
|
||||
Derives a tranparent address from a public key
|
||||
- Parameter pubkey: public key represented as a string
|
||||
*/
|
||||
static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String
|
||||
|
||||
static func deriveUnifiedFullViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int32, networkType: NetworkType) throws -> [UnifiedFullViewingKey]
|
||||
|
||||
) -> Int64 // swiftlint:disable function_parameter_count
|
||||
|
||||
/// Obtains the available receiver typecodes for the given String encoded Unified Address
|
||||
/// - Parameter address: public key represented as a String
|
||||
/// - Returns the `[UInt32]` that compose the given UA
|
||||
/// - Throws `RustWeldingError.malformedStringInput` when the UA is either invalid or malformed
|
||||
/// - Throws `RustWeldingError.invalidInput(message: String)` when the UA is either invalid or malformed
|
||||
static func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32]
|
||||
|
||||
/**
|
||||
Gets the consensus branch id for the given height
|
||||
- Parameter height: the height you what to know the branch id for
|
||||
*/
|
||||
static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32
|
||||
|
||||
/// Gets the consensus branch id for the given height
|
||||
/// - Parameter height: the height you what to know the branch id for
|
||||
/// - Parameter networkType: the network type
|
||||
static func consensusBranchIdFor(
|
||||
height: Int32,
|
||||
networkType: NetworkType
|
||||
) throws -> Int32
|
||||
|
||||
|
||||
/// Derives a `UnifiedFullViewingKey` from a `UnifiedSpendingKey`
|
||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` to derive from
|
||||
/// - Parameter networkType: the network type
|
||||
/// - Throws: `RustWeldingError.unableToDeriveKeys` if the SDK couldn't derive the UFVK.
|
||||
/// - Returns: the derived `UnifiedFullViewingKey`
|
||||
static func deriveUnifiedFullViewingKey(
|
||||
from spendingKey: UnifiedSpendingKey,
|
||||
networkType: NetworkType
|
||||
) throws -> UnifiedFullViewingKey
|
||||
}
|
||||
|
|
|
@ -106,27 +106,24 @@ public protocol Synchronizer {
|
|||
func getTransparentAddress(accountIndex: Int) -> TransparentAddress?
|
||||
|
||||
/// Sends zatoshi.
|
||||
/// - Parameter spendingKey: the key that allows spends to occur.
|
||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` that allows spends to occur.
|
||||
/// - Parameter zatoshi: the amount to send in Zatoshi.
|
||||
/// - Parameter toAddress: the recipient's address.
|
||||
/// - Parameter memo: the memo to include as part of the transaction.
|
||||
/// - Parameter accountIndex: the optional account id to use. By default, the first account is used.
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func sendToAddress(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
toAddress: Recipient,
|
||||
memo: Memo,
|
||||
from accountIndex: Int
|
||||
memo: Memo
|
||||
) async throws -> PendingTransactionEntity
|
||||
|
||||
/// Shields transparent funds from the given private key into the best shielded pool of the given account.
|
||||
/// - Parameter transparentAccountPrivateKey: the key that allows to spend transparent funds
|
||||
/// Shields transparent funds from the given private key into the best shielded pool of the account associated to the given `UnifiedSpendingKey`.
|
||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` that allows to spend transparent funds
|
||||
/// - Parameter memo: the optional memo to include as part of the transaction.
|
||||
/// - Parameter accountIndex: the optional account id that will be used to shield your funds to. By default, the first account is used.
|
||||
func shieldFunds(
|
||||
transparentAccountPrivateKey: TransparentAccountPrivKey,
|
||||
memo: Memo,
|
||||
from accountIndex: Int
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
memo: Memo
|
||||
) async throws -> PendingTransactionEntity
|
||||
|
||||
/// Attempts to cancel a transaction that is about to be sent. Typically, cancellation is only
|
||||
|
@ -150,7 +147,6 @@ public protocol Synchronizer {
|
|||
/// A repository serving transactions in a paginated manner
|
||||
/// - Parameter kind: Transaction Kind expected from this PaginatedTransactionRepository
|
||||
func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository
|
||||
|
||||
|
||||
/// Returns a list of confirmed transactions that preceed the given transaction with a limit count.
|
||||
/// - Parameters:
|
||||
|
@ -165,14 +161,13 @@ public protocol Synchronizer {
|
|||
|
||||
/// Returns the latest block height from the provided Lightwallet endpoint
|
||||
func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void)
|
||||
|
||||
|
||||
/// Returns the latest block height from the provided Lightwallet endpoint
|
||||
/// Blocking
|
||||
func latestHeight() throws -> BlockHeight
|
||||
|
||||
/// Returns the latests UTXOs for the given address from the specified height on
|
||||
func refreshUTXOs(address: String, from height: BlockHeight) async throws -> RefreshedUTXOs
|
||||
func refreshUTXOs(address: TransparentAddress, from height: BlockHeight) async throws -> RefreshedUTXOs
|
||||
|
||||
/// Returns the last stored transparent balance
|
||||
func getTransparentBalance(accountIndex: Int) throws -> WalletBalance
|
||||
|
@ -191,7 +186,7 @@ public protocol Synchronizer {
|
|||
|
||||
/// Returns the shielded verified balance (anchor is 10 blocks back)
|
||||
func getShieldedVerifiedBalance(accountIndex: Int) -> Zatoshi
|
||||
|
||||
|
||||
|
||||
/// Stops the synchronizer and rescans the known blocks with the current keys.
|
||||
/// - Parameter policy: the rewind policy
|
||||
|
|
|
@ -458,11 +458,10 @@ public class SDKSynchronizer: Synchronizer {
|
|||
// MARK: Synchronizer methods
|
||||
|
||||
public func sendToAddress(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
toAddress: Recipient,
|
||||
memo: Memo,
|
||||
from accountIndex: Int
|
||||
memo: Memo
|
||||
) async throws -> PendingTransactionEntity {
|
||||
do {
|
||||
try await initializer.downloadParametersIfNeeded()
|
||||
|
@ -474,23 +473,19 @@ public class SDKSynchronizer: Synchronizer {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: zatoshi,
|
||||
toAddress: toAddress.stringEncoded,
|
||||
memo: memo,
|
||||
from: accountIndex
|
||||
memo: memo
|
||||
)
|
||||
}
|
||||
|
||||
public func shieldFunds(
|
||||
transparentAccountPrivateKey: TransparentAccountPrivKey,
|
||||
memo: Memo,
|
||||
from accountIndex: Int
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
memo: Memo
|
||||
) async throws -> PendingTransactionEntity {
|
||||
// let's see if there are funds to shield
|
||||
let derivationTool = DerivationTool(networkType: self.network.networkType)
|
||||
|
||||
let accountIndex = Int(spendingKey.account)
|
||||
do {
|
||||
let tAddr = try derivationTool.deriveTransparentAddressFromAccountPrivateKey(transparentAccountPrivateKey, index: 0)
|
||||
|
||||
let tBalance = try utxoRepository.balance(address: tAddr.stringEncoded, latestHeight: self.latestDownloadedHeight())
|
||||
let tBalance = try self.getTransparentBalance(accountIndex: accountIndex)
|
||||
|
||||
// Verify that at least there are funds for the fee. Ideally this logic will be improved by the shielding wallet.
|
||||
guard tBalance.verified >= self.network.constants.defaultFee(for: self.latestScannedHeight) else {
|
||||
|
@ -507,7 +502,7 @@ public class SDKSynchronizer: Synchronizer {
|
|||
|
||||
// TODO: Task will be removed when this method is changed to async, issue 487, https://github.com/zcash/ZcashLightClientKit/issues/487
|
||||
let transaction = try await transactionManager.encodeShieldingTransaction(
|
||||
xprv: transparentAccountPrivateKey,
|
||||
spendingKey: spendingKey,
|
||||
pendingTransaction: shieldingSpend
|
||||
)
|
||||
|
||||
|
@ -518,18 +513,17 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
|
||||
func createToAddress(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
toAddress: String,
|
||||
memo: Memo,
|
||||
from accountIndex: Int
|
||||
memo: Memo
|
||||
) async throws -> PendingTransactionEntity {
|
||||
do {
|
||||
let spend = try transactionManager.initSpend(
|
||||
zatoshi: zatoshi,
|
||||
toAddress: toAddress,
|
||||
memo: memo.asMemoBytes(),
|
||||
from: accountIndex
|
||||
from: Int(spendingKey.account)
|
||||
)
|
||||
|
||||
let transaction = try await transactionManager.encode(
|
||||
|
@ -596,7 +590,10 @@ public class SDKSynchronizer: Synchronizer {
|
|||
return
|
||||
}
|
||||
|
||||
initializer.lightWalletService.fetchUTXOs(for: address, height: network.constants.saplingActivationHeight) { [weak self] fetchResult in
|
||||
initializer.lightWalletService.fetchUTXOs(
|
||||
for: address,
|
||||
height: network.constants.saplingActivationHeight
|
||||
) { [weak self] fetchResult in
|
||||
guard let self = self else { return }
|
||||
switch fetchResult {
|
||||
case .success(let utxos):
|
||||
|
@ -613,7 +610,7 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
public func refreshUTXOs(address: String, from height: BlockHeight) async throws -> RefreshedUTXOs {
|
||||
public func refreshUTXOs(address: TransparentAddress, from height: BlockHeight) async throws -> RefreshedUTXOs {
|
||||
try await blockProcessor.refreshUTXOs(tAddress: address, startHeight: height)
|
||||
}
|
||||
@available(*, deprecated, message: "This function will be removed soon, use the one returning a `Zatoshi` value instead")
|
||||
|
@ -639,28 +636,19 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
|
||||
public func getUnifiedAddress(accountIndex: Int) -> UnifiedAddress? {
|
||||
blockProcessor.getUnifiedAddres(accountIndex: accountIndex)
|
||||
blockProcessor.getUnifiedAddress(accountIndex: accountIndex)
|
||||
}
|
||||
|
||||
public func getTransparentAddress(accountIndex: Int) -> TransparentAddress? {
|
||||
blockProcessor.getTransparentAddress(accountIndex: accountIndex)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Returns the last stored transparent balance
|
||||
public func getTransparentBalance(accountIndex: Int) throws -> WalletBalance {
|
||||
try blockProcessor.getTransparentBalance(accountIndex: accountIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the last stored transparent balance
|
||||
*/
|
||||
public func getTransparentBalance(address: String) throws -> WalletBalance {
|
||||
do {
|
||||
return try self.blockProcessor.utxoCacheBalance(tAddress: address)
|
||||
} catch {
|
||||
throw SynchronizerError.uncategorized(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
public func rewind(_ policy: RewindPolicy) throws {
|
||||
self.stop()
|
||||
|
||||
|
|
|
@ -20,76 +20,28 @@ public protocol KeyValidation {
|
|||
}
|
||||
|
||||
public protocol KeyDeriving {
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated viewing keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive viewing keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the viewing keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
func deriveUnifiedFullViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey]
|
||||
|
||||
/**
|
||||
Given a spending key, return the associated viewing key.
|
||||
|
||||
- Parameter spendingKey: the key from which to derive the viewing key.
|
||||
|
||||
- Returns: the viewing key that corresponds to the spending key.
|
||||
*/
|
||||
func deriveViewingKey(spendingKey: SaplingExtendedSpendingKey) throws -> SaplingExtendedFullViewingKey
|
||||
/// Given the seed bytes tand the account index, return the UnifiedSpendingKey
|
||||
/// - Parameter seed: `[Uint8]` seed bytes
|
||||
/// - Parameter accountNumber: `Int` with the account number
|
||||
/// - Throws `.unableToDerive` if there's a problem deriving this key
|
||||
/// - Returns a `UnifiedSpendingKey`
|
||||
func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) throws -> UnifiedSpendingKey
|
||||
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated spending keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive spending keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the spending keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [SaplingExtendedSpendingKey]
|
||||
|
||||
/**
|
||||
Given a seed and account index, return the associated unified address.
|
||||
|
||||
- Parameter seed: the seed from which to derive the address.
|
||||
- Parameter accountIndex: the index of the account to use for deriving the address. Multiple
|
||||
accounts are not fully supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the address that corresponds to the seed and account index.
|
||||
*/
|
||||
func deriveUnifiedAddress(seed: [UInt8], accountIndex: Int) throws -> UnifiedAddress
|
||||
|
||||
/// Extracts the `SaplingAddress` from the given `UnifiedAddress`
|
||||
/// - Parameter address: the `UnifiedAddress`
|
||||
/// - Throws `KeyDerivationErrors.receiverNotFound` if the receiver is not present
|
||||
static func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress?
|
||||
|
||||
/// Given a unified full viewing key string, return the associated unified address.
|
||||
///
|
||||
/// - Parameter ufvk: the viewing key to use for deriving the address. The viewing key is tied to
|
||||
/// a specific account so no account index is required.
|
||||
///
|
||||
/// - Returns: the address that corresponds to the viewing key.
|
||||
func deriveUnifiedAddress(from ufvk: UnifiedFullViewingKey) throws -> UnifiedAddress
|
||||
|
||||
/**
|
||||
Derives a transparent address from seedbytes, specifying account and index
|
||||
*/
|
||||
func deriveTransparentAddress(seed: [UInt8], account: Int, index: Int) throws -> TransparentAddress
|
||||
|
||||
/**
|
||||
Derives the account private key to spend transparent funds from a specific seed and account
|
||||
*/
|
||||
func deriveTransparentAccountPrivateKey(seed: [UInt8], account: Int) throws -> TransparentAccountPrivKey
|
||||
|
||||
/**
|
||||
Derives a transparent address from the given transparent account private key
|
||||
*/
|
||||
func deriveTransparentAddressFromAccountPrivateKey(_ xprv: TransparentAccountPrivKey, index: Int) throws -> TransparentAddress
|
||||
/// Extracts the `TransparentAddress` from the given `UnifiedAddress`
|
||||
/// - Parameter address: the `UnifiedAddress`
|
||||
/// - Throws `KeyDerivationErrors.receiverNotFound` if the receiver is not present
|
||||
static func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress?
|
||||
|
||||
/// Extracts the `UnifiedAddress.ReceiverTypecodes` from the given `UnifiedAddress`
|
||||
/// - Parameter address: the `UnifiedAddress`
|
||||
/// - Throws
|
||||
func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes]
|
||||
static func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes]
|
||||
}
|
||||
|
||||
public enum KeyDerivationErrors: Error {
|
||||
|
@ -97,10 +49,11 @@ public enum KeyDerivationErrors: Error {
|
|||
case unableToDerive
|
||||
case invalidInput
|
||||
case invalidUnifiedAddress
|
||||
case receiverNotFound
|
||||
}
|
||||
|
||||
public class DerivationTool: KeyDeriving {
|
||||
var rustwelding: ZcashRustBackendWelding.Type = ZcashRustBackend.self
|
||||
static var rustwelding: ZcashRustBackendWelding.Type = ZcashRustBackend.self
|
||||
|
||||
var networkType: NetworkType
|
||||
|
||||
|
@ -108,195 +61,47 @@ public class DerivationTool: KeyDeriving {
|
|||
self.networkType = networkType
|
||||
}
|
||||
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated viewing keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive viewing keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the viewing keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
public func deriveUnifiedFullViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey] {
|
||||
guard numberOfAccounts > 0, let numberOfAccounts = Int32(exactly: numberOfAccounts) else {
|
||||
throw KeyDerivationErrors.invalidInput
|
||||
}
|
||||
|
||||
do {
|
||||
let ufvks = try rustwelding.deriveUnifiedFullViewingKeyFromSeed(seed, numberOfAccounts: numberOfAccounts, networkType: networkType)
|
||||
|
||||
var keys: [UnifiedFullViewingKey] = []
|
||||
for ufvk in ufvks {
|
||||
keys.append(ufvk)
|
||||
}
|
||||
return keys
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
public static func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress? {
|
||||
try rustwelding.getSaplingReceiver(for: unifiedAddress)
|
||||
}
|
||||
|
||||
/**
|
||||
Given a spending key, return the associated viewing key.
|
||||
|
||||
- Parameter spendingKey: the key from which to derive the viewing key.
|
||||
|
||||
- Returns: the viewing key that corresponds to the spending key.
|
||||
*/
|
||||
public func deriveViewingKey(spendingKey: SaplingExtendedSpendingKey) throws -> SaplingExtendedFullViewingKey {
|
||||
do {
|
||||
guard let key = try rustwelding.deriveSaplingExtendedFullViewingKey(spendingKey, networkType: networkType) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return key
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
public static func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress? {
|
||||
try rustwelding.getTransparentReceiver(for: unifiedAddress)
|
||||
}
|
||||
|
||||
public func deriveUnifiedFullViewingKeysFromSeed(_ seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey] {
|
||||
guard numberOfAccounts > 0, let numberOfAccounts = Int32(exactly: numberOfAccounts) else {
|
||||
throw KeyDerivationErrors.invalidInput
|
||||
}
|
||||
do {
|
||||
return try rustwelding.deriveUnifiedFullViewingKeyFromSeed(seed, numberOfAccounts: numberOfAccounts, networkType: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
/// Given a spending key, return the associated viewing key.
|
||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` from which to derive the `UnifiedFullViewingKey` from.
|
||||
/// - Returns: the viewing key that corresponds to the spending key.
|
||||
public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) throws -> UnifiedFullViewingKey {
|
||||
try DerivationTool.rustwelding.deriveUnifiedFullViewingKey(from: spendingKey, networkType: self.networkType)
|
||||
}
|
||||
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated spending keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive spending keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the spending keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
public func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [SaplingExtendedSpendingKey] {
|
||||
guard numberOfAccounts > 0, let numberOfAccounts = Int32(exactly: numberOfAccounts) else {
|
||||
throw KeyDerivationErrors.invalidInput
|
||||
}
|
||||
do {
|
||||
guard let keys = try rustwelding.deriveSaplingExtendedSpendingKeys(seed: seed, accounts: numberOfAccounts, networkType: networkType) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return keys
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Given a seed and account index, return the associated unified address.
|
||||
|
||||
- Parameter seed: the seed from which to derive the address.
|
||||
- Parameter accountIndex: the index of the account to use for deriving the address. Multiple
|
||||
accounts are not fully supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the address that corresponds to the seed and account index.
|
||||
*/
|
||||
public func deriveUnifiedAddress(seed: [UInt8], accountIndex: Int) throws -> UnifiedAddress {
|
||||
|
||||
/// Given a seed and a number of accounts, return the associated spending keys.
|
||||
/// - Parameter seed: the seed from which to derive spending keys.
|
||||
/// - Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
/// supported so the default value of 1 is recommended.
|
||||
/// - Returns: the spending keys that correspond to the seed, formatted as Strings.
|
||||
public func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) throws -> UnifiedSpendingKey {
|
||||
guard accountIndex >= 0, let accountIndex = Int32(exactly: accountIndex) else {
|
||||
throw KeyDerivationErrors.invalidInput
|
||||
}
|
||||
|
||||
do {
|
||||
guard let address = try rustwelding.deriveUnifiedAddressFromSeed(seed: seed, accountIndex: accountIndex, networkType: networkType) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return UnifiedAddress(validatedEncoding: address, network: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Given a unified viewing key string, return the associated unified address.
|
||||
|
||||
- Parameter viewingKey: the viewing key to use for deriving the address. The viewing key is tied to
|
||||
a specific account so no account index is required.
|
||||
|
||||
- Returns: the address that corresponds to the viewing key.
|
||||
*/
|
||||
public func deriveUnifiedAddress(from ufvk: UnifiedFullViewingKey) throws -> UnifiedAddress {
|
||||
do {
|
||||
guard let stringEncodedUA = try rustwelding.deriveUnifiedAddressFromViewingKey(ufvk.stringEncoded, networkType: networkType) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return UnifiedAddress(validatedEncoding: stringEncodedUA, network: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
public func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes] {
|
||||
do {
|
||||
return try rustwelding.receiverTypecodesOnUnifiedAddress(address.stringEncoded)
|
||||
.map({ UnifiedAddress.ReceiverTypecodes(typecode: $0) })
|
||||
} catch {
|
||||
throw KeyDerivationErrors.invalidUnifiedAddress
|
||||
}
|
||||
}
|
||||
|
||||
public func deriveTransparentAddress(seed: [UInt8], account: Int = 0, index: Int = 0) throws -> TransparentAddress {
|
||||
do {
|
||||
guard let taddr = try rustwelding.deriveTransparentAddressFromSeed(
|
||||
seed: seed,
|
||||
account: account,
|
||||
index: index,
|
||||
networkType: networkType
|
||||
) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return TransparentAddress(validatedEncoding: taddr)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// derives a Unified Address from a Unified Full Viewing Key
|
||||
public func deriveUnifiedAddressFromUnifiedFullViewingKey(_ ufvk: UnifiedFullViewingKey) throws -> UnifiedAddress {
|
||||
do {
|
||||
return try deriveUnifiedAddress(from: ufvk)
|
||||
return try DerivationTool.rustwelding.deriveUnifiedSpendingKey(
|
||||
from: seed,
|
||||
accountIndex: accountIndex,
|
||||
networkType: self.networkType
|
||||
)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
}
|
||||
|
||||
/// Derives the transparent funds account private key from the given seed
|
||||
/// - Throws:
|
||||
/// - KeyDerivationErrors.derivationError with the underlying error when it fails
|
||||
/// - KeyDerivationErrors.unableToDerive when there's an unknown error
|
||||
public func deriveTransparentAccountPrivateKey(seed: [UInt8], account: Int = 0) throws -> TransparentAccountPrivKey {
|
||||
public static func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes] {
|
||||
do {
|
||||
guard let seedKey = try rustwelding.deriveTransparentAccountPrivateKeyFromSeed(
|
||||
seed: seed,
|
||||
account: account,
|
||||
networkType: networkType
|
||||
) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return TransparentAccountPrivKey(encoding: seedKey)
|
||||
return try DerivationTool.rustwelding.receiverTypecodesOnUnifiedAddress(address.stringEncoded)
|
||||
.map({ UnifiedAddress.ReceiverTypecodes(typecode: $0) })
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Derives the transparent address from an account private key
|
||||
/// - Throws:
|
||||
/// - KeyDerivationErrors.derivationError with the underlying error when it fails
|
||||
/// - KeyDerivationErrors.unableToDerive when there's an unknown error
|
||||
public func deriveTransparentAddressFromAccountPrivateKey(_ xprv: TransparentAccountPrivKey, index: Int) throws -> TransparentAddress {
|
||||
do {
|
||||
guard let tAddr = try rustwelding.deriveTransparentAddressFromAccountPrivateKey(xprv.encoding, index: index, networkType: networkType) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return TransparentAddress(validatedEncoding: tAddr)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
throw KeyDerivationErrors.invalidUnifiedAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +109,7 @@ public class DerivationTool: KeyDeriving {
|
|||
extension DerivationTool: KeyValidation {
|
||||
public func isValidUnifiedAddress(_ unifiedAddress: String) throws -> Bool {
|
||||
do {
|
||||
return try rustwelding.isValidUnifiedAddress(unifiedAddress, networkType: networkType)
|
||||
return try DerivationTool.rustwelding.isValidUnifiedAddress(unifiedAddress, networkType: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
|
@ -312,7 +117,7 @@ extension DerivationTool: KeyValidation {
|
|||
|
||||
public func isValidExtendedViewingKey(_ extvk: String) throws -> Bool {
|
||||
do {
|
||||
return try rustwelding.isValidSaplingExtendedFullViewingKey(extvk, networkType: networkType)
|
||||
return try DerivationTool.rustwelding.isValidSaplingExtendedFullViewingKey(extvk, networkType: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
|
@ -320,7 +125,7 @@ extension DerivationTool: KeyValidation {
|
|||
|
||||
public func isValidTransparentAddress(_ tAddress: String) throws -> Bool {
|
||||
do {
|
||||
return try rustwelding.isValidTransparentAddress(tAddress, networkType: networkType)
|
||||
return try DerivationTool.rustwelding.isValidTransparentAddress(tAddress, networkType: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
|
@ -328,7 +133,7 @@ extension DerivationTool: KeyValidation {
|
|||
|
||||
public func isValidSaplingAddress(_ zAddress: String) throws -> Bool {
|
||||
do {
|
||||
return try rustwelding.isValidSaplingAddress(zAddress, networkType: networkType)
|
||||
return try DerivationTool.rustwelding.isValidSaplingAddress(zAddress, networkType: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
|
@ -336,7 +141,7 @@ extension DerivationTool: KeyValidation {
|
|||
|
||||
public func isValidSaplingExtendedSpendingKey(_ extsk: String) throws -> Bool {
|
||||
do {
|
||||
return try rustwelding.isValidSaplingExtendedSpendingKey(extsk, networkType: networkType)
|
||||
return try DerivationTool.rustwelding.isValidSaplingExtendedSpendingKey(extsk, networkType: networkType)
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
|
@ -369,9 +174,8 @@ extension UnifiedAddress {
|
|||
/// already validated by another function. only for internal use. Unless you are
|
||||
/// constructing an address from a primitive function of the FFI, you probably
|
||||
/// shouldn't be using this..
|
||||
init(validatedEncoding: String, network: NetworkType) {
|
||||
init(validatedEncoding: String) {
|
||||
self.encoding = validatedEncoding
|
||||
self.network = network
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -407,3 +211,27 @@ extension SaplingExtendedSpendingKey {
|
|||
self.encoding = validatedEncoding
|
||||
}
|
||||
}
|
||||
|
||||
public extension UnifiedSpendingKey {
|
||||
func map<T>(_ transform: (UnifiedSpendingKey) throws -> T) rethrows -> T {
|
||||
try transform(self)
|
||||
}
|
||||
|
||||
func deriveFullViewingKey() throws -> UnifiedFullViewingKey {
|
||||
try DerivationTool(networkType: self.network).deriveUnifiedFullViewingKey(from: self)
|
||||
}
|
||||
}
|
||||
|
||||
public extension UnifiedAddress {
|
||||
/// Extracts the sapling receiver from this UA if available
|
||||
/// - Returns: an `Optional<SaplingAddress>`
|
||||
func saplingReceiver() -> SaplingAddress? {
|
||||
try? DerivationTool.saplingReceiver(from: self)
|
||||
}
|
||||
|
||||
/// Extracts the transparent receiver from this UA if available
|
||||
/// - Returns: an `Optional<TransparentAddress>`
|
||||
func transparentReceiver() -> TransparentAddress? {
|
||||
try? DerivationTool.transparentReceiver(from: self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,12 +65,12 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
|||
}
|
||||
|
||||
func encodeShieldingTransaction(
|
||||
xprv: TransparentAccountPrivKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
pendingTransaction: PendingTransactionEntity
|
||||
) async throws -> PendingTransactionEntity {
|
||||
do {
|
||||
let encodedTransaction = try self.encoder.createShieldingTransaction(
|
||||
tAccountPrivateKey: xprv,
|
||||
spendingKey: spendingKey,
|
||||
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
|
||||
from: pendingTransaction.accountIndex
|
||||
)
|
||||
|
@ -98,7 +98,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
|||
}
|
||||
|
||||
func encode(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
pendingTransaction: PendingTransactionEntity
|
||||
) async throws -> PendingTransactionEntity {
|
||||
do {
|
||||
|
|
|
@ -25,15 +25,16 @@ protocol TransactionEncoder {
|
|||
/// Blocking
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - Parameter spendingKey: a `SaplingExtendedSpendingKey` containing the spending key
|
||||
/// - Parameter spendingKey: a `UnifiedSpendingKey` containing the spending key
|
||||
/// - Parameter zatoshi: the amount to send in `Zatoshi`
|
||||
/// - Parameter to: string containing the recipient address
|
||||
/// - Parameter memoBytes: MemoBytes for this transaction
|
||||
/// - Parameter accountIndex: index of the account that will be used to send the funds
|
||||
///
|
||||
/// - Throws: a TransactionEncoderError
|
||||
///
|
||||
func createTransaction(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes,
|
||||
|
@ -55,7 +56,7 @@ protocol TransactionEncoder {
|
|||
/// - Parameter result: a non escaping closure that receives a Result containing either an EncodedTransaction or a /// TransactionEncoderError
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func createTransaction(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes,
|
||||
|
@ -68,13 +69,13 @@ protocol TransactionEncoder {
|
|||
Blocking
|
||||
|
||||
- Parameters:
|
||||
- Parameter tAccountPrivateKey: transparent account private key to spend the UTXOs
|
||||
- Parameter spendingKey: `UnifiedSpendingKey` to spend the UTXOs
|
||||
- Parameter memoBytes: containing the memo (optional)
|
||||
- Parameter accountIndex: index of the account that will be used to send the funds
|
||||
- Throws: a TransactionEncoderError
|
||||
*/
|
||||
func createShieldingTransaction(
|
||||
tAccountPrivateKey: TransparentAccountPrivKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
memoBytes: MemoBytes,
|
||||
from accountIndex: Int
|
||||
) throws -> EncodedTransaction
|
||||
|
|
|
@ -22,12 +22,12 @@ protocol OutboundTransactionManager {
|
|||
) throws -> PendingTransactionEntity
|
||||
|
||||
func encodeShieldingTransaction(
|
||||
xprv: TransparentAccountPrivKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
pendingTransaction: PendingTransactionEntity
|
||||
) async throws -> PendingTransactionEntity
|
||||
|
||||
func encode(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
pendingTransaction: PendingTransactionEntity
|
||||
) async throws -> PendingTransactionEntity
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
}
|
||||
|
||||
func createTransaction(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes,
|
||||
|
@ -80,7 +80,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func createTransaction(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes,
|
||||
|
@ -108,7 +108,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
}
|
||||
|
||||
func createSpend(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes,
|
||||
|
@ -120,8 +120,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
|
||||
let txId = rustBackend.createToAddress(
|
||||
dbData: self.dataDbURL,
|
||||
account: Int32(accountIndex),
|
||||
extsk: spendingKey.stringEncoded,
|
||||
usk: spendingKey,
|
||||
to: address,
|
||||
value: zatoshi.amount,
|
||||
memo: memoBytes,
|
||||
|
@ -138,12 +137,12 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
}
|
||||
|
||||
func createShieldingTransaction(
|
||||
tAccountPrivateKey: TransparentAccountPrivKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
memoBytes: MemoBytes,
|
||||
from accountIndex: Int
|
||||
) throws -> EncodedTransaction {
|
||||
let txId = try createShieldingSpend(
|
||||
xprv: tAccountPrivateKey.encoding,
|
||||
spendingKey: spendingKey,
|
||||
memo: memoBytes,
|
||||
accountIndex: accountIndex
|
||||
)
|
||||
|
@ -162,7 +161,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
}
|
||||
}
|
||||
|
||||
func createShieldingSpend(xprv: String, memo: MemoBytes, accountIndex: Int) throws -> Int {
|
||||
func createShieldingSpend(spendingKey: UnifiedSpendingKey, memo: MemoBytes, accountIndex: Int) throws -> Int {
|
||||
guard ensureParams(spend: self.spendParamsURL, output: self.spendParamsURL) else {
|
||||
throw TransactionEncoderError.missingParams
|
||||
}
|
||||
|
@ -170,8 +169,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
let txId = rustBackend.shieldFunds(
|
||||
dbCache: self.cacheDbURL,
|
||||
dbData: self.dataDbURL,
|
||||
account: Int32(accountIndex),
|
||||
xprv: xprv,
|
||||
usk: spendingKey,
|
||||
memo: memo,
|
||||
spendParamsPath: self.spendParamsURL.path,
|
||||
outputParamsPath: self.outputParamsURL.path,
|
||||
|
|
|
@ -310,8 +310,7 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
spendingKey: coordinator.spendingKeys!.first!,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "test transaction"),
|
||||
from: 0
|
||||
memo: try Memo(string: "test transaction")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
|
@ -733,8 +732,8 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -1095,15 +1094,16 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
|
||||
continuation.resume()
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 5)
|
||||
wait(for: [firstSyncExpectation], timeout: 10)
|
||||
|
||||
sleep(1)
|
||||
let initialTotalBalance: Zatoshi = coordinator.synchronizer.initializer.getBalance()
|
||||
|
@ -1119,8 +1119,8 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try! Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try! Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
|
|
@ -91,8 +91,8 @@ class BalanceTests: XCTestCase {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalance,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -249,8 +249,8 @@ class BalanceTests: XCTestCase {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalanceMinusOne,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "\(self.description) \(Date().description)"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "\(self.description) \(Date().description)")
|
||||
)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -406,8 +406,8 @@ class BalanceTests: XCTestCase {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalanceMinusOne,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "test send \(self.description) \(Date().description)"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "test send \(self.description) \(Date().description)")
|
||||
)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -566,8 +566,8 @@ class BalanceTests: XCTestCase {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -749,8 +749,8 @@ class BalanceTests: XCTestCase {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "test send \(self.description) \(Date().description)"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "test send \(self.description) \(Date().description)")
|
||||
)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -915,8 +915,8 @@ class BalanceTests: XCTestCase {
|
|||
spendingKey: spendingKeys,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: memo,
|
||||
from: 0)
|
||||
memo: memo
|
||||
)
|
||||
pendingTx = transaction
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -1090,8 +1090,8 @@ class BalanceTests: XCTestCase {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "test send \(self.description)"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "test send \(self.description)")
|
||||
)
|
||||
pendingTx = pending
|
||||
} catch {
|
||||
// balance should be the same as before sending if transaction failed
|
||||
|
|
|
@ -90,8 +90,8 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -189,8 +189,8 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -268,8 +268,8 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -379,8 +379,8 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
@ -508,8 +508,8 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
|
|
@ -105,8 +105,8 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
|||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: try Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "this is a test"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "this is a test")
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
|
|
@ -181,8 +181,8 @@ class RewindRescanTests: XCTestCase {
|
|||
spendingKey: coordinator.spendingKey,
|
||||
zatoshi: Zatoshi(1000),
|
||||
toAddress: testRecipientAddress,
|
||||
memo: .empty,
|
||||
from: 0)
|
||||
memo: .empty
|
||||
)
|
||||
XCTAssertEqual(Zatoshi(1000), pendingTx.value)
|
||||
} catch {
|
||||
XCTFail("sending fail: \(error)")
|
||||
|
@ -284,8 +284,8 @@ class RewindRescanTests: XCTestCase {
|
|||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalance,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: try Memo(string: "test send \(self.description) \(Date().description)"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "test send \(self.description) \(Date().description)")
|
||||
)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
|
|
|
@ -207,14 +207,6 @@ class ShieldFundsTests: XCTestCase {
|
|||
// 9. shield the funds
|
||||
let shieldFundsExpectation = XCTestExpectation(description: "shield funds")
|
||||
|
||||
let transparentAccountPrivateKey = try DerivationTool(
|
||||
networkType: network.networkType
|
||||
)
|
||||
.deriveTransparentAccountPrivateKey(
|
||||
seed: TestSeed().seed(),
|
||||
account: 0
|
||||
)
|
||||
|
||||
shouldContinue = false
|
||||
|
||||
var shieldingPendingTx: PendingTransactionEntity?
|
||||
|
@ -222,9 +214,9 @@ class ShieldFundsTests: XCTestCase {
|
|||
// shield the funds
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.shieldFunds(
|
||||
transparentAccountPrivateKey: transparentAccountPrivateKey,
|
||||
memo: try Memo(string: "shield funds"),
|
||||
from: 0)
|
||||
spendingKey: coordinator.spendingKey,
|
||||
memo: try Memo(string: "shield funds")
|
||||
)
|
||||
shouldContinue = true
|
||||
XCTAssertEqual(pendingTx.value, Zatoshi(10000))
|
||||
shieldingPendingTx = pendingTx
|
||||
|
|
|
@ -62,8 +62,24 @@ class TransactionEnhancementTests: XCTestCase {
|
|||
|
||||
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
|
||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||
|
||||
_ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1, networkType: network.networkType)
|
||||
|
||||
let ufvks = [
|
||||
try DerivationTool(networkType: network.networkType)
|
||||
.deriveUnifiedSpendingKey(seed: TestSeed().seed(), accountIndex: 0)
|
||||
.map{
|
||||
try DerivationTool(networkType: network.networkType)
|
||||
.deriveUnifiedFullViewingKey(from: $0)
|
||||
}
|
||||
|
||||
]
|
||||
guard try rustBackend.initAccountsTable(
|
||||
dbData: processorConfig.dataDb,
|
||||
ufvks: ufvks,
|
||||
networkType: network.networkType
|
||||
) else {
|
||||
XCTFail("Failed to init accounts table error: " + String(describing: rustBackend.getLastError()))
|
||||
return
|
||||
}
|
||||
|
||||
let dbInit = try rustBackend.initDataDb(dbData: processorConfig.dataDb, seed: nil, networkType: network.networkType)
|
||||
|
||||
|
|
|
@ -109,8 +109,8 @@ class Z2TReceiveTests: XCTestCase {
|
|||
spendingKey: coordinator.spendingKeys!.first!,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: try! Recipient(testRecipientAddress, network: self.network.networkType),
|
||||
memo: try Memo(string: "test transaction"),
|
||||
from: 0)
|
||||
memo: try Memo(string: "test transaction")
|
||||
)
|
||||
pendingEntity = pending
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
|
|
|
@ -109,6 +109,8 @@ class BlockScanTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testScanValidateDownload() async throws {
|
||||
let seed = "testreferencealicetestreferencealice"
|
||||
|
||||
logger = SampleLogger(logLevel: .debug)
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
|
@ -123,10 +125,18 @@ class BlockScanTests: XCTestCase {
|
|||
return
|
||||
}
|
||||
|
||||
let uvks = try DerivationTool(networkType: .testnet).deriveUnifiedFullViewingKeys(seed: TestSeed().seed(), numberOfAccounts: 1)
|
||||
let derivationTool = DerivationTool(networkType: .testnet)
|
||||
let ufvk = try derivationTool
|
||||
.deriveUnifiedSpendingKey(seed: Array(seed.utf8), accountIndex: 0)
|
||||
.map { try derivationTool.deriveUnifiedFullViewingKey(from: $0) }
|
||||
|
||||
guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, ufvks: uvks, networkType: network.networkType) else {
|
||||
XCTFail("failed to init account table")
|
||||
|
||||
guard try self.rustWelding.initAccountsTable(
|
||||
dbData: self.dataDbURL,
|
||||
ufvks: [ufvk],
|
||||
networkType: network.networkType
|
||||
) else {
|
||||
XCTFail("failed to init account table. error: \(self.rustWelding.getLastError() ?? "no error found")")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
dataDbHandle.dispose()
|
||||
}
|
||||
|
||||
func testInitWithShortSeedAndFail() {
|
||||
func testInitWithShortSeedAndFail() throws {
|
||||
let seed = "testreferencealice"
|
||||
|
||||
var dbInit: DbInitResult!
|
||||
|
@ -46,58 +46,10 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
return
|
||||
}
|
||||
|
||||
_ = ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType)
|
||||
XCTAssertNotNil(ZcashRustBackend.getLastError())
|
||||
XCTAssertThrowsError(try ZcashRustBackend.createAccount(dbData: dbData!, seed: Array(seed.utf8), networkType: networkType))
|
||||
}
|
||||
|
||||
func testDeriveExtendedSpendingKeys() {
|
||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||
|
||||
var spendingKeys: [SaplingExtendedSpendingKey]?
|
||||
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveSaplingExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
|
||||
|
||||
XCTAssertNotNil(spendingKeys)
|
||||
XCTAssertEqual(spendingKeys?.count, 1)
|
||||
}
|
||||
|
||||
func testDeriveExtendedFullViewingKeys() {
|
||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||
|
||||
var fullViewingKeys: [SaplingExtendedFullViewingKey]?
|
||||
XCTAssertNoThrow(
|
||||
try {
|
||||
fullViewingKeys = try ZcashRustBackend.deriveSaplingExtendedFullViewingKeys(
|
||||
seed: seed,
|
||||
accounts: 2,
|
||||
networkType: networkType
|
||||
)
|
||||
}()
|
||||
)
|
||||
|
||||
XCTAssertNotNil(fullViewingKeys)
|
||||
XCTAssertEqual(fullViewingKeys?.count, 2)
|
||||
}
|
||||
|
||||
func testDeriveExtendedFullViewingKey() {
|
||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||
var fullViewingKey: SaplingExtendedFullViewingKey?
|
||||
|
||||
var spendingKeys: [SaplingExtendedSpendingKey]?
|
||||
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveSaplingExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
|
||||
|
||||
XCTAssertNotNil(spendingKeys)
|
||||
|
||||
guard let spendingKey = spendingKeys?.first else {
|
||||
XCTFail("no spending key generated")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertNoThrow(try { fullViewingKey = try ZcashRustBackend.deriveSaplingExtendedFullViewingKey(spendingKey, networkType: networkType) }())
|
||||
|
||||
XCTAssertNotNil(fullViewingKey)
|
||||
}
|
||||
|
||||
func testInitAndScanBlocks() {
|
||||
|
||||
func testInitAndScanBlocks() throws {
|
||||
guard let cacheDb = TestDbBuilder.prePopulatedCacheDbURL() else {
|
||||
XCTFail("pre populated Db not present")
|
||||
return
|
||||
|
@ -105,21 +57,36 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
let seed = "testreferencealicetestreferencealice"
|
||||
|
||||
var dbInit: DbInitResult!
|
||||
XCTAssertNoThrow(try { dbInit = try ZcashRustBackend.initDataDb(dbData: self.dbData!, seed: nil, networkType: self.networkType) }())
|
||||
XCTAssertNoThrow(try { dbInit = try ZcashRustBackend.initDataDb(dbData: self.dbData!, seed: Array(seed.utf8), networkType: self.networkType) }())
|
||||
|
||||
guard case .success = dbInit else {
|
||||
XCTFail("Failed to initDataDb. Expected `.success` got: \(String(describing: dbInit))")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
XCTAssertEqual(ZcashRustBackend.getLastError(), nil)
|
||||
let ufvks = [
|
||||
try DerivationTool(networkType: networkType).deriveUnifiedSpendingKey(seed: Array(seed.utf8), accountIndex: 0)
|
||||
.deriveFullViewingKey()
|
||||
|
||||
]
|
||||
guard try ZcashRustBackend.initAccountsTable(dbData: dbData!, ufvks: ufvks, networkType: networkType) else {
|
||||
XCTFail("failed with error: \(String(describing: ZcashRustBackend.lastError()))")
|
||||
return
|
||||
}
|
||||
XCTAssertNotNil(
|
||||
try ZcashRustBackend.createAccount(
|
||||
dbData: dbData!,
|
||||
seed: Array(seed.utf8),
|
||||
networkType: networkType
|
||||
)
|
||||
)
|
||||
XCTAssertEqual(ZcashRustBackend.getLastError(), nil)
|
||||
|
||||
XCTAssertNotNil(ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType))
|
||||
let addr = try ZcashRustBackend.getCurrentAddress(dbData: dbData!, account: 0, networkType: networkType)
|
||||
XCTAssertEqual(ZcashRustBackend.getLastError(), nil)
|
||||
|
||||
let addr = ZcashRustBackend.getAddress(dbData: dbData!, account: 0, networkType: networkType)
|
||||
XCTAssertEqual(ZcashRustBackend.getLastError(), nil)
|
||||
XCTAssertEqual(addr, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"))
|
||||
XCTAssertEqual(addr.saplingReceiver()?.stringEncoded, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"))
|
||||
|
||||
XCTAssertTrue(ZcashRustBackend.scanBlocks(dbCache: cacheDb, dbData: dbData, networkType: networkType))
|
||||
}
|
||||
|
@ -199,4 +166,74 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
XCTFail("Failed as invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func testListTransparentReceivers() throws {
|
||||
let testVector = [TestVector](TestVector.testVectors![0 ... 2])
|
||||
let network = NetworkType.mainnet
|
||||
let tempDBs = TemporaryDbBuilder.build()
|
||||
let seed = testVector[0].root_seed!
|
||||
let ufvk = try DerivationTool(networkType: network).deriveUnifiedSpendingKey(seed: seed, accountIndex: Int(testVector[0].account)).deriveFullViewingKey()
|
||||
|
||||
XCTAssertEqual(
|
||||
try ZcashRustBackend.initDataDb(
|
||||
dbData: tempDBs.dataDB,
|
||||
seed: seed,
|
||||
networkType: network
|
||||
),
|
||||
.success
|
||||
)
|
||||
|
||||
// XCTAssertTrue(
|
||||
// try ZcashRustBackend.initAccountsTable(
|
||||
// dbData: tempDBs.dataDB,
|
||||
// ufvks: [ufvk],
|
||||
// networkType: network
|
||||
// )
|
||||
// )
|
||||
XCTAssertNoThrow(
|
||||
try ZcashRustBackend.createAccount(
|
||||
dbData: tempDBs.dataDB,
|
||||
seed: seed,
|
||||
networkType: .mainnet
|
||||
)
|
||||
)
|
||||
|
||||
let expectedReceivers = testVector.map {
|
||||
UnifiedAddress(validatedEncoding: $0.unified_addr!)
|
||||
}
|
||||
.compactMap({ $0.transparentReceiver() })
|
||||
|
||||
|
||||
guard expectedReceivers.count >= 2 else {
|
||||
XCTFail("not enough transparent receivers")
|
||||
return
|
||||
}
|
||||
|
||||
for _ in [0 ... 2] {
|
||||
XCTAssertNoThrow(
|
||||
try ZcashRustBackend.getCurrentAddress(
|
||||
dbData: tempDBs.dataDB,
|
||||
account: 0,
|
||||
networkType: network
|
||||
)
|
||||
)
|
||||
|
||||
XCTAssertNoThrow(
|
||||
try ZcashRustBackend.getNextAvailableAddress(
|
||||
dbData: tempDBs.dataDB,
|
||||
account: 0,
|
||||
networkType: network
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(
|
||||
expectedReceivers,
|
||||
try ZcashRustBackend.listTransparentReceivers(
|
||||
dbData: tempDBs.dataDB,
|
||||
account: 0,
|
||||
networkType: network
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,15 @@ import XCTest
|
|||
class DerivationToolMainnetTests: XCTestCase {
|
||||
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
|
||||
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
|
||||
let testRecipientAddress = UnifiedAddress(validatedEncoding: "u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj", network: .mainnet) //TODO: Parameterize this from environment
|
||||
|
||||
let expectedSpendingKey = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv")
|
||||
|
||||
let testRecipientAddress = UnifiedAddress(validatedEncoding: "u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj") //TODO: Parameterize this from environment
|
||||
|
||||
let expectedSpendingKey = UnifiedSpendingKey(
|
||||
network: .mainnet,
|
||||
bytes: Data(base64Encoded: "tNDWwgMg8Tkw4YrTsuDcwFRcaL4E6xllYD/72MAFAWl0ozX9q+ICqQOUcMGPAAAAgGofH2hCmQcNq7zShy1FFKYcENBO+X4tO3z8AlMahG6xOZQS96NqNozvVSf/ZffZxqWY0U8z2mwcJF04DKv/ZQRVzmOebCbHjT1q3PR40S8qy6jNFMmiKUUCprPLexpgB1ziepyEZ9FXROg3qYIwsmhZn3jFyDQ1/00oCXO3K65bln5489aKWhnXnmo/2qoFcmntX15GRdBtUw50Wj6+iAsAQBgnnRntCLIa/wXB4KsvlPe21H9bTk24s27gb5/tIXOZNug65274BKRqcMVddG9ISBGT85GYg0BmOBVSIPt8ZvQ=")!.bytes,
|
||||
account: 0
|
||||
)
|
||||
|
||||
let expectedViewingKey = UnifiedFullViewingKey(validatedEncoding: "uview17fme6ux853km45g9ep07djpfzeydxxgm22xpmr7arzxyutlusalgpqlx7suga4ahzywfuwz4jclm00u7g8u65qvvdt45kttnfunvschssg3h3g06txs9ja32vx3xa8dej3unnatgzjvd0vumk37t8es3ludldrtse3q6226ws7eq4q0ywz78nudwpepgdn7jmxz8yvp7k6gxkeynkam0f8aqf9qpeaej55zhkw39x7epayhndul0j4xjttdxxlnwcd09nr8svyx8j0zng0w6scx3m5unpkaqxcm3hslhlfg4caz7r8d4xy9wm7klkg79w7j0uyzec5s3yje20eg946r6rmkf532nfydu26s8q9ua7mwxw2j2ag7hfcuu652gw6uta03vlm05zju3a9rwc4h367kqzfqrcz35pdwdk2a7yqnk850un3ujxcvve45ueajgvtr6dj4ufszgqwdy0aedgmkalx2p7qed2suarwkr35dl0c8dnqp3", account: 0)
|
||||
let expectedSaplingExtendedViewingKey = SaplingExtendedFullViewingKey(validatedEncoding: "zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy")
|
||||
|
||||
|
@ -23,52 +28,43 @@ class DerivationToolMainnetTests: XCTestCase {
|
|||
let derivationTool = DerivationTool(networkType: NetworkType.mainnet)
|
||||
let expectedTransparentAddress = TransparentAddress(validatedEncoding: "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz")
|
||||
func testDeriveViewingKeysFromSeed() throws {
|
||||
let accounts: Int = 1
|
||||
let seedBytes = [UInt8](seedData)
|
||||
let viewingKeys = try derivationTool.deriveUnifiedFullViewingKeys(seed: seedBytes, numberOfAccounts: accounts)
|
||||
|
||||
XCTAssertEqual(viewingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
|
||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||
|
||||
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||
|
||||
guard let viewingKey = viewingKeys.first else {
|
||||
XCTFail("no viewing key generated")
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(expectedViewingKey, viewingKey)
|
||||
|
||||
}
|
||||
|
||||
func testDeriveViewingKeyFromSpendingKeys() throws {
|
||||
XCTAssertEqual(expectedSaplingExtendedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
|
||||
XCTAssertEqual(
|
||||
expectedViewingKey,
|
||||
try derivationTool.deriveUnifiedFullViewingKey(from: expectedSpendingKey)
|
||||
)
|
||||
}
|
||||
|
||||
func testDeriveSpendingKeysFromSeed() throws {
|
||||
let accounts: Int = 1
|
||||
let seedBytes = [UInt8](seedData)
|
||||
|
||||
let spendingKeys = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: accounts)
|
||||
XCTAssertEqual(spendingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
|
||||
|
||||
guard let spendingKey = spendingKeys.first else {
|
||||
XCTFail("no viewing key generated")
|
||||
return
|
||||
}
|
||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||
|
||||
XCTAssertEqual(expectedSpendingKey, spendingKey)
|
||||
|
||||
}
|
||||
|
||||
func testDeriveUnifiedAddressFromSeed() throws {
|
||||
|
||||
func testDeriveUnifiedSpendingKeyFromSeed() throws {
|
||||
let account = 0
|
||||
let seedBytes = [UInt8](seedData)
|
||||
|
||||
let unifiedAddress = try derivationTool.deriveUnifiedAddress(seed: seedBytes, accountIndex: 0)
|
||||
XCTAssertEqual(unifiedAddress, testRecipientAddress)
|
||||
|
||||
XCTAssertNoThrow(try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: account))
|
||||
}
|
||||
|
||||
func testDeriveUnifiedAddressFromViewingKey() throws {
|
||||
XCTAssertEqual(try derivationTool.deriveUnifiedAddress(from: expectedViewingKey), testRecipientAddress)
|
||||
}
|
||||
|
||||
func testDeriveTransparentAddressFromSeed() throws {
|
||||
XCTAssertEqual(try derivationTool.deriveTransparentAddress(seed: [UInt8](seedData)), expectedTransparentAddress)
|
||||
|
||||
func testGetTransparentAddressFromUA() throws {
|
||||
XCTAssertEqual(
|
||||
try DerivationTool.transparentReceiver(from: testRecipientAddress),
|
||||
expectedTransparentAddress
|
||||
)
|
||||
}
|
||||
|
||||
func testIsValidViewingKey() throws {
|
||||
|
@ -77,24 +73,25 @@ class DerivationToolMainnetTests: XCTestCase {
|
|||
XCTAssertFalse(try derivationTool.isValidExtendedViewingKey("zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7"))
|
||||
}
|
||||
|
||||
func testDeriveTransparentAccountPrivateKeyFromSeed() throws {
|
||||
XCTAssertEqual(try derivationTool.deriveTransparentAccountPrivateKey(seed: [UInt8](seedData)), TransparentAccountPrivKey(encoding: "xprv9yCTU6giJ1qZ1DLC5rc7KMzwY9s8rSRXYqmoAKffAExpUVUKLhcdvN9ERdxjEW8tQq4pxerLKZE3WcNUKZCeX19rVTxpV2msTyNMNiFT3Nw"))
|
||||
}
|
||||
|
||||
func testDeriveUnifiedKeysFromSeed() throws {
|
||||
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 1)
|
||||
XCTAssertEqual(unifiedKeys.count, 1)
|
||||
|
||||
XCTAssertEqual(unifiedKeys[0].account, 0)
|
||||
XCTAssertEqual(unifiedKeys[0], expectedViewingKey)
|
||||
}
|
||||
|
||||
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
|
||||
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 10)
|
||||
XCTAssertEqual(unifiedKeys.count, 10)
|
||||
|
||||
XCTAssertEqual(unifiedKeys[0].account, 0)
|
||||
XCTAssertEqual(unifiedKeys[0], expectedViewingKey)
|
||||
let numberOfAccounts: Int = 10
|
||||
let ufvks = try (0 ..< numberOfAccounts)
|
||||
.map({
|
||||
try derivationTool.deriveUnifiedSpendingKey(
|
||||
seed: [UInt8](seedData),
|
||||
accountIndex: $0
|
||||
)
|
||||
|
||||
})
|
||||
.map {
|
||||
try derivationTool.deriveUnifiedFullViewingKey(
|
||||
from: $0
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(ufvks.count, numberOfAccounts)
|
||||
XCTAssertEqual(ufvks[0].account, 0)
|
||||
XCTAssertEqual(ufvks[0], expectedViewingKey)
|
||||
}
|
||||
|
||||
func testShouldFailOnInvalidChecksumAddresses() throws {
|
||||
|
@ -102,10 +99,6 @@ class DerivationToolMainnetTests: XCTestCase {
|
|||
XCTAssertFalse(try derivationTool.isValidTransparentAddress(testAddress))
|
||||
}
|
||||
|
||||
func testSpendingKeyValidation() throws {
|
||||
XCTAssertTrue(try derivationTool.isValidSaplingExtendedSpendingKey(expectedSpendingKey.stringEncoded))
|
||||
}
|
||||
|
||||
func testSpendingKeyValidationFailsOnInvalidKey() throws {
|
||||
let wrongSpendingKey = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vvZzZzZz"
|
||||
|
||||
|
|
|
@ -12,105 +12,103 @@ import XCTest
|
|||
class DerivationToolTestnetTests: XCTestCase {
|
||||
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
|
||||
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
|
||||
let testRecipientAddress = UnifiedAddress(validatedEncoding: "utest1uqmec4a2njqz2z2rwppchsd06qe7a0jh4jmsqr0yy99m9er9646zlxunf3v8qr0hncgv86e8a62vxy0qa32qzetmj8s57yudmyx9zav6f52nurclsqjkqtjtpz6vg679p6wkczpl2wu", network: .testnet) //TODO: Parameterize this from environment
|
||||
|
||||
let expectedSpendingKey = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-test1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6lk8xce3d4jw7s8ln5yjp6fqv2g0nzue2hc0kv5t004vklvlenncscq9flwh5vf5qnv0hnync72n7gjn70u47765v3kyrxytx50g730svvmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqe49swv")
|
||||
|
||||
let testRecipientAddress = UnifiedAddress(validatedEncoding: "utest1uqmec4a2njqz2z2rwppchsd06qe7a0jh4jmsqr0yy99m9er9646zlxunf3v8qr0hncgv86e8a62vxy0qa32qzetmj8s57yudmyx9zav6f52nurclsqjkqtjtpz6vg679p6wkczpl2wu") //TODO: Parameterize this from environment
|
||||
|
||||
let expectedSpendingKey = UnifiedSpendingKey(
|
||||
network: .testnet,
|
||||
bytes: Data(base64Encoded: "tNDWwgMg6xrWm9j+A47jcwGN5dh/XkFK6GKTy5TYam5Y8UF6o+kCqQNMS2+dAAAAgAiJqYeoNR3c8a4CGf86m/5GnI0AUAInWtAQ5HAKsbr9jmxmLayd6B/zoSQdJAxSHzFzKr4fZlFvfVlvs/mc8QwAqfuvRiaAmx95knjyp+RKfn8r72qMjYgzEWaj0ei+DGbvf/RToOR9wvevnpsPYkVN0dxg+RCDpqfUX+5K82uvByr+a0STltGka9zx5AiUuSBi/gC+rid7L5P123xTQ+AAQAJO8vbUxpLCW2IvT1HEYhBOtKJDvC1Wp+wmBUmTmhG1aw/JybD+N5IY6PgiY2fiU43KI7tW9HZAlQTKitT+9m8=")!.bytes,
|
||||
account: 0
|
||||
)
|
||||
|
||||
let expectedViewingKey = UnifiedFullViewingKey(validatedEncoding: "uviewtest12tkgzhaevmw78us4xj2cx6ehxjgpp5da2qwrjqvytztejqfjdmy3e6nryqggtwrjum5cefuuuky8rscuw5dynmjec2tx3kkupqexw4va879pf874kvp6r8kjeza26gysxllaqwl67hm9u0jjke06zc93asrpw4wmy3g0lr9r5cy9pz49q2g7y7wm2pls5akmzhuvqr7khftk93aa2kpvwp7n3sjtmef28mxg3n2rpctsjlgsrhc29g6r23qc0u4tzd8rz8vqq4j7jxummdts8zx0jatzw4l2tl7r3egxhlw587rtkjx0y6dvw4hf4vjprn0qv3hs0sulmavk84ajeewn7argyerpr4essqvgfd0d24jpz6phxlasnd58qazh9d3yc6ad3hc5atp0pkvlq053zga65gscp0pv2plhqj9y2tcmx43thw5g4v8z3unytkc2dhyttuhmnlh5dyz4rmhgfkc96tp8z8rpfe35whjvky0jagz5n7qx", account: 0)
|
||||
|
||||
let expectedSaplingExtendedViewingKey = SaplingExtendedFullViewingKey(validatedEncoding: "zxviewtestsapling1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6l5smlqrckkl2x5rnrauzc4gp665q3zyw0qf2sfdsx5wpp832htfavqk72uchuuvq2dpmgk8jfaza5t5l56u66fpx0sr8ewp9s3wj2txavmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqgegsaj")
|
||||
|
||||
let expectedSaplingAddress = SaplingAddress(validatedEncoding: "ztestsapling1475xtm56czrzmleqzzlu4cxvjjfsy2p6rv78q07232cpsx5ee52k0mn5jyndq09mampkgvrxnwg")
|
||||
|
||||
|
||||
let derivationTool = DerivationTool(networkType: NetworkType.testnet)
|
||||
let expectedTransparentAddress = TransparentAddress(validatedEncoding: "tmXuTnE11JojToagTqxXUn6KvdxDE3iLKbp")
|
||||
|
||||
func testDeriveViewingKeysFromSeed() throws {
|
||||
let accounts: Int = 1
|
||||
let seedBytes = [UInt8](seedData)
|
||||
let viewingKeys = try derivationTool.deriveUnifiedFullViewingKeys(seed: seedBytes, numberOfAccounts: accounts)
|
||||
|
||||
XCTAssertEqual(viewingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
|
||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||
|
||||
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||
|
||||
guard let viewingKey = viewingKeys.first else {
|
||||
XCTFail("no viewing key generated")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(expectedViewingKey, viewingKey)
|
||||
}
|
||||
|
||||
|
||||
func testDeriveViewingKeyFromSpendingKeys() throws {
|
||||
XCTAssertEqual(expectedSaplingExtendedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
|
||||
// XCTAssertEqual(
|
||||
// expectedViewingKey,
|
||||
// try derivationTool.deriveUnifierFullViewingKey(from: expectedSpendingKey)
|
||||
// )
|
||||
}
|
||||
|
||||
|
||||
func testDeriveSpendingKeysFromSeed() throws {
|
||||
let accounts: Int = 1
|
||||
let seedBytes = [UInt8](seedData)
|
||||
|
||||
let spendingKeys = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: accounts)
|
||||
XCTAssertEqual(spendingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
|
||||
|
||||
guard let spendingKey = spendingKeys.first else {
|
||||
XCTFail("no viewing key generated")
|
||||
return
|
||||
}
|
||||
|
||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||
|
||||
XCTAssertEqual(expectedSpendingKey, spendingKey)
|
||||
|
||||
}
|
||||
|
||||
func testDeriveUnifiedAddressFromSeed() throws {
|
||||
|
||||
func testDeriveUnifiedSpendingKeyFromSeed() throws {
|
||||
let account = 0
|
||||
let seedBytes = [UInt8](seedData)
|
||||
|
||||
let unifiedAddress = try derivationTool.deriveUnifiedAddress(seed: seedBytes, accountIndex: 0)
|
||||
XCTAssertEqual(unifiedAddress, testRecipientAddress)
|
||||
}
|
||||
|
||||
func testDeriveUnifiedAddressFromViewingKey() throws {
|
||||
XCTAssertEqual(try derivationTool.deriveUnifiedAddress(from: expectedViewingKey), testRecipientAddress)
|
||||
}
|
||||
|
||||
func testDeriveTransparentAddressFromSeed() throws {
|
||||
XCTAssertEqual(try derivationTool.deriveTransparentAddress(seed: [UInt8](seedData)), expectedTransparentAddress)
|
||||
}
|
||||
|
||||
func testIsValidViewingKey() throws {
|
||||
XCTAssertTrue(try derivationTool.isValidExtendedViewingKey(self.expectedSaplingExtendedViewingKey.stringEncoded))
|
||||
|
||||
XCTAssertFalse(try derivationTool.isValidExtendedViewingKey("zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy"))
|
||||
}
|
||||
|
||||
func testDeriveTransparentAccountPrivateKeyFromSeed() throws {
|
||||
XCTAssertEqual(try derivationTool.deriveTransparentAccountPrivateKey(seed: [UInt8](seedData)), TransparentAccountPrivKey(encoding: "xprv9yURYog8Ds8XB36PVzPadbVaCPwVm4CZVMejW9bPPTqBCY8oLssPbe1MhJhPzSbVeg7cWZtuXxuUy2urADuAJUaN27c5f9nErx68SQokG1b"))
|
||||
}
|
||||
|
||||
func testDeriveUnifiedKeysFromSeed() throws {
|
||||
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 1)
|
||||
XCTAssertEqual(unifiedKeys.count, 1)
|
||||
|
||||
XCTAssertEqual(unifiedKeys[0].account, 0)
|
||||
XCTAssertEqual(unifiedKeys[0], expectedViewingKey)
|
||||
}
|
||||
|
||||
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
|
||||
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 10)
|
||||
XCTAssertEqual(unifiedKeys.count, 10)
|
||||
|
||||
XCTAssertEqual(unifiedKeys[0].account, 0)
|
||||
XCTAssertEqual(unifiedKeys[0], expectedViewingKey)
|
||||
|
||||
XCTAssertNoThrow(try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: account))
|
||||
}
|
||||
|
||||
func testSpendingKeyValidation() throws {
|
||||
XCTAssertTrue(try derivationTool.isValidSaplingExtendedSpendingKey(expectedSpendingKey.stringEncoded))
|
||||
func testGetTransparentAddressFromUA() throws {
|
||||
XCTAssertEqual(
|
||||
try DerivationTool.transparentReceiver(from: testRecipientAddress),
|
||||
expectedTransparentAddress
|
||||
)
|
||||
}
|
||||
|
||||
func testIsValidViewingKey() throws {
|
||||
XCTAssertTrue(try derivationTool.isValidExtendedViewingKey("zxviewtestsapling1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6l5smlqrckkl2x5rnrauzc4gp665q3zyw0qf2sfdsx5wpp832htfavqk72uchuuvq2dpmgk8jfaza5t5l56u66fpx0sr8ewp9s3wj2txavmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqgegsaj"))
|
||||
|
||||
XCTAssertFalse(try derivationTool.isValidExtendedViewingKey("zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7"))
|
||||
}
|
||||
|
||||
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
|
||||
let numberOfAccounts: Int = 10
|
||||
let ufvks = try (0 ..< numberOfAccounts)
|
||||
.map({
|
||||
try derivationTool.deriveUnifiedSpendingKey(
|
||||
seed: [UInt8](seedData),
|
||||
accountIndex: $0
|
||||
)
|
||||
|
||||
})
|
||||
.map {
|
||||
try derivationTool.deriveUnifiedFullViewingKey(
|
||||
from: $0
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(ufvks.count, numberOfAccounts)
|
||||
XCTAssertEqual(ufvks[0].account, 0)
|
||||
XCTAssertEqual(ufvks[0], expectedViewingKey)
|
||||
}
|
||||
|
||||
func testShouldFailOnInvalidChecksumAddresses() throws {
|
||||
let testAddress = "t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1"
|
||||
XCTAssertFalse(try derivationTool.isValidTransparentAddress(testAddress))
|
||||
}
|
||||
|
||||
func testSpendingKeyValidationFailsOnInvalidKey() throws {
|
||||
let wrongSpendingKey = "secret-extended-key-test1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vvZzZzZz"
|
||||
let wrongSpendingKey = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vvZzZzZz"
|
||||
|
||||
XCTAssertFalse(try derivationTool.isValidSaplingExtendedSpendingKey(wrongSpendingKey))
|
||||
}
|
||||
|
||||
// TODO: Address encoding does not catch this test https://github.com/zcash/ZcashLightClientKit/issues/509
|
||||
// func testSpendingKeyValidationThrowsWhenWrongNetwork() throws {
|
||||
// XCTAssertThrowsError(try derivationTool.isValidExtendedSpendingKey("secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv"))
|
||||
// XCTAssertThrowsError(try derivationTool.isValidExtendedSpendingKey("secret-extended-key-test1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6lk8xce3d4jw7s8ln5yjp6fqv2g0nzue2hc0kv5t004vklvlenncscq9flwh5vf5qnv0hnync72n7gjn70u47765v3kyrxytx50g730svvmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqe49swv"))
|
||||
// }
|
||||
}
|
||||
|
||||
|
|
|
@ -57,10 +57,10 @@ class NullBytesTests: XCTestCase {
|
|||
}
|
||||
|
||||
switch rustError {
|
||||
case .malformedStringInput:
|
||||
case .invalidInput:
|
||||
XCTAssertTrue(true)
|
||||
default:
|
||||
XCTFail("expected \(RustWeldingError.malformedStringInput) and got \(rustError)")
|
||||
XCTFail("expected \(RustWeldingError.invalidInput) and got \(rustError)")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,39 +81,41 @@ class NullBytesTests: XCTestCase {
|
|||
}
|
||||
|
||||
switch rustError {
|
||||
case .malformedStringInput:
|
||||
case .invalidInput:
|
||||
XCTAssertTrue(true)
|
||||
default:
|
||||
XCTFail("expected \(RustWeldingError.malformedStringInput) and got \(rustError)")
|
||||
XCTFail("expected \(RustWeldingError.invalidInput) and got \(rustError)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testderiveExtendedFullViewingKeyWithNullBytes() throws {
|
||||
// swiftlint:disable:next line_length
|
||||
let wrongSpendingKeys = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mq\0uy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv") // this spending key corresponds to the "demo app reference seed"
|
||||
|
||||
// swiftlint:disable:next line_length
|
||||
let goodSpendingKeys = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv")
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try ZcashRustBackend.deriveSaplingExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),
|
||||
"Should have thrown an error but didn't! this is dangerous!"
|
||||
) { error in
|
||||
guard let rustError = error as? RustWeldingError else {
|
||||
XCTFail("Expected RustWeldingError")
|
||||
return
|
||||
}
|
||||
|
||||
switch rustError {
|
||||
case .malformedStringInput:
|
||||
XCTAssertTrue(true)
|
||||
default:
|
||||
XCTFail("expected \(RustWeldingError.malformedStringInput) and got \(rustError)")
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertNoThrow(try ZcashRustBackend.deriveSaplingExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
|
||||
// TODO: fix
|
||||
// // swiftlint:disable:next line_length
|
||||
// let wrongSpendingKeys = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mq\0uy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv") // this spending key corresponds to the "demo app reference seed"
|
||||
//
|
||||
// // swiftlint:disable:next line_length
|
||||
// let goodSpendingKeys = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv")
|
||||
//
|
||||
// XCTAssertThrowsError(
|
||||
// try ZcashRustBackend.deriveSaplingExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),
|
||||
// "Should have thrown an error but didn't! this is dangerous!"
|
||||
// ) { error in
|
||||
// guard let rustError = error as? RustWeldingError else {
|
||||
// XCTFail("Expected RustWeldingError")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// switch rustError {
|
||||
// case .malformedStringInput:
|
||||
// XCTAssertTrue(true)
|
||||
// default:
|
||||
// XCTFail("expected \(RustWeldingError.malformedStringInput) and got \(rustError)")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// XCTAssertNoThrow(try ZcashRustBackend.deriveSaplingExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
|
||||
}
|
||||
|
||||
func testCheckNullBytes() throws {
|
||||
|
|
|
@ -15,7 +15,7 @@ final class RecipientTests: XCTestCase {
|
|||
let transparentString = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz"
|
||||
|
||||
func testUnifiedRecipient() throws {
|
||||
let expectedUnifiedAddress = UnifiedAddress(validatedEncoding: uaString, network: .mainnet)
|
||||
let expectedUnifiedAddress = UnifiedAddress(validatedEncoding: uaString)
|
||||
|
||||
XCTAssertEqual(try Recipient(uaString, network: .mainnet), .unified(expectedUnifiedAddress))
|
||||
}
|
||||
|
|
|
@ -1,220 +1,73 @@
|
|||
////
|
||||
//// UnifiedTypecodesTests.swift
|
||||
//// OfflineTests
|
||||
////
|
||||
//// Created by Francisco Gindre on 9/14/22.
|
||||
////
|
||||
//
|
||||
// UnifiedTypecodesTests.swift
|
||||
// OfflineTests
|
||||
//import XCTest
|
||||
//@testable import ZcashLightClientKit
|
||||
//final class UnifiedTypecodesTests: XCTestCase {
|
||||
//
|
||||
// Created by Francisco Gindre on 9/14/22.
|
||||
// func testVectorBuilding() throws {
|
||||
// guard let testVectors = TestVector.hexStringtestVectors else {
|
||||
// XCTFail("fail to construct vectors")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
final class UnifiedTypecodesTests: XCTestCase {
|
||||
|
||||
func testVectorBuilding() throws {
|
||||
guard let testVectors = UnifiedAddress.testVectors else {
|
||||
XCTFail("fail to construct vectors")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(testVectors.count, 20)
|
||||
}
|
||||
|
||||
func testUnifiedAddressHasTransparentSaplingReceiversBackend() throws {
|
||||
guard let testVectors = UnifiedAddress.testVectors,
|
||||
let firstVector = testVectors.first,
|
||||
let seed = firstVector.root_seed else {
|
||||
XCTFail("fail to construct vectors")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let address = try DerivationTool(networkType: .mainnet).deriveUnifiedAddress(seed: seed, accountIndex: Int(firstVector.account))
|
||||
|
||||
let typecodes = try ZcashRustBackend.receiverTypecodesOnUnifiedAddress(address.stringEncoded)
|
||||
|
||||
XCTAssertEqual(Set(typecodes), Set([0x00, 0x02]))
|
||||
|
||||
}
|
||||
|
||||
func testUnifiedAddressHasTransparentSaplingReceivers() throws {
|
||||
guard let testVectors = UnifiedAddress.testVectors,
|
||||
let firstVector = testVectors.first,
|
||||
let seed = firstVector.root_seed else {
|
||||
XCTFail("fail to construct vectors")
|
||||
return
|
||||
}
|
||||
|
||||
let tool = DerivationTool(networkType: .mainnet)
|
||||
let address = try tool.deriveUnifiedAddress(seed: seed, accountIndex: Int(firstVector.account))
|
||||
|
||||
let typecodes = try tool.receiverTypecodesFromUnifiedAddress(address)
|
||||
|
||||
XCTAssertEqual(
|
||||
Set<UnifiedAddress.ReceiverTypecodes>(typecodes),
|
||||
Set([UnifiedAddress.ReceiverTypecodes.p2pkh, .sapling])
|
||||
)
|
||||
}
|
||||
|
||||
func testReceiverTypecodes() {
|
||||
XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x00), .p2pkh)
|
||||
XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x01), .p2sh)
|
||||
XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x02), .sapling)
|
||||
XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x03), .orchard)
|
||||
XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x0F), .unknown(0x0F))
|
||||
}
|
||||
|
||||
func testExtractTypecode() throws {
|
||||
let ua = UnifiedAddress(validatedEncoding: "u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj", network: .mainnet)
|
||||
XCTAssertEqual(try ua.availableReceiverTypecodes(), [.sapling, .p2pkh])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
extension UnifiedAddress {
|
||||
/// Test vectors for unified addresses
|
||||
/// Original file can be found here https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/test-vectors/json/unified_address.json
|
||||
/// Note: These vectors can't be used as-is since we are missing derivation functions that take a DiversifiedIndex
|
||||
static var testVectors: [TestVector]? {
|
||||
var vectors = [TestVector]()
|
||||
for rawVector in UnifiedAddress.testVector.dropFirst(2) {
|
||||
guard let vector = TestVector(from: rawVector) else {
|
||||
return nil
|
||||
}
|
||||
vectors.append(vector)
|
||||
}
|
||||
|
||||
return vectors
|
||||
}
|
||||
|
||||
static let testVector: [[Any?]] =
|
||||
[
|
||||
["From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/unified_address.py"],
|
||||
["p2pkh_bytes, p2sh_bytes, sapling_raw_addr, orchard_raw_addr, unknown_typecode, unknown_bytes, unified_addr, root_seed, account, diversifier_index"],
|
||||
["e6cabf813929132d772d04b03ae85223d03b9be8", nil, nil, "d4714ee761d1ae823b6972152e20957fefa3f6e3129ea4dfb0a9e98703a63dab929589d6dc51c970f935b3", 65533, "f6ee6921481cdd86b3cc4318d9614fc820905d042bb1ef9ca3f24988c7b3534201cfb1cd8dbf69b8250c18ef41294ca97993db546c1fe0", "753179793677386e336a6d6a73676a39777663656e7238723570366833387679636c686d71307767396b7a70786c7534367a387636346b3567737a72387966777a346a7672796c76766733673633337a30326c756b38356e6d73636b366432736578336e3564376b6e3638687a7a3574763475647439703673793770676c6565756c76676c767832363237646666353771396665703577676478386d3065737832386d307a767578706d7779617a74336a756e3272707177386e75366a326663657167686b353563656436366a73366b366a786e387932787475653866337061716a726b3871366e70746e6e", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 0],
|
||||
["7bec9de217c04f7ce1a86f1fb458aa881c8f39e4", nil, nil, "d8e5ecb4e005c28718e61a5c336a4f369e771ccdb3363f4f7a04b02a966901a4c05da662d5fd75678f7fb4", 65530, nil, "75317a35677538783364766b7677636d726a30716b3568727839706361646c3536683834663777647970366e7635337233643563636365646563686d77393835746765357733633272353639716137326c676775753578727178683739616a7a63376b716d65733230706b747a71726a6c707835367168676d716d3536686e39777432686379787064616d616b", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 1, 0],
|
||||
["aa6d43480fd9d91375ce6c4a020706361bd296de", nil, "88533c398a49c2513dc85162bf220abaf47dc983f14e908ddaaa7322dba16531bc62efe750fe575c8d149b", nil, 65530, nil, "7531343367706a3772643934766d39356d7a73757537746a74716161677934706d6678386c6b77656d70786a7463777a33357a746361383530796e6c7a323932307477617a6171703270367168787878337a357178616b6e73716372676c7578716a337070757367776635757963686c61677938376b376874613768773965793336776d7930367065776c6470", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 2, 0],
|
||||
[nil, "a8d7551db5fd9313e8c7203d996af7d477083756", "52fd6aedefbf401633c2e4532515ebcf95bcc2b4b8e4d676dfad7e17925c6dfb8671e52544dc2ca075e261", nil, 65534, nil, "753178797970646a307a7978637466666b6878796d766a6e6b376e383371666c376e7365356c3071726b346e3266376465376c3733727a79787970347463727975356d6b7875617a6c646e633279306479747a7567797a79636739373034616a66786173376b63757761776d706877776e383839743938743735376579716667346a766566746b687672337167", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 3, 0],
|
||||
[nil, "f44ab023752cb5b406ed8985e18130ab33362697", nil, "165082de84f2ad7204426ffafd6b6c7de9cab6d25c13846a1786715268c415948db788f4a5e0daa03d699e", 65533, nil, "7531706a336c72656d6e7175737368393878667161336a66647077303872726b35377330346b6c32366865707a7133746a72736e78653574367371716567653976716d776c63366c786373746e6333306e3575357232776b6b7a687039367a3564306a797530716137746b686378366663386a35396b616b387a35636570363261716d61336d36343566683863", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 4, 0],
|
||||
[nil, nil, nil, "ea9df83fbee07d6f7895ebb2ea41ec7c4ba682b863e069b4a438e31c9571c83126c305d75456412aeaef1b", 65531, nil, "753132787567643930666c726b646b6575336e6c6e6e337565736b793533707175356d323479366170786d38386d34387637333734636c7335367a7039336e61796c617864636866307161796678747267653034376d393533717a3376326772346c74737232736b3372", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 5, 0],
|
||||
[nil, nil, nil, "3c40246912b6efefab9a55244ac2c174e1a9f8c0bc0fd526933963c6ecb9b84ec8b0f6b40dc858fa23c72b", 65530, nil, "75317370757467353667736a763233637435346d7277646c616e7a7665716337747a73356d78786e616135636465676d303368673778363661797079647336356d39327674397561786c3637327375687063367a3768747776657079686b727066757376617a71756539", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 6, 0],
|
||||
[nil, "defa3d5a57efc2e1e9b01a035587d5fb1a38e01d", nil, "cc099cc214e56b1192c7b5b17e958c3413e27fefd553380700aca81b24b2918cac951a1a68017fac525a18", 65535, nil, "75317667736b636d3939783567687561757668337978713777747037756e366130793663617964736e6e33357032647577707773356873367079676a6877703738326a716e65727a6c6878773370343971666d713237383339716a7472667976686b377964393877396e3064366a6e7336756834666333687364663736366b6e74716e6c6a646b64353667636e", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 7, 0],
|
||||
[nil, nil, nil, "5f09a9807a56323b263b05df368dc28391b21a64a0e1b40f9a6803b7e68f3905923f35cb01f119b223f493", 65530, nil, "75316378636379656d6d3038747964776d743968703273356e6638776a766c757575366c32653861396a666c6c647861736e7a6b6438667665727170636a30786e767261637a71673235356377356e767936783977727566666d703975657a727a72376763783535396b", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 8, 0],
|
||||
[nil, "10acd20b183e31d49f25c9a138f49b1a537edcf0", "9b60ae3d302248b349d601567e3d7795bfb334ea1fd1a7e71402169ebbe14bd2ceaa244ccd6e5aa2245613", "e340636542ece1c81285ed4eab448adbb5a8c0f4d386eeff337e88e6915f6c3ec1b6ea835a88d56612d2bd", 65531, nil, "75317a656b68686d686b353478356365356333367274376e63323735676570376e6176326e73783473683061666c6c75703976726835687338367a38736b6a746436646e736c7667736d6174743068386832343763676e666b73646c776c39786d617275797570666c743064716673637830647979656d3266616139776571653378616b397736656672353437636a3832397232746e7974613032687866647873646a6d76397a72356b746b70323066706378656164686672683032616b346136686e7876357336377267717272766670646a7435", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 9, 0],
|
||||
[nil, "af9db6990ed83dd64af3597c04323ea51b0052ad", nil, "cdf7fed0d0822fd849cffb20a4d5ee701ad8141e66d81ddfabf87875117c05092240603c546b8dc187cd8c", 65532, nil, "753165353471636e30746570796c33307a7a326672677a37713461366d736e326530326e7076326e6666736433683532336d747838643232616a7666767371757235736a7a3876666e6d77327973363730387170386b6139306a3561343330757938763833616c6a63306330357a6a7535347879356e7677336d66686b376e7737366b6b7964796c713466656c", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 10, 0],
|
||||
[nil, nil, nil, "24fd59f32b2d39dde66e46c39206a31bc04fa5c6847976ea6bbd3163ee14f58f584acc131479ea558d3f84", 65530, nil, "75317a38777372686d66366d3967766136766c33737a636b303670393730783577686d36336a666a3266726d6d63396e39756d34796373387975746a37673833387672676832306c667879353279306832367474386e6776643267796370797176396b793032716b6373", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 11, 0],
|
||||
[nil, nil, "78d85bd0db639043377987cdd814c6390016964b684016faf1ad4f166c5f72399a5e8d469ec6beb873d55d", nil, 65535, nil, "75317861686a333570376d7639756c6b3337327333766465687172663438753077646633786c3772787a7270653461307468753864306d396d7961617078376b35767836747a357074636a76637675346472667137753771777a6d667565336b74387376736333736535", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 12, 0],
|
||||
["33a6dd87b4d872a4895d345761e4ec423b77928d", nil, nil, "5178924f7067eac261044ca27ba3cf52f798486973af0795e61587aa1b1ecad333dc520497edc61df88980", 65533, "91e00c7a1d48af046827591e9733a97fa6b679f3dc601d008285edcbdae69ce8fc1be4aac00ff2711ebd931de518856878f73476f21a482ec9378365c8f7393c94e2885315eb4671098b79535e790fe53e29fef2b3766697ac32b4f473f468a008e72389fc03880d780cb07fcfaabe3f1a84b27db59a4a153d882d2b2103596555ed9494c6ac893c49723833ec8926c1", "7531687970706c733364776d616c783373756c746b72397564763237376679716a6478307378716c746638676a6e777976343968743575327270336c6c767632756e796d7330383675616a6b6638393837636175616a7136383670356638687276393474616336663078796637796d7a3636747279366b7936726179336d6a633567786661683030637370766b3564676d67736e3737663274336775763270307861366b6c6138717479376d6b6e6b6d337a68303932306c77733633326166743071686b3532363579736c337067323237747866373461736d7075656e326c746533616a6330667a376b34736878797a656d6e7035773770336b746c6874643030366d6b61787979306d746637646a73646175397a666b657332616e387661687a6737647173677938326330707830396d39683061657a736e7936786c66706767667268656d7661786a3578747871356a6e67763076306167726c3073757079676639636574656a35323779727a7a6574386471747164616771", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 13, 0],
|
||||
["a56c057ef71dab58aa90e47025695c5faaea5123", nil, "a75a6de421d2ad1ee8f4b25e398adda9c0aaa6ab1f2518981a9ddb1de6a3957d77842332d6289dbe94e832", "b208c9235c8d40e49b76100b2d010f3783f12c66e7d3beb117b2c96321b7f6562adb4efc144e39d909e728", 65533, nil, "7531646670723876647335683361756e79657a7a7877726d38756461353273743837733876726c676732746730357430713070783336686368783974676b786b6c77747370753332786a6135617271336b7470326e387a613470773779776a30676d68713372776539353072386b3973756e736a76773734743538716c3333347065673464766b616c6b746d6e676e716b7077723332353837653779747932376e6d673636747371377976723779343639776570366b7077346a3530786e6c6d78306a78786737766c6735796c6671387566657664", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 14, 0],
|
||||
[nil, nil, nil, "9e5445d6cd3cb9f98b0df1062bda47adffd5a66c0c2c483c8bf15c3176d755914a3576496b5c35fee28a88", 65531, nil, "75316a676c686a326d617936646674777a39753271796e786a717a6e75743637343768617375306d646d6c63303266636173756178756764797a776a326c38346d6a3966677a6a3779306b396663706a373336736c6d6a38676b37377567386c6c61766367326c666d6d", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 15, 0],
|
||||
["b02aec10f6fa02a08667bf9b924c3d0574a1334f", nil, nil, "2598d84dffb34f5908b90732490f3881399150d4c694fce9bf30d1560b2c56f09829fe123b9add20e5d71c", 65534, nil, "7531397163617a647761793438707566366a77616a78307732386d307871756d746d6e6435677974796c6c6e79676867396c76393978356d3872387439673566396a307a30786e34787a6d6e7866747a3772746633756164786b79367178706e6b7438666b66686c78386b63396d6e72646c6e7874733536786378656a7a6472776c65787a7637377876797634", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 16, 0],
|
||||
[nil, nil, "d3a803803feee7a032a24adfaa8f6a94cecb9671c1333d0d5d1a3d79d82bc310727c665364d71022559c50", "7c98b8f613f9ff02746bea2a167cfd1bd3a1862af9631bf61d9d604e0824e2cb8467a1e549db87a76e7a8a", 65535, nil, "75316136346c303971727378756c666a7a6e6d366b326735333575737968746166386564363076346a726a6d6b77766b757834743770647963336e6b7a7265666467746e77383432306c6a3873686d30356a6139667878676e68726139326e6873713536677838633270757a33666b6b676e726b7166357975716664746637743672616e343767646366357676646661637a7766337575793466797368336d7a7538686435746b6c30356d76726765396e38", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 17, 0],
|
||||
["26c061d67beb8bad48c6b4774a156551e30e4fe2", nil, nil, "a80405d5568ab8ab8f8546163d951ab297fd5e6f43e7fcebcb664feacfab5afd80aaf7f354c07a9901788c", 65535, nil, "7531787a757764386163686667776d336577793976326d6a3537373268726b6e6d6578777a6339346d7a6133356d78363863656e767877727a3973396670306e39767a753872756a357a71666d6d376c65387775366c363275346c6d30376e75717865656d383733677838366a766e776c70787379636c397576366b786b72686d30726c677037307830357366", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 18, 0],
|
||||
[nil, nil, "8660070e3757ff6507060791fd694f6a631b8495a2b74ffa39236cf653caea5575b86af3200b010e513bab", "63b7b706d991169986aee56133f0a50b2a0c8225fba6dae95176007b1f023a1e97c1aa366e99bf970fda82", 65534, nil, "7531766736326d676a64646e6c763577366c646b793278653063387465746d633832747539766c7a7a6b75796e783439666e75716a76786a743564676e33636d3874356e38357a6371356c6a727467377a6d77686b3730683672646d636c6637736378786e67756b35666c76663261707037367875393037636d6a796c787673656e3235786539763776336b727378613975793076326a6a7133376b6834796d6c61666e3870657671616c716134646d3637", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 19, 5]
|
||||
]
|
||||
|
||||
struct TestVector {
|
||||
enum Indices: Int, CaseIterable {
|
||||
case p2pkh_bytes = 0
|
||||
case p2sh_bytes
|
||||
case sapling_raw_addr
|
||||
case orchard_raw_addr
|
||||
case unknown_typecode
|
||||
case unknown_bytes
|
||||
case unified_addr
|
||||
case root_seed
|
||||
case account
|
||||
case diversifier_index
|
||||
}
|
||||
|
||||
var p2pkh_bytes: [UInt8]?
|
||||
var p2sh_bytes: [UInt8]?
|
||||
var sapling_raw_addr: [UInt8]?
|
||||
var orchard_raw_addr: [UInt8]?
|
||||
var unknown_typecode: UInt32 = UInt32.max
|
||||
var unknown_bytes: [UInt8]?
|
||||
var unified_addr: [UInt8]?
|
||||
var root_seed: [UInt8]?
|
||||
var account: UInt32 = 0
|
||||
var diversifier_index: UInt32 = 0
|
||||
|
||||
static func optionalByteArrayKeyPath(from index: Indices) -> WritableKeyPath<TestVector, [UInt8]?>? {
|
||||
switch index {
|
||||
case .p2pkh_bytes:
|
||||
return \Self.p2pkh_bytes
|
||||
case .p2sh_bytes:
|
||||
return \Self.p2sh_bytes
|
||||
case .sapling_raw_addr:
|
||||
return \Self.sapling_raw_addr
|
||||
case .orchard_raw_addr:
|
||||
return \Self.orchard_raw_addr
|
||||
case .unknown_bytes:
|
||||
return \Self.unknown_bytes
|
||||
case .unified_addr:
|
||||
return \Self.unified_addr
|
||||
case .root_seed:
|
||||
return \Self.root_seed
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func uintKeyPath(from index: Indices) -> WritableKeyPath<TestVector, UInt32>? {
|
||||
switch index {
|
||||
case .unknown_typecode:
|
||||
return \Self.unknown_typecode
|
||||
case .account:
|
||||
return \Self.account
|
||||
case .diversifier_index:
|
||||
return \Self.diversifier_index
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
init?(from rawVector: [Any?]) {
|
||||
guard rawVector.count == Indices.diversifier_index.rawValue + 1 else { return nil }
|
||||
|
||||
for varIndex in Indices.allCases {
|
||||
switch varIndex {
|
||||
case .p2pkh_bytes,
|
||||
.p2sh_bytes,
|
||||
.sapling_raw_addr,
|
||||
.orchard_raw_addr,
|
||||
.unknown_bytes,
|
||||
.unified_addr,
|
||||
.root_seed:
|
||||
|
||||
guard let keyPath = Self.optionalByteArrayKeyPath(from: varIndex) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rawVector[varIndex.rawValue] == nil {
|
||||
self[keyPath: keyPath] = nil
|
||||
break
|
||||
}
|
||||
|
||||
guard let hexString = rawVector[varIndex.rawValue] as? String,
|
||||
let data = Data(fromHexEncodedString: hexString) else { return nil }
|
||||
|
||||
self[keyPath: keyPath] = data.bytes
|
||||
|
||||
case .unknown_typecode,
|
||||
.account,
|
||||
.diversifier_index:
|
||||
|
||||
guard rawVector[varIndex.rawValue] != nil else { return nil }
|
||||
|
||||
guard let keyPath = Self.uintKeyPath(from: varIndex) else { return nil }
|
||||
|
||||
guard let optionalValue = rawVector[varIndex.rawValue],
|
||||
let intValue = optionalValue as? Int,
|
||||
let uintValue = UInt32(exactly: intValue) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self[keyPath: keyPath] = uintValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// XCTAssertEqual(testVectors.count, 60)
|
||||
// }
|
||||
//
|
||||
// func testUnifiedAddressHasTransparentSaplingReceiversBackend() throws {
|
||||
// guard let testVectors = TestVector.testVectors,
|
||||
// let firstVector = testVectors.first,
|
||||
// let uAddress = firstVector.unified_addr else {
|
||||
// XCTFail("fail to construct vectors")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
//
|
||||
// let address = UnifiedAddress(validatedEncoding: uAddress)
|
||||
//
|
||||
// let typecodes = try ZcashRustBackend.receiverTypecodesOnUnifiedAddress(address.stringEncoded)
|
||||
//
|
||||
// XCTAssertEqual(typecodes, [0x03, 0, 65533])
|
||||
//
|
||||
// }
|
||||
//
|
||||
// func testUnifiedAddressHasTransparentSaplingReceivers() throws {
|
||||
// guard let testVectors = TestVector.testVectors,
|
||||
// let firstVector = testVectors.first,
|
||||
// let uAddress = firstVector.unified_addr else {
|
||||
// XCTFail("fail to construct vectors")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
//
|
||||
// let address = UnifiedAddress(validatedEncoding: uAddress, network: .mainnet)
|
||||
//
|
||||
// let typecodes = try DerivationTool(networkType: .mainnet).receiverTypecodesFromUnifiedAddress(address)
|
||||
//
|
||||
// XCTAssertEqual(
|
||||
// Set<UnifiedAddress.ReceiverTypecodes>(typecodes),
|
||||
// Set([
|
||||
// .unknown(65533),
|
||||
// .orchard,
|
||||
// .p2pkh
|
||||
// ])
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// func testReceiverTypecodes() {
|
||||
// XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x00), .p2pkh)
|
||||
// XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x01), .p2sh)
|
||||
// XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x02), .sapling)
|
||||
// XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x03), .orchard)
|
||||
// XCTAssertEqual(UnifiedAddress.ReceiverTypecodes(typecode: 0x0F), .unknown(0x0F))
|
||||
// }
|
||||
//
|
||||
// func testExtractTypecode() throws {
|
||||
// let ua = UnifiedAddress(validatedEncoding: "u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj", network: .mainnet)
|
||||
// XCTAssertEqual(try ua.availableReceiverTypecodes(), [.sapling, .p2pkh])
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -35,7 +35,8 @@ class WalletTests: XCTestCase {
|
|||
|
||||
func testWalletInitialization() throws {
|
||||
let derivationTool = DerivationTool(networkType: network.networkType)
|
||||
let ufvk = try derivationTool.deriveUnifiedFullViewingKeysFromSeed(seedData.bytes, numberOfAccounts: 1)
|
||||
let ufvk = try derivationTool.deriveUnifiedSpendingKey(seed: seedData.bytes, accountIndex: 0)
|
||||
.map( { try derivationTool.deriveUnifiedFullViewingKey(from: $0) })
|
||||
let wallet = Initializer(
|
||||
cacheDbURL: try __cacheDbURL(),
|
||||
dataDbURL: try __dataDbURL(),
|
||||
|
@ -44,7 +45,7 @@ class WalletTests: XCTestCase {
|
|||
network: network,
|
||||
spendParamsURL: try __spendParamsURL(),
|
||||
outputParamsURL: try __outputParamsURL(),
|
||||
viewingKeys: ufvk,
|
||||
viewingKeys: [ufvk],
|
||||
walletBirthday: 663194
|
||||
)
|
||||
|
||||
|
|
|
@ -81,10 +81,58 @@ extension LightWalletServiceMockResponse {
|
|||
}
|
||||
|
||||
class MockRustBackend: ZcashRustBackendWelding {
|
||||
static func receiverTypecodesOnUnifiedAddress(_ ua: String) throws -> [UInt32] {
|
||||
static func clearUtxos(dbData: URL, address: ZcashLightClientKit.TransparentAddress, sinceHeight: ZcashLightClientKit.BlockHeight, networkType: ZcashLightClientKit.NetworkType) throws -> Int32 {
|
||||
0
|
||||
}
|
||||
|
||||
static func getTransparentBalance(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> Int64 {
|
||||
0
|
||||
}
|
||||
|
||||
static func getVerifiedTransparentBalance(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> Int64 {
|
||||
0
|
||||
}
|
||||
|
||||
static func listTransparentReceivers(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> [ZcashLightClientKit.TransparentAddress] {
|
||||
[]
|
||||
}
|
||||
|
||||
static func deriveUnifiedFullViewingKey(from spendingKey: ZcashLightClientKit.UnifiedSpendingKey, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.UnifiedFullViewingKey {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func deriveUnifiedSpendingKey(from seed: [UInt8], accountIndex: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.UnifiedSpendingKey {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func getCurrentAddress(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.UnifiedAddress {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func getNextAvailableAddress(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.UnifiedAddress {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func getSaplingReceiver(for uAddr: ZcashLightClientKit.UnifiedAddress) throws -> ZcashLightClientKit.SaplingAddress? {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func getTransparentReceiver(for uAddr: ZcashLightClientKit.UnifiedAddress) throws -> ZcashLightClientKit.TransparentAddress? {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func shieldFunds(dbCache: URL, dbData: URL, usk: ZcashLightClientKit.UnifiedSpendingKey, memo: ZcashLightClientKit.MemoBytes, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) -> Int64 {
|
||||
-1
|
||||
}
|
||||
|
||||
static func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32] {
|
||||
throw KeyDerivationErrors.receiverNotFound
|
||||
}
|
||||
|
||||
static func createAccount(dbData: URL, seed: [UInt8], networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.UnifiedSpendingKey {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func getReceivedMemo(dbData: URL, idNote: Int64, networkType: ZcashLightClientKit.NetworkType) -> ZcashLightClientKit.Memo? {
|
||||
nil
|
||||
}
|
||||
|
@ -93,15 +141,10 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
nil
|
||||
}
|
||||
|
||||
static func createToAddress(dbData: URL, account: Int32, extsk: String, to address: String, value: Int64, memo: ZcashLightClientKit.MemoBytes, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) -> Int64 {
|
||||
static func createToAddress(dbData: URL, usk: ZcashLightClientKit.UnifiedSpendingKey, to address: String, value: Int64, memo: ZcashLightClientKit.MemoBytes, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) -> Int64 {
|
||||
-1
|
||||
}
|
||||
|
||||
static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, xprv: String, memo: ZcashLightClientKit.MemoBytes, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) -> Int64 {
|
||||
-1
|
||||
}
|
||||
|
||||
|
||||
static func initDataDb(dbData: URL, seed: [UInt8]?, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.DbInitResult {
|
||||
.seedRequired
|
||||
}
|
||||
|
@ -110,7 +153,7 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
throw RustWeldingError.unableToDeriveKeys
|
||||
}
|
||||
|
||||
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: ZcashLightClientKit.NetworkType) throws -> Bool {
|
||||
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: ZcashLightClientKit.NetworkType) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -118,7 +161,7 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
nil
|
||||
}
|
||||
|
||||
static func isValidUnifiedAddress(_ address: String, networkType: ZcashLightClientKit.NetworkType) throws -> Bool {
|
||||
static func isValidUnifiedAddress(_ address: String, networkType: ZcashLightClientKit.NetworkType) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -130,10 +173,6 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
public func deriveViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey] {
|
||||
[]
|
||||
}
|
||||
|
||||
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 {
|
||||
-1
|
||||
}
|
||||
|
||||
static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32 {
|
||||
-1
|
||||
|
@ -147,14 +186,6 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
false
|
||||
}
|
||||
|
||||
static func getVerifiedTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64 {
|
||||
-1
|
||||
}
|
||||
|
||||
static func getTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64 {
|
||||
-1
|
||||
}
|
||||
|
||||
static func putUnspentTransparentOutput(
|
||||
dbData: URL,
|
||||
txid: [UInt8],
|
||||
|
@ -184,72 +215,27 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
) -> Int64 {
|
||||
-1
|
||||
}
|
||||
|
||||
static func shieldFunds(
|
||||
dbCache: URL,
|
||||
dbData: URL,
|
||||
account: Int32,
|
||||
xprv: String,
|
||||
memo: String?,
|
||||
spendParamsPath: String,
|
||||
outputParamsPath: String,
|
||||
networkType: NetworkType
|
||||
) -> Int64 {
|
||||
-1
|
||||
}
|
||||
|
||||
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
|
||||
|
||||
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> TransparentAddress {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func deriveTransparentAccountPrivateKeyFromSeed(seed: [UInt8], account: Int, networkType: NetworkType) throws -> String? {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func deriveTransparentAddressFromAccountPrivateKey(_ xprv: String, index: Int, networkType: NetworkType) throws -> String? {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
|
||||
static func deriveUnifiedFullViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int32, networkType: NetworkType) throws -> [UnifiedFullViewingKey] {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
|
||||
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) throws -> Bool {
|
||||
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) throws -> Bool {
|
||||
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], networkType: NetworkType) throws -> String? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func initAccountsTable(dbData: URL, exfvks: [String], networkType: NetworkType) throws -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
static func deriveTransparentAddressFromSeed(seed: [UInt8], networkType: NetworkType) throws -> String? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func deriveSaplingExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [SaplingExtendedSpendingKey]? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func deriveUnifiedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func deriveUnifiedAddressFromViewingKey(_ ufvk: String, networkType: NetworkType) throws -> String? {
|
||||
nil
|
||||
}
|
||||
|
||||
|
||||
static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 {
|
||||
guard let consensus = consensusBranchID else {
|
||||
return try rustBackend.consensusBranchIdFor(height: height, networkType: networkType)
|
||||
|
@ -285,11 +271,11 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
mockLastError ?? rustBackend.getLastError()
|
||||
}
|
||||
|
||||
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) throws -> Bool {
|
||||
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) throws -> Bool {
|
||||
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -298,11 +284,7 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
_ = try rustBackend.initDataDb(dbData: dbData, seed: nil, networkType: networkType)
|
||||
}
|
||||
}
|
||||
|
||||
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32, networkType: NetworkType) -> [SaplingExtendedSpendingKey]? {
|
||||
mockAccounts ?? rustBackend.initAccountsTable(dbData: dbData, seed: seed, accounts: accounts, networkType: networkType)
|
||||
}
|
||||
|
||||
|
||||
static func initBlocksTable(
|
||||
dbData: URL,
|
||||
height: Int32,
|
||||
|
@ -323,10 +305,6 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
}
|
||||
}
|
||||
|
||||
static func getAddress(dbData: URL, account: Int32, networkType: NetworkType) -> String? {
|
||||
mockAddresses?[Int(account)] ?? rustBackend.getAddress(dbData: dbData, account: account, networkType: networkType)
|
||||
}
|
||||
|
||||
static func getBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64 {
|
||||
mockBalance ?? rustBackend.getBalance(dbData: dbData, account: account, networkType: networkType)
|
||||
}
|
||||
|
|
|
@ -37,12 +37,12 @@ class TestCoordinator {
|
|||
|
||||
var completionHandler: ((SDKSynchronizer) throws -> Void)?
|
||||
var errorHandler: ((Error?) -> Void)?
|
||||
var spendingKey: SaplingExtendedSpendingKey
|
||||
var spendingKey: UnifiedSpendingKey
|
||||
var birthday: BlockHeight
|
||||
var channelProvider: ChannelProvider
|
||||
var synchronizer: SDKSynchronizer
|
||||
var service: DarksideWalletService
|
||||
var spendingKeys: [SaplingExtendedSpendingKey]?
|
||||
var spendingKeys: [UnifiedSpendingKey]?
|
||||
var databases: TemporaryTestDatabases
|
||||
let network: ZcashNetwork
|
||||
convenience init(
|
||||
|
@ -53,28 +53,13 @@ class TestCoordinator {
|
|||
) throws {
|
||||
let derivationTool = DerivationTool(networkType: network.networkType)
|
||||
|
||||
guard
|
||||
let spendingKey = try derivationTool
|
||||
.deriveSpendingKeys(
|
||||
seed: TestSeed().seed(),
|
||||
numberOfAccounts: 1
|
||||
)
|
||||
.first
|
||||
else {
|
||||
throw CoordinatorError.builderError
|
||||
}
|
||||
|
||||
guard
|
||||
let ufvk = try derivationTool
|
||||
.deriveUnifiedFullViewingKeysFromSeed(
|
||||
TestSeed().seed(),
|
||||
numberOfAccounts: 1
|
||||
)
|
||||
.first
|
||||
else {
|
||||
throw CoordinatorError.builderError
|
||||
}
|
||||
|
||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(
|
||||
seed: TestSeed().seed(),
|
||||
accountIndex: 0
|
||||
)
|
||||
|
||||
let ufvk = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||
|
||||
try self.init(
|
||||
spendingKey: spendingKey,
|
||||
unifiedFullViewingKey: ufvk,
|
||||
|
@ -85,7 +70,7 @@ class TestCoordinator {
|
|||
}
|
||||
|
||||
required init(
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
unifiedFullViewingKey: UnifiedFullViewingKey,
|
||||
walletBirthday: BlockHeight,
|
||||
channelProvider: ChannelProvider,
|
||||
|
@ -176,12 +161,12 @@ class TestCoordinator {
|
|||
self.errorHandler?(notification.userInfo?[SDKSynchronizer.NotificationKeys.error] as? Error)
|
||||
}
|
||||
|
||||
@objc func synchronizerSynced(_ notification: Notification) {
|
||||
@objc func synchronizerSynced(_ notification: Notification) throws {
|
||||
if case .stopped = self.synchronizer.status {
|
||||
LoggerProxy.debug("WARNING: notification received after synchronizer was stopped")
|
||||
return
|
||||
}
|
||||
try? self.completionHandler?(self.synchronizer)
|
||||
try self.completionHandler?(self.synchronizer)
|
||||
}
|
||||
|
||||
@objc func synchronizerDisconnected(_ notification: Notification) {
|
||||
|
@ -288,13 +273,13 @@ enum TestSynchronizerBuilder {
|
|||
storage: CompactBlockStorage,
|
||||
spendParamsURL: URL,
|
||||
outputParamsURL: URL,
|
||||
spendingKey: SaplingExtendedSpendingKey,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
unifiedFullViewingKey: UnifiedFullViewingKey,
|
||||
walletBirthday: BlockHeight,
|
||||
network: ZcashNetwork,
|
||||
seed: [UInt8]? = nil,
|
||||
loggerProxy: Logger? = nil
|
||||
) throws -> (spendingKeys: [SaplingExtendedSpendingKey]?, synchronizer: SDKSynchronizer) {
|
||||
) throws -> (spendingKeys: [UnifiedSpendingKey]?, synchronizer: SDKSynchronizer) {
|
||||
let initializer = Initializer(
|
||||
cacheDbURL: cacheDbURL,
|
||||
dataDbURL: dataDbURL,
|
||||
|
@ -334,21 +319,13 @@ enum TestSynchronizerBuilder {
|
|||
walletBirthday: BlockHeight,
|
||||
network: ZcashNetwork,
|
||||
loggerProxy: Logger? = nil
|
||||
) throws -> (spendingKeys: [SaplingExtendedSpendingKey]?, synchronizer: SDKSynchronizer) {
|
||||
guard
|
||||
let spendingKey = try DerivationTool(networkType: network.networkType)
|
||||
.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1)
|
||||
.first
|
||||
else {
|
||||
throw TestCoordinator.CoordinatorError.builderError
|
||||
}
|
||||
) throws -> (spendingKeys: [UnifiedSpendingKey]?, synchronizer: SDKSynchronizer) {
|
||||
let spendingKey = try DerivationTool(networkType: network.networkType)
|
||||
.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||
|
||||
|
||||
guard let uvk = try DerivationTool(networkType: network.networkType)
|
||||
.deriveUnifiedFullViewingKeysFromSeed(seedBytes, numberOfAccounts: 1)
|
||||
.first
|
||||
else {
|
||||
throw TestCoordinator.CoordinatorError.builderError
|
||||
}
|
||||
let uvk = try DerivationTool(networkType: network.networkType)
|
||||
.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||
|
||||
return try build(
|
||||
rustBackend: rustBackend,
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Francisco Gindre on 9/26/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import ZcashLightClientKit
|
||||
|
||||
/// Test vectors for unified addresses
|
||||
/// Original file can be found here https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/test-vectors/json/unified_address.json
|
||||
/// Note: These vectors can't be used as-is since we are missing derivation functions that take a DiversifiedIndex
|
||||
struct TestVector {
|
||||
enum Indices: Int, CaseIterable {
|
||||
case p2pkh_bytes = 0
|
||||
case p2sh_bytes
|
||||
case sapling_raw_addr
|
||||
case orchard_raw_addr
|
||||
case unknown_typecode
|
||||
case unknown_bytes
|
||||
case unified_addr
|
||||
case root_seed
|
||||
case account
|
||||
case diversifier_index
|
||||
}
|
||||
|
||||
var p2pkh_bytes: [UInt8]?
|
||||
var p2sh_bytes: [UInt8]?
|
||||
var sapling_raw_addr: [UInt8]?
|
||||
var orchard_raw_addr: [UInt8]?
|
||||
var unknown_typecode: UInt32?
|
||||
var unknown_bytes: [UInt8]?
|
||||
var unified_addr: String?
|
||||
var root_seed: [UInt8]?
|
||||
var account: UInt32 = 0
|
||||
var diversifier_index: UInt32 = 0
|
||||
|
||||
static func optionalByteArrayKeyPath(from index: Indices) -> WritableKeyPath<TestVector, [UInt8]?>? {
|
||||
switch index {
|
||||
case .p2pkh_bytes:
|
||||
return \Self.p2pkh_bytes
|
||||
case .p2sh_bytes:
|
||||
return \Self.p2sh_bytes
|
||||
case .sapling_raw_addr:
|
||||
return \Self.sapling_raw_addr
|
||||
case .orchard_raw_addr:
|
||||
return \Self.orchard_raw_addr
|
||||
case .unknown_bytes:
|
||||
return \Self.unknown_bytes
|
||||
case .root_seed:
|
||||
return \Self.root_seed
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func stringKeyPath(from index: Indices) -> WritableKeyPath<TestVector, String?>? {
|
||||
switch index {
|
||||
case .unified_addr:
|
||||
return \Self.unified_addr
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func uintKeyPath(from index: Indices) -> WritableKeyPath<TestVector, UInt32>? {
|
||||
switch index {
|
||||
case .account:
|
||||
return \Self.account
|
||||
case .diversifier_index:
|
||||
return \Self.diversifier_index
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static var testVectors: [TestVector]? {
|
||||
var vectors = [TestVector]()
|
||||
for rawVector in testVector.dropFirst(2) {
|
||||
guard let vector = TestVector(from: rawVector) else {
|
||||
return nil
|
||||
}
|
||||
vectors.append(vector)
|
||||
}
|
||||
|
||||
return vectors
|
||||
}
|
||||
|
||||
init?(from rawVector: [Any?]) {
|
||||
guard rawVector.count == Indices.diversifier_index.rawValue + 1 else { return nil }
|
||||
|
||||
for varIndex in Indices.allCases {
|
||||
switch varIndex {
|
||||
case .p2pkh_bytes,
|
||||
.p2sh_bytes,
|
||||
.sapling_raw_addr,
|
||||
.orchard_raw_addr,
|
||||
.unknown_bytes,
|
||||
.root_seed:
|
||||
|
||||
guard let keyPath = Self.optionalByteArrayKeyPath(from: varIndex) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rawVector[varIndex.rawValue] == nil {
|
||||
self[keyPath: keyPath] = nil
|
||||
break
|
||||
}
|
||||
|
||||
guard let hexString = rawVector[varIndex.rawValue] as? String,
|
||||
let data = hexString.hexadecimal else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self[keyPath: keyPath] = data.bytes
|
||||
|
||||
case .account,
|
||||
.diversifier_index:
|
||||
|
||||
guard rawVector[varIndex.rawValue] != nil else { return nil }
|
||||
|
||||
guard let keyPath = Self.uintKeyPath(from: varIndex) else { return nil }
|
||||
|
||||
guard let optionalValue = rawVector[varIndex.rawValue],
|
||||
let intValue = optionalValue as? Int,
|
||||
let uintValue = UInt32(exactly: intValue) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self[keyPath: keyPath] = uintValue
|
||||
case .unified_addr:
|
||||
guard rawVector[varIndex.rawValue] != nil else { return nil }
|
||||
|
||||
guard let keyPath = Self.stringKeyPath(from: varIndex) else { return nil }
|
||||
|
||||
guard let optionalValue = rawVector[varIndex.rawValue],
|
||||
let stringValue = optionalValue as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self[keyPath: keyPath] = stringValue
|
||||
case .unknown_typecode:
|
||||
self.unknown_typecode = rawVector[varIndex.rawValue] as? UInt32
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
|
||||
/// Create `Data` from hexadecimal string representation
|
||||
///
|
||||
/// This creates a `Data` object from hex string. Note, if the string has any spaces or non-hex characters (e.g. starts with '<' and with a '>'), those are ignored and only hex characters are processed.
|
||||
///
|
||||
/// - returns: Data represented by this hexadecimal string.
|
||||
///
|
||||
/// source: https://stackoverflow.com/questions/26501276/converting-hex-string-to-nsdata-in-swift
|
||||
var hexadecimal: Data? {
|
||||
var data = Data(capacity: count / 2)
|
||||
|
||||
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
|
||||
regex.enumerateMatches(in: self, range: NSRange(startIndex..., in: self)) { match, _, _ in
|
||||
let byteString = (self as NSString).substring(with: match!.range)
|
||||
let num = UInt8(byteString, radix: 16)!
|
||||
data.append(num)
|
||||
}
|
||||
|
||||
guard data.count > 0 else { return nil }
|
||||
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
let testVector: [[Any?]] =
|
||||
[
|
||||
["From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/unified_address.py"],
|
||||
["p2pkh_bytes, p2sh_bytes, sapling_raw_addr, orchard_raw_addr, unknown_typecode, unknown_bytes, unified_addr, root_seed, account, diversifier_index"],
|
||||
["e6cabf813929132d772d04b03ae85223d03b9be8", nil, "d8ef8293d26de832e7193f296ba1922d90f122c6135bc231eebd91efdb03b1a8606771cd4fd6480574d43e", "d4714ee761d1ae823b6972152e20957fefa3f6e3129ea4dfb0a9e98703a63dab929589d6dc51c970f935b3", nil, nil, "u1jttnjvd97hja2fvajcgfmu6w2mcffuzlgfmvepjy8qdhkjmv4pf90dqgzcse23t95yvxaaysh8fu0d6wwjw2x7pxvzgx5zhxfn2j33mgspxlxysdhqafush2awsz4huts5mqz7mffzl09697my7dgl7c48eggfe072aj2u8jd7ktl0vzf36j65cye9ff0erc5n2mgqkjygwnq004a3y", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 0],
|
||||
["314f9bb5a18af9c9f6eeb035cfee3acb111facd9", nil, "435b0bbc95b5b7d52531a3944f2b85603ee22aaf850963bc156eb561edf2cbe7cf0e770e393ae5d7049026", "a9e372a4c8950cf34ae29ccc664564b56cc3030025065fc24da4c00f785e8d1b9531e3ef83a66a4edc3816", nil, nil, "u1ee82x2telrxdw72p4ke636wu2c2p09qrq7mhzm5kccjymh2033avaeh3ttt5s89ez0a3yrgwaec7glvgkyn7xl8x962dza5s6c4q9aspe655d4c3er883dleqdhgxnaxhex2j3z265mly7pf0kuv69mhyh30pm5vnsnq2lwn8hga24a0y52l9ydvg6hda5w23fes6hyasknhumwd8nu", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 3],
|
||||
["3ca74c80ef1d1853423ae2891cd5d0ecbcfde137", nil, "69a25a38699708e5f6e76e54e6a7a2ab84dcf288df0d1f2563670168d6c44ace0ef11155c60d5c225e9dec", "7e243f6141643f81e1e93fda73cf2f64f68de487785370f3021d1940f34bc3ed13a9d9a03baa78e4a43b97", nil, nil, "u1uqlu50zy5q6dtkqjfq92a8fxt3yg9gv6yrj48rt9l0jlxpgdxvddgefct6femf73yv05umnxcf848jr4r8ue37g036h64vk5cwel6sml50w0jeah8fg6awcuj0q7f9udr6agq9j76dza8j3urh6zq7p8t4gppgxsqr2nv3fgrrqv4dhx6hye7h2fz5ppq9m4v332x7767jzg75qe0kp", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 4],
|
||||
[nil, nil, "9f6e0bf90a18fc0b9b83ae9f23ad4358648638482b5def8975635b66fd8a708335f9235a3186ec0f033f84", nil, nil, nil, "u1z9vyk0d0h2k2jwuuk2gfvh5p65qsagkwcgqm6lvh8ratkzjau7stq5snlnkl0eutr687f3wcyn8a0m3n3462c0e4t4cs7m3lvumj2ddm", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 1, 3],
|
||||
[nil, nil, "e1adf156a07d56bcac91bdb2f7bb3ea7c44569dcfee54273c09e8065807b6823faa94a77219554d0f6e017", nil, nil, nil, "u188xrtf88khrjcd8d4487qvjk3getm6xmex0pvjket5qen35tlzhpmgadkcyccz8q0kp3sxzy4ldgn5n0cnll34s47ymvw9cqfunh53wq", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 1, 7],
|
||||
[nil, nil, "60ba572f8e379312d86897025decdd64b4b95e2c4afa9d13726b8cc393edb4988c51b976028f890f108bd2", nil, nil, nil, "u1jn6752r2s080uhf8grhdnnkfzrgfcyv3tu45f03rzcgheqpmxj5wuvf0v274l0k5ehvc763epv6qxnsv6t04vcn66h0sa2c8nsnyy2f3", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 1, 8],
|
||||
["aa6d43480fd9d91375ce6c4a020706361bd296de", nil, nil, "953f3c78d103c32b60559299462ebb27348964b892acad10482fe502c99f0d524959ba7be4f188e3a27138", 65532, "cd8dbf69b8250c18ef41294ca97993db546c1fe01f7e9c8e36d6a5e29d4e30a73594bf5098421c69378af1e40f64e125946f62c2fa7b2fecbcb64b6968912a6381ce3dc166d56a1d62f5a8d7551db5fd9313e8c7203d996af7d477083756d59af80d06a745f44ab023752cb5b406ed8985e18130ab33362697b0e4e4c763ccb8f676495c222f7fba1e31defa3d5a57efc2e1e9b01a035587d5fb1a38e01d94903d3c3e0ad3360c1d3710acd20b183e31d49f25c9a138f49b1a537edcf04be34a9851a7af9db6990ed83dd64af3597c04323ea51b0052ad8084a8b9da948d320dadd64f5431e61ddf658d24ae67c22c8d1309131fc00fe7f2357342", "u1uwdt59245hh0y324zds9s4knmw3q450qgm4rhmyzq6x62uxerpwtsnmqlp25w7w79c9y9qez6j072krjvlvg9805a4hj5mya9k8h35kauj7cmdg3hqnmvqeaa0sfgg95qpd6k7mrnfxpp2zl0kq7z90wyr8ptmgdnq3swem4wken5pwr0vdgkvylzfzwcr2mesef9j9pd9frudzgdm392uvlh3nhe3vvlwkd4nu3tm03gzllae9dn0n0csupewz95z96xnauljwyc3crw34d2zftcumd0uadz0rlj24ax4svvm6y5ga9j363k4a996dh3h8dz769gekf3jadx5kwwf4eckfvkwn7lf04rctx7kql08956xz036jyrl2pphlwjn9xyprfs04ug3p0z92znkv7yf53hn0w63elnkwjl5u934lck6f5q8l7wnrlcly62utckyew808judy8lnuzrzfmd9r952v64p6g0g88s8n5w2wgshp4l58vssndy3rltlhw9y4r9agykflzrw0dp0w2yajnucnx2rd", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 2, 0],
|
||||
["707aae9a13445677cf7d7cb394b9a883f4104018", nil, nil, "88391e4e038ca9e15cc38624a64552a99f07be0715ae2db4474234e946e1b6c6b6676e5cf7b25d90593e8c", 65532, "76d38d47f1e191e00c7a1d48af046827591e9733a97fa6b679f3dc601d008285edcbdae69ce8fc1be4aac00ff2711ebd931de518856878f73476f21a482ec9378365c8f7393c94e2885315eb4671098b79535e790fe53e29fef2b3766697ac32b4f473f468a008e72389fc03880d780cb07fcfaabe3f1a84b27db59a4a153d882d2b2103596555ed9494c6ac893c49723833ec8926c1039586a7afcf4a0d9c731e985d99589c8bb838e8aaf745533ed9e8ae3a1cd074a51a20da8aba18d1dbebbc862ded42435e92476930d069896cff30eb414f727b89e001afa2fb8dc3436d75a4a6f26572504b192232ecb9f0c02411e52596bc5e90457e7459", "u1c8qg4struvf8gm0gulzg25z30uxjxxcj2cmcdl5jyamqjmgdk85flag2lw7kjdptzaqkv04kjypyvga4vdmedw7y298h7e8qhp7qkdc53qmnt4k77cym7gnyhsz5e82cgkvfnl3sghndsnjcfnrj2w2n9x7p949x5mmxjkhpvs92zyyvf0zx28d093t629sl332aqgpv4qp9m6ytaqr6av6wy6l0le2n20z6ck6akd7276ql8cv7thzqd8nc2uyz9pedqywj90nmlymhkqk8pzjvauqfmnly2h6ezgwwv4utu4njj66y85ysamkm3g35wjrqkytad343uysst406pyr6y2asa6t9pzznpzf363hqxv8u34sccaafrrqpklrq7ejpv6nawvm425hxt0np3x7nwq4cdvjwcqghrq5c7pc4lddxlgdgv3ujlm5s5d6ss8f98hk99vkqw27jl2clnpz382htyccncdhp40c4xvm48glm3sr2nakfqm0twckzcuwenq96768yu04wprp3w6ayhsf8k9cshpj", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 2, 1],
|
||||
["21e2c228dd8bad8816a407c18ad7987d1a4f0336", nil, nil, "251dcb7e5a988146d9cb52db9d7f81de1eb8ef58ee08eb4ec4810a23be8f4337790a99bfba8e364aa25b8d", 65532, "39ffedbd12863ce71a02af117d417adb3d15cc54dcb1fce467500c6b8fb86b12b56da9c382857deecc40a98d5f2935395ee4762dd21afdbb5d47fa9a6dd984d567db2857b927b7fae2db587105415d4642789d38f50b8dbcc129cab3d17d19f3355bcf73cecb8cb8a5da01307152f13936a270572670dc82d39026c6cb4cd4b0f7f5aa2a4f5a5341ec5dd715406f2fdd2afa733f5f641c8c21862a1bafce2609d9eecfa158cfb5cd79f88008e315dc7d8388e76c1782fd2795d18a763624c25fa959cc97489ce75745824b77868c53239cfbdf73caec65604037314faaceb56218c6bd30f8374ac13386793f21a9fb80ad03bc0cda4a44946c00e1", "u1q3vrqfexveqh2772en0ynkwstt62sqlyvkqzn8kr2w4hnpqy07d7l6qxzwwuuv3k040c5t6haqkak60km9l3c7hzd6y5ycednjep3c7puknhtlmp24adyduh02zq8kw3mqm4vhzkzc84tmsv9h2rpp6jf4xqpw2md4jrmrmuklw3zv50ajr2gxkgk6hxq2szymsmykvzpvwz8rt7zekzqakurrmrvnezmvu6h5c6gupp275qc6lrl57rg9pwvg7dza37c3ft569gnzhjz7f9ujvm8799nrc7nr2udgzcaphyxmrpzrzhzqpdqy28cqzdsay467fjtexyn24mqlzjdqwsylj3sqaylfy0hu8ezpt3q4xlssq7m6c0c0706w3mf7ed9nd20209q0rmxj75rya62gxcu5r2nss8vtdq8kuk93t4dvrte9r587zy37ty998njtmwk7s5vzeg4ugq07ea0ffdzjpf2zy84ccwauzkrq36z5vm72qwptvn3k47kurxxs0ltvrq262d0hfrmfp9ecpys7eewqy", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 2, 2],
|
||||
["235fd68bee8f799114c9e7cb8ce3c01f5e442a58", nil, "52fd6aedefbf401633c2e4532515ebcf95bcc2b4b8e4d676dfad7e17925c6dfb8671e52544dc2ca075e261", nil, 65532, "8cc3d14d2cf6556df6ed4b4ddd3d9a69f53357d7767f4f5ccbdbc596631277f8fecd08cb056b95e3025b9792fff7f244fc716269b926d62e9596fa825c6bf21aff9e68625a192440ea06828123", "u1v8dtwgkrza584fj3jv7xvwm0paf3fqelt972s9kr3t808tj35gfa7lsnfpzjqgedkcc7kefrtek5nhpv6q6ekykua0eusve549crkm9yhjzrq3yqqk5wve684sjwazkztk4v4nupwgl4y6xyakysdy2p68msjm5tla8hsadaw4tmjrjzmwlm6u4c8z0fjaxew6l52qfl4dt5hqwz0wx82maek5wys7k7a0rjmh03ykgjsaphmz8qz62dpgvwl4t7pfzk4xqlvy6pk", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 3, 0],
|
||||
["cd7c11d41e1f9db7c3fac7b01fac2d81a20a0fb0", nil, "78ba60804b822cc7e970b11a96b5bccbda556a7c26f0b082cfcd9a68e2690017771c4bdcf8f8bad3c8591f", nil, 65532, "d97884806f15fa08da52754a1095e3ff1abd5ce4fddfccfc3a6128aef784a64610a89d1a7099216d0814d3a2d452431c32d411ac1cce82ad0229407bbc48985675e3f874a4533f1d63a84dfa3e", "u1n6trq9cqde5vywu6zl4u6ydhg4k39nh3ymtvecnvzlv0crt906t97uxmxdqjxcf8uqratws4l0g6q4mjr34u77pmcle4224n35tq9ge7hjra8j2e88ggveqfmw9mdrrgcftu0p5hjmjf89fzehug6hng3zyktmmk0y9jyespq76s2l3sh539vk2v8h8aykqa2k6mmpmkza4ngpds7l9h2vf9nhfkhmjlysc0nsrq3y0qvfma8g3ad8efxwy8hjsgjyy2lts6muf3a", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 3, 3],
|
||||
["a257c2f326ba0eccee803c2867e91779cf93ef19", nil, "508942b74eac2ab8e9868b06c95b30a6b5a56c35478b3b05460fc9e63217c22259ef84c23c0f29f877be4f", nil, 65532, "0f460fe2f57e34fbc75423c3737f5b2a0615f5722db041a3ef66fa483afd3c2e19e59444a64add6df1d963f5dd5b5010d3d025f0287c4cf19c75f33d51ddddba5d657b43ee8da645443814cc73", "u1q26wd9e3vgsepgw9748tvsktlq0jqvfr59ul4fya0tn56sss7yv5emkq348yr7hawdazngph0elatc56t6gz72lhjh8dcfrfkt6kamsf664w7h354rksgar90xt5h7axypgej6rudw8c4t0nchklst05hamddf67r5gkzcsqqz6a8ugjtl0ur0rlywfe8pmqju97s42tslaaygj0mnyu3xk3g2x6e2jezyjfwpqxfysjf0q8a5xcex26qpdwzsyc3smpw5cahgjc3", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 3, 5],
|
||||
["7ae2a0db6781b6db28ebeccbac16f39ed3e5e4cb", nil, nil, "165082de84f2ad7204426ffafd6b6c7de9cab6d25c13846a1786715268c415948db788f4a5e0daa03d699e", 65530, "86a2658e0a07a05ac5b950051cd24c47a88d13d659ba2a46ca1830816d09cd7646f76f716abec5de07fe9b523410806ea6f288f8736c23357c85f45791e1708029d9824d90704607f387a03e49bf9836574431345a7877efaa8a08e73081ef8d62cb780ab6883a50a0d470190dfba10a857f82842d3825b3d6da0573d316eb160dc0b716c48fbd467f75b780149ae8808f4e68f50c0536acddf6f1aeab016b6bc1ec144b4e553acfd670f77e755fc88e0677e31ba459b44e307768958fe3789d41c2b1ff434cb30e15914f01bc6bc2307b488d2556d7b7380ea4ffd712f6b02fe806b94569cd4059f396bf29b99d0a40e5e1711ca944f72d43", "u1qtww2cneawwdu5v9rqt4dm9kwn80s2nztcwcpeqz8jagey04qnate7r8j6zu9thm97ldtn4qdl36vlpn8lvy3ljk8s37kr9pgkpqlmlla9vhh9j6wucqwham9zddrzu5jl9g8jav3rdx560ft6cr5c7j2p4gqp88z6y4zmrhszssnss839zfzkn34h5ttrtg6tuw4qdf272lhqns2faylkykz2yed239tehndaruw4v93rw04yc435eke3m7lczed935zhtasdptyjw0rd5ulhdg02rnqhltk43s3d2jgd30xla8qda550tlkmtg2d5kz3amvtldmzl7w778we2zq8ynfny4v6g6us6exvdcc4qsgq3esw3fvev5tycpyhk4srvj4u2haw4m3z37hpaan5y2k4pl53hdnd2je8ejcv5ka3a34c5xu7zxd3nydf4as5wsl7dpzn6zjqkl4dcs6l3cyzl5n6z77pn7d043d5egu4tcrg2suh9l0rwwz8enrqqw2c70q50n3lt3rgl2m3cqevdj0srv", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 4, 0],
|
||||
["f45861cfbb22c49f51c40a3cde5c66c0d95bc413", nil, nil, "c906109b51e2b37bf8b67761bfa917dc5059c357b7dc8107672b66189a0d15bc496d84ef9114c68c99c911", 65530, "6a102fca4b97693da0b086fe9d2e7162470d02e0f05d4bec9512bfb3f38327296efaa74328b118c27402c70c3a90b49ad4bbc68e37c0aa7d9b3fe17799d73b841e751713a02943905aae0803fd69442eb7681ec2a05600054e92eed555028f21b6a155268a2dd6640a69301a52a38d4d9f9f957ae35af7167118141ce4c9be0a6a492fe79f1581a155fa3a2b9dafd82e650b386ad3a08cb6b83131ac300b0846354a7eef9c410e4b62c47c5426907dfc6685c5c99b7141ac626ab4761fd3f41e728e1a28f89db89ffdeca364dd2f0f0739f0534556483199c71f189341ac9b78a269164206a0ea1ce73bfb2a942e7370b247c046f8e75ef8e3", "u1qxhqghcyrv0vunc0qgdqlm45ftmahunlu8jwstmqmrptgam2ddw7nz3dcwmc93pzjqn3vk24acxtzdvytpnr4hlukkmnmhe063342u24wr0l2td6zdgwe06cfun4u2sa0ml00pmzdz3fhv079yz3jwdzq26hj8dywv0ml90xv74mljuvdc3apv8vkp03xlskc2rcrrfz4c6jazjjschses08xpxd088yl8e2aw0gg7arlfwletk4ruwam5qvmwz5drhe70kmwd38637y0zh2q7ayl6hunrgvqyyc42x28ewk7tt23lul4wjkl5g0w2aqz8p3jy62zk2e5vemd5sxeyudcfq3u3a5lhahl230adlx00z00tnx5kuwmgk7mf6ylylep76q9j6642fqg3y2svckg0nwxgadmtyyp8pwgltd7rdv9wefzwd2rywpu9h33gwq4s07txgjwwadmgs27n8m93ndr8vljxr74xr4n8ghveumzh3wnya7etkx8a49dyuzm0xvugsh5ejk8qggm63xv5jc0le5", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 4, 1],
|
||||
["2456cac075428d24707af7de2fc610c833831bdb", nil, nil, "7cd065b0ab297fb7fd701291d03589031fe3aadf1177902e5bcb65b5ba0aa2a0b73f09734f0b867b29763d", 65530, "f8bd821cf577491864e20e6d08fd2e32b555c92c661f19588b72a89599710a88061253ca285b6304b37da2b5294f5cb354a894322848ccbdc7c2545b7da568afac87ffa005c312241c2d57f4b45d6419f0d2e2c5af33ae243785b325cdab95404fc7aed70525cddb41872cfcc214b13232edc78609753dbff930eb0dc156612b9cb434bc4b693392deb87c530435312edcedc6a961133338d786c4a3e103f60110a16b1337129704bf4754ff6ba9fbe65951e610620f71cda8fc877625f2c5bb04cbe1228b1e886f4050afd8fe94e97d2e9e85c6bb748c0042d3249abb1342bb0eebf62058bf3de080d94611a3750915b5dc6c0b3899d41222", "u15g2qv6nj2h46z9wkqxvj584lqejspg8rv4a4djpzdll9mz3fh36c54qhwgpgdrh03s6ehzdpx87pfqvcd7hwl2m5clfl9n6fcfj07pztsdttdxy5sfxx0dnrug38yders826wh5x64fq2sac2q40g6sk65a22wt0fmg8pvjhrel98f4jtxf4yg2l2jkr0aw0lng2hhwwzme7yzm5k5sxeys83hwwxmlum04z374za20zr2ghhty5ada5qpv5ry9ht6amrg2mfn8vf8emr84ng66zf2e48ymdfc7hxdcvmaly7j7kg5g27a42vgrvs5w7m996xmx4vtv924nlzcekpjgkfskn677muv6u0t8uqmv0q2hzdgvk6p0j39zm2u6vyct2sf6vnq24crgy3zfdg5v2tmwv5vtyuq8sdu7xjn9yuae4gtfs0ug3ryhujq43azve9t9zmm6pccxswxkwfexvzpmn8xrfltdfmgex68y6wrd3qwd0sgp0p8wxf6eyup2ydff2ytxq4ehngt35zeh6vv5u4t3r", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 4, 2],
|
||||
[nil, nil, nil, "ea9df83fbee07d6f7895ebb2ea41ec7c4ba682b863e069b4a438e31c9571c83126c305d75456412aeaef1b", nil, nil, "u12xugd90flrkdkeu3nlnn3uesky53pqu5m24y6apxm88m48v7374cls56zp93naylaxdchf0qayfxtrge047m953qz3v2gr4ltsr2sk3r", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 5, 0],
|
||||
[nil, nil, nil, "fd3e7eccdb1a91f2c4498bb7eb61cba83eca499cfde9c5ce3e3241873bad2e423abe91dece0a6930e8901d", nil, nil, "u1kffwpljstudp6rmdmdtfc8h408yf983qyrnl2pfsymapqsrsgznp2qnh57mzlzdcmecdgd82repec6zfjw874w5frxrw73na6sj3m90t", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 5, 1],
|
||||
[nil, nil, nil, "5ef3c8b2bf2a8b0e60a6254f312229b4124d4787e7dada5d81e16b51211707871bede32811a35f4094ae8b", nil, nil, "u178uk6ed50uezamsthlls26qxwpj0hlv2nd7l4wl586x7y9zpzvmnjgwrx7f9j260ny5f3ewxxasun8zklw4schlmh6aw0c5epuuc75tg", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 5, 2],
|
||||
["7ddfe9c9b7d08ed6bda0bbc2be4030e04679d59a", nil, "1cc9bcb1a50880e4efb08e6e5a49305d358d575a746a51fe0db5a96b7eb39bd20744dae185061819fb7967", nil, nil, nil, "u16u53z44ydps7d5kmx7wyt3cf67z8rpllvmfgcsj3ra0uaxwqm033s3xfczfl3l78h9d6th6p2de8t0dqkad4u50k3gsalvwlwrwkvf3px7eyzgsvz83sfdhg79pfgxhgnl0hz03vx36", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 6, 0],
|
||||
["150a17d8f88608900ae24ca27046fbfa082940b1", nil, "ac093a82a7f4a5ab66bcc994bbfc5b3f5f945f4499c5d8987f6404ceb4a91c46320b3618c318d80281b285", nil, nil, nil, "u1vl86hhk6wtueylzh72tksuh5pscamttzzkq7f3vnq6stg4u63zwmwndjul9jfu8g8ns8hu075f09cvc48j456048rtcwueka866v7dx3088sth7c59wd3jvh0pfc22s9vtkjyknhtgv", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 6, 1],
|
||||
["133341e730a55e80e5f7a0bbf468663835f7e0c8", nil, "7198a7b9bf9099809a63bccbd56af56744ea2857ac8d12892ad58d82fd5b0cce71ea7a25816007c34491ec", nil, nil, nil, "u1uhuw9lsxpw72ejrsgeh8rrztu7cm7h3qjyawyrgcekgn0f277msnlyqgysu5986ew3z8a2g0lmvcf36dqq7wguy7gvnteprz4qn8qkwwfq2pxeyukyn3v4tl65ptkjzul8lpv32lxly", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 6, 2],
|
||||
[nil, nil, nil, "cc099cc214e56b1192c7b5b17e958c3413e27fefd553380700aca81b24b2918cac951a1a68017fac525a18", 65530, "942bfc9f4fd6ebb6b4cdd4da2bca26fac4578e9f543405acc7d86ff59158bd0cba3aef6f4a8472d144d99f8b8d1dedaa9077d4f01d4bb27bbe31d88fbefac3dcd4797563a26b1d61fcd9a464ab21ed550fe6fa09695ba0b2f10eea6468cc6e20a66f826e3d14c5006f0563887f5e1289be1b2004caca8d3f34d6e84bf59c1e04619a7c23a996941d889e4622a9b9b1d59d5e319094318cd4", "u1643kh4y642rxtsqa2pvmjnkch8ex0z3u5j8upczd4vgl8wqh0whpyu5cssjuyp4pf2g8mvz7phpuaj8zakha7qtzw6ec9hpczwa5n5zu88ylfxhysq3xpxtfemprkw2j4w78n6q3x4h2ty35cfgyzk7aduzazav4rg4y08du34kr5kdtg22plumma5c2xz3tzksr9et8wax0g647xrrmqqq29ryx29fet7xhrj44zz2qwfvmth0hcrvwrynd7m73tdf9sq9fkfm8g850y4l37ycw7eet48y0p03vwhzdmhrcnag670ctvfehsfs4kjtpssr6ayrvjuje2ftmgzyhgpgwgn2q6m9uv0", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 7, 0],
|
||||
[nil, nil, nil, "3c025e3e717e185a77c29ef372b6e7c3b17c459256074fef6e6cbe321cf9e0886a82598867b979de1a7da1", 65530, "05ba27b7e2c084762d31453ec4549a4d97729d033460fcf89d6494f2ffd789e98082ea5ce9534b3acd60fe49e37e4f666931677319ed89f85588741b3128901a93bd78e4be0225a9e2692c77c969ed0176bdf9555948cbd5a332d045de6ba6bf4490adfe7444cd467a09075417fcc0062e49f008c51ad4227439c1b4476ccd8e97862dab7be1e8d399c05ef27c6e22ee273e15786e394c8f", "u12h7pa43zagukq40ndvujxsw2t3ekgzt8xfk4tkdn0u5mckfgg8nuxxwjf8xlwehgsg2zy2hesc5dm2mm2xy20rxkcw89fm37wz73xgp5amm9ccpczasmq4qhp2gnjgj4yxxpxsxtrjpgvssguau0tc7pdyjm6hh0843zk9cmmu60c5ckuaj7p585q330pd4dukpmseu9havskyhda6zcd58kc4dfpkpl24gd4y86z88kgmka6nx3y5d8ndmvwyw2sl3gcedrfrwphxm56q5dkg2amccs84egjrhnlfz2sanvydpn2y808u4m2mrh3vu4xcccg6v6y2uv957ja3r060cewkjs25ydd5", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 7, 1],
|
||||
[nil, nil, nil, "cb1c888234bd7f9e6bdbc2178bd32c2fb0451384027975e83f71a98871a290f3bf43c94be686c77b12edb3", 65530, "1be31682a30147963ac8da8d41d804258426a3f70289b8ad19d8de13be4eebe3bd4c8a6f55d6e0c373d456851879f5fbc282db9e134806bff71e11bc33ab75dd6ca067fb73a043b646a7cf39cab4928386786d2f24141ee120fdc34d6764eafc66880ee0204f53cc1167ed20b43a52dea3ca7cff8ef35cd8e6d7c111a68ef44bcd0c1513ad47ca61c659cc5d325b440f6b9f59aff66879bb", "u1xsvuwuzm254u2rycpckqsv8hv592jktdf9cgadxp4j82mvhvh2w6k4d9lrdp260gm7lkspekskgakujyunywqv3g0kzd72e0pwmdg28ykfhjnfvr2j066cd92yjk5xjka00dmsf0kax5zdcgyknu2j7s84x7aeue2x97705ydq7s00cuntwft5cv3ejzd4whp4awcr9vsuhfjrqlnkjyk9v6n89jg57umf57fnace7z2ysdjqudcfwwjwp2999h3jpypa0c5da4hh9t48p7gxd6a5cm4xkwmddmspmxazm89s7p4fa425n0wrlu6gnf9xy4v89wt03wwtcs7jmz3zfz9nk3s9ldymk", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 7, 2],
|
||||
[nil, nil, nil, "5f09a9807a56323b263b05df368dc28391b21a64a0e1b40f9a6803b7e68f3905923f35cb01f119b223f493", nil, nil, "u1cxccyemm08tydwmt9hp2s5nf8wjvluuu6l2e8a9jflldxasnzkd8fverqpcj0xnvraczqg255cw5nvy6x9wruffmp9uezrzr7gcx559k", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 8, 0],
|
||||
[nil, nil, nil, "21006cfbb3db4f4bb63111ef63f7f80056f31b344d06aca5b7fa0740c660c8b2dc3bd234f4c18ae9eaf811", nil, nil, "u1e38h9rl45mryslydy7g4sjh4wqfql54ay6mk0hj78pay5p3esnz3kmk7sqfyjgpla5yrwa9h6tqy9y6earefuhq69n92sgq8que6mlvk", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 8, 1],
|
||||
[nil, nil, nil, "04915d2bebce11111ce195226cde8440263c50204b2272ac8a96b38dbd70db8969ec9b6c87cd15d9d76512", nil, nil, "u1clspfaz7dswwrkl0vlp4gfjmprmsvdjyq0xewwldt8rfw5yy0meqqscczn74j3n6rpgucpk99mpf7gfr87yw99tum7pz796kpyjk97ml", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 8, 2],
|
||||
["6b94c815d9cd2ac0cca4ff8bee0cd5175afb0d72", nil, nil, "e340636542ece1c81285ed4eab448adbb5a8c0f4d386eeff337e88e6915f6c3ec1b6ea835a88d56612d2bd", nil, nil, "u153s0peymew62a299k3nw437h57nyqgw28art0q7z5wa7lfp62w3czu2njsc4lma48kqlp889fh854nmhlpjyzwffmrdc0guj082jqef9knsvuwjc4mkypf0nqgydqsu5wzcy77255ev", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 9, 0],
|
||||
["53a89cd8e8b635cd4c4b39d4df0a035d045c50d4", nil, nil, "3fadf8edb20a3301e8260aa311f4cbd54d7d6a76baac88c244b0b121c6dc22a8bcce15898e267829fc1e01", nil, nil, "u1fdsfklmddxv2uq6ypsz09vf28vyldv4qen2spj0lrzdl0jv38pdk7a6ju3806zdaghwaway62nvuhv98mwrfd4tdn7tu22eq4ma7emq5gajn7tuy7dxradjkzeeust0x7h7pvcfyhus", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 9, 1],
|
||||
["972085f9e6a02aabb3c420f0e4e7c8c3267a00cb", nil, nil, "987fd74a2256c596a66f83eaff7bb026286e972be56d3b50e3459747dfba53ffa0f24732b4aa6cd437a317", nil, nil, "u1uh2cdr9mqewwzujfwnnf49mczesvmprjnqrk6yjqfvwshlquq07p73y43tpdha04fjdz6x6plneqz5rj3ka2tfr83768kglsn5a53u278sm9nfjx42ev2feht0e2tsczedw2z49m8uh", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 9, 2],
|
||||
[nil, nil, nil, "cdf7fed0d0822fd849cffb20a4d5ee701ad8141e66d81ddfabf87875117c05092240603c546b8dc187cd8c", nil, nil, "u1sj55qey22hefwyz6mnc3ldz7fcnkg9536uk5e98rwznvvald27r2vzmeupya5u696l5j0w6f5fdxkf54yvyhy0xze2u2wa2zdv2g67u2", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 10, 0],
|
||||
[nil, nil, nil, "a6aa4fd8937382812c9e5b333f95bb440e290f2e2dc6b9978298d88c277b85f7dbb4ab9d9788479b75ce04", nil, nil, "u16d6remztx7ezmgfdvcglv3w44cjdmjapf0jz6wgldj49p2a7269gf5gzpun597mv50d3h4pgetgznawjdjvaeuhqgx6qzxk09qq48qqf", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 10, 1],
|
||||
[nil, nil, nil, "e4e01051b99c08506834971f80dadec44a4da13ecdcba617f77fc48d25324f57cb1d4d7424705d573cd682", nil, nil, "u1wyge9pna2zs3qwc27uvu6l0cf8sxtrsr2lpfkdz8g6gxhxlvy48xalk5xapwawrwer8vc4weha25cxd5vumzj9yyhxrhzuzkz5nw5u5d", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 10, 2],
|
||||
[nil, nil, "0ba97e749afc9322db91f262fd8d2872f05f09de246b1f9068abfd25f5165da1a05115c6f4784d2b922a3d", nil, nil, nil, "u1e25fvhxh3hcqd9424am3pf20fvvvzjt4445lpk03f40d3xxjc6ppj5wn9lt0ru3zvnpt5q5fkhw0npgnu9z2en9l65xe4fqdxq7t4x5r", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 11, 0],
|
||||
[nil, nil, "4f9e8b832971ce3bd99a2a1bd545fc258921fb51abcf8d2c00fcca7e9d2888fd60ffa31716786f1bcd4226", nil, nil, nil, "u1cnzmjsp3nl542nj73ezrvtll9ss7gmegjyuz65q7dn8wlyj99lxxzvy807t9700pesc5554a2egnx2pet6s99gllt2dzcsqn8sxvdwcr", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 11, 6],
|
||||
[nil, nil, "314da30f32e4899d14d64212f70a10cfb60f541da1bdf72323654eefb75f1bdf4fccced2a4aae90e54e7e5", nil, nil, nil, "u1l9d7naej4k7pkm6f89rqvy9uc5q5rv70e78nyjtyt7st4hgyn9rj9we49amdjmg44s0uxmvyc6tq407phcexvwayc5jhts4trvs5uzpe", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 11, 7],
|
||||
[nil, "4686e569d58d99c1383597fad81193c4c1b16e6a", nil, "6ed96d65379d5ece656901f5cb20cf554ce18600d4a1edcf6812f4459d7ff73cf2b88cd8476b75e8c08d28", nil, nil, "u149cwhzqdfvattu3dj40anwhge8z4slczq3wyf8m7qqp5uvwdsd5c3d3m55jltnzp0twl34p20mcxkuygvkwdnffuq7vlvl0l2mwlc502czdcfzwndznkqev2p703es0t82aujtdzcgk", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 12, 0],
|
||||
[nil, "4686e569d58d99c1383597fad81193c4c1b16e6a", nil, "b6f481042a780462ffa96f81e1288978e5f05c791587de7e957729bcac6eb95892532b0fe13e9c7eef6a24", nil, nil, "u103cga223qevwyyq9wcdj34ngg2dmh30r7cwcgykjtyuu4kvm6gdye0dh2rkj8g7evq5pauzl8z68jrwn3wqjhcn6tkh058587u92tr6ufh8l4sfpzdmde32x0q28rty6e3pa2fkz5cv", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 12, 1],
|
||||
[nil, "4686e569d58d99c1383597fad81193c4c1b16e6a", nil, "a8e557a58a1908eb8a1bb078b77a95c032fe0a0069ce8c89d3e7705a48d2c08f7b604e5af0218d8cc9c8b8", nil, nil, "u1encagheqh9gl7n7862g0z73fr2nsxzh75zjyyqsuynm03s7pat5se3e0xfpxy8mye9hknymfylzr03mm2h9z4wdpu37fzf4cfmprq6gs2x6xnzwjqtswh39tv0xt9953pam76jh7jxw", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 12, 2],
|
||||
["33a6dd87b4d872a4895d345761e4ec423b77928d", nil, nil, "5178924f7067eac261044ca27ba3cf52f798486973af0795e61587aa1b1ecad333dc520497edc61df88980", 65535, "952fbfee76af61668190bd52ed490e677b515d014384af07219c7c0ee7fc7bfc79f325644e4df4c0d7db08e9f0bd024943c705abff8994bfa605cf", "u105s6j4gpnqtcwpnxl328kea8gf5jrvfw6s4vkjqz0pxnv4963d6l670hhyw5ugl3ydcsm9c3jzhdpn8v23j5p7n9uhn0sp774azjvzx69z9r2s0axl2pflhqdavtwcdrk3jzps9q35j720exual42phm3qyw5kxvdk77p8ug68w5dmuvr5lueu9dk02u84z96ecnc0ztax5atv9qcsedtafa4lex8jrdv5y77v5gtuk5p2pa", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 13, 0],
|
||||
["eb1f66b5cd522c4f6a8e4bb81f3687c95c3939ec", nil, nil, "907639193311a847366c1a43ebaadd935a53180fd3e1219c07c8205f45077bc1768abdcf2425a4a13c4aba", 65535, "bc7ed746a7d3f7c37d9e8bdc433b7d79e08a12f738a8f0dbddfef2f2657ef3e47d1b0fd11e6a13311fb799c79c641d9da43b33e7ad012e28255398", "u1g50gam98jf3xvc8k0d7tcp2wkaxsz9qcmrn6nh3sjqypqcj0mjemdq7mcu5j0mjqduvxj37apk339zh7u3s8ckpkjvqalajeju4ht2w7xnsgy3max0n52dk4nknfvkxy9de9h37fa5rvljm7t0t5033x4pwhklkhgjradmknuvpe0e0z3urxh7cuj8l49tccc3760f8q9nsdv0ezp22vpvldqz9tu4rqjv62thc0ssrqxakn", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 13, 1],
|
||||
["a9e21d18d3b8abaebcc89e7b6ab02def8ee7954e", nil, nil, "2809ddfc7db70c660a6c3fc7560c7add1c7889d9b277cb92d14cb40d2de00aae31670b753a42bdcdc3c220", 65535, "789262275f1175be8462c01491c4d842406d0ec4282c9526174a09878fe8fdde33a29604e5e5e7b2a025d6650b97dbb52befb59b1d30a57433b0a3", "u1285z7wyv8apqxky4hmagy9pu467t0qjhn8tsffjkwu0cduhzmwukwg5702j0mrmgepmekcj5tzd9e6dcyw79xeuhu3jxlaq5p7smeerugn8xddw5l32qstklpvw8f94mapx3hge6tcyukpxa9sdd2at85sftn5097snusewkcs2hz0m3m4chneym59k4krrmaer3wchlwzfvdxw87tsahdv5xjppks5dlm7m3f4ppykud0uy", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 13, 2],
|
||||
["a56c057ef71dab58aa90e47025695c5faaea5123", nil, nil, "b208c9235c8d40e49b76100b2d010f3783f12c66e7d3beb117b2c96321b7f6562adb4efc144e39d909e728", nil, nil, "u1m83339wch8a7z0u78cnz37hcmc98q2lv8nmgmppnanvay5u59m4qym30fyphvnq36evezky5j9fa0eg9gxgfv5nr230uuggvltp6y59t5jxcdlq9q873j35n06zphugwchgwgeaq884", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 14, 0],
|
||||
["d1dbe863479e28f55ad9dd1817d57f253886f310", nil, nil, "332f451dc6f7da17fe5ff4077d3d5db79a036e712df558853d4a854ac4f6e51474cf75f38fa97c22b4cf09", nil, nil, "u1w4qq0ycdlcnat2nkhqcq30wa4shnat0avgcf487t7etge34x8dxqah35drfsh5cmynqumnhdn3h0hhv0d738mskln0hlehph924l83wcju8qjk79pn4q29dp6kgcfvka0mcw6a4vm4k", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 14, 1],
|
||||
["0c2af13bc82480607ea4e52412029bbbce6bb060", nil, nil, "3b68c29b4a138b289fea8b6795e64759a7cd7c0aaf4bb98ed3079959b0bba9b761704b6cfc1465ad74bb05", nil, nil, "u1aujw5lwjlajnysfmjyewn0c2qeann0x4l34axhxg0nd8pvlzglzg00c32jq0urgdc7cam05fte554lqn8wsecpc4pgm8nk5c546egpjwuw262mhgck5dxfrfwevpga2m66u9qskynum", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 14, 2],
|
||||
["228e677b0b428bdbfa4fcaee0714c81963760585", nil, "eee19641bc6b802f353eb793f728b17a277ef0358696a24a7122bc56537b229647f3810d27ce45227c6f39", nil, 65535, "c447586f69173446d8e48bf84cbc000a807899973eb93c5e819aad669413f8387933ad1584aa35e43f4ecd1e2d0407c0b1b89920ffdfdb9bea51ac95b557af71b89f903f5d9848f14fcbeb1837570f544d6359eb23faf38a0822da36ce426c4a2fbeffeb0a8a2e297a9d19ba15024590e332", "u1u5kkc8lggdf4dgg9t7qg8vfpd06zvpcetq34rw55yg329kqrclj99atez0hn7jtg0cw5qh7jxewees0ynpv2hlkhtcpgsjjm22zrh8hn8j7uddvrwt07dwqfwh7mqkft326ft4y038s9y77dentqeynw2g6smh7s0ceuah6lylvxj07ex474u2lsh44m59gep2wywskwt54wx299jsr0h7rn9z6vhp59sxf5ey8qczv5ck6d0czkupvua6kcl6h6n3ssqvcfueh46xwr07clhexdjax9l45turlwxd9s8xc5c3nczmd2uyseut2zrra3kg6sucdj", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 15, 0],
|
||||
["55a6349abd9eadcdbbcd337c71f09723b241beee", nil, "50ca46f825f7f423007aa4147169b529f07f1c8ed634fafc8145a4813177dd1257ee8d8fc5f44e9b564f6a", nil, 65535, "9d9fa9261f9938a4032dd34606c9cf9f3dd33e576f05cd1dd6811c6298757d77d9e810abdb226afcaa4346a6560f8932b3181fd355d5d391976183f8d99388839632d6354f666d09d3e5629ea19737388613d38a34fd0f6e50ee5a0cc9677177f50028c141378187bd2819403fc534f80076", "u1pcqreshyawlmmskegkjvulf8xk6h97nxckx88aj6m88qu2zeucf4kywfsz43fjrce6w4w5jv5e28n430z2jlj9vfv5yrs5cudx3qv8p7d9jmx5vhayk9a8gyl49yfjp46t6c7d8vh5jhuu7llfkzt2gswkvt2368cpjc0u8u2sgawtgzu07y55raunrx5n48v3tuzpwv8273tnrunh40yu3gk98zhg0pmjcjg8c3tf3qmnfr8zm93eynplk4jx7ypev84pl0yxhk5ckq8zr5gv267skrmcpqgngpnrn43hl9awe7qwvzhds7zg6qtfp9fggpnmvc", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 15, 2],
|
||||
["f7b2c94ce3ca21526b6b472d3d5611fa98bec498", nil, "c412c8ff78f28d9b3391f4ab15d06acf46ac052821ee096a51524813f2adf9a4065cc6c45feba2c052df9e", nil, 65535, "e9380cb4964d3b6b45819d3b8e9caf54f051852d671bf8c1ffde2d1510756418cb4810936aa57e6965d6fb656a760b7f19adf96c173488552193b147ee58858033dac7cd0eb204c06490bbdedf5f7571acb2ebe76acef3f2a01ee987486dfe6c3f0a5e234c127258f97a28fb5d164a8176be", "u1dffmg4dp98h39xcvv4ghgaz76fmu50pezp8uf7xpyysj3ye8j9e07r8sdhge4yjk6ssl94qna5lwc6sjpdzk43tvf2gpxlzkymktqy9az77rjavvawy57xu5tyaevekq3esd5g23ew6gpt9srj9fqxusx4u5qnvwl4f3y39v2ryld8plc34x9l2y73m6wzk72gjepe536wf92q4065taed6cmcgkvr65rzv268qwhmwk5z77fkcseac3ewsmuxa4suzkzv0383yaykyj9a6v2xxg24p7e5k8paxadd59xs330t9nm6geuu2jps6ejh69asqak3x0", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 15, 3],
|
||||
[nil, nil, nil, "2598d84dffb34f5908b90732490f3881399150d4c694fce9bf30d1560b2c56f09829fe123b9add20e5d71c", nil, nil, "u12jl7f8zw52z4lqvy6rdfc5q4zlz0gr50uq87zgwr6nvcu8pfkpnajx8uyj8utlsyekj7uafehuxn3tg8ufczgk8xwzj2fz0fjvh9fr8p", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 16, 0],
|
||||
[nil, nil, nil, "c1150ae8529e667015c462f91fb26e9124095aebd6e72fca95a2fe17ae53e8cb101eda84d9fb4d336ee103", nil, nil, "u1xxndf9jxq3k60r2walgtza0e67nqvuwuhc3va3trhhgkkgynnwzjrwthktt68w2es9vwehgx2rx0sqt65ru087vutdh2v52ypcu8ylkh", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 16, 1],
|
||||
[nil, nil, nil, "e961944a708a15c9c62734c34510bb5e2cd740abdeb488e4142b5d402b0295bec67922f1e71ab7fbd0a2ae", nil, nil, "u14ke36gmjx6xj370ntw3h3ruyl2ad57d8ma5zvwd22ygjfsycmgr6ft4pjm7l2gw3xzglz4lrh9v9mzgaj08vsghqaw062j5uvvxlwc54", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 16, 2],
|
||||
[nil, nil, "d3a803803feee7a032a24adfaa8f6a94cecb9671c1333d0d5d1a3d79d82bc310727c665364d71022559c50", "7c98b8f613f9ff02746bea2a167cfd1bd3a1862af9631bf61d9d604e0824e2cb8467a1e549db87a76e7a8a", nil, nil, "u1a64l09qrsxulfjznm6k2g535usyhtaf8ed60v4jrjmkwvkux4t7pdyc3nkzrefdgtnw8420lj8shm05ja9fxxgnhra92nhsq56gx8c2puz3fkkgnrkqf5yuqfdtf7t6ran47gdcf5vvdfaczwf3uuy4fysh3mzu8hd5tkl05mvrge9n8", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 17, 0],
|
||||
[nil, nil, "25c25d58c50533dfb55d29f9a8864f58f02ea4fed44369352c43538cdf9545b905bb2ef0961bd2daf25883", "8a1bff2a9d921e1153b3cb264bc05185a9811de911d53467935434d6537d306752d02054fe5a170464259d", nil, nil, "u1f2mk4p04nnn9rmxqs4elkmqd42l0gxzfeurrn2zdedrjutx6fh0hgxz8avdlq45uv5achkjguvpyay329sk2raxkswspfy9z4m9a2yn8mkla3qpjpe3d9slczyj3ulf3pdvf2yrswayxj9ausn7d2zze850ctvkrltfjvvsjwgnkues4", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 17, 1],
|
||||
[nil, nil, "54b7fc0c85d378f375be48218a85424bb9e7a304830e9eb7255a12a09c961cca1f629b867e13242ed90d92", "14adca6f616abcbe5bc850cc617dcf999517a9a790292fec6bc0761eaa790333e7d06d016de05bca7c6712", nil, nil, "u1cha4ke52axxa37d3y5yjcdkpxjtgqvckww9zaecaq96c59y2hzm3hqsu5pktakkjhcl2r28ltdx95lfvq7y9wd5w4w0hfdrhgy0tkczephu30py7qyp7ftth92e68hhkjepj32xm2fp538p37nssx867g8t5apu84unc39ywxyltjhyq", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 17, 2],
|
||||
["26c061d67beb8bad48c6b4774a156551e30e4fe2", nil, "bd51d90654e25613b5a4839dda2b9524ef4b12e7dbdccf3d4af150b06d95758afeb029227396094faf914a", nil, nil, nil, "u1p2nrze8u4geddlwn0dnppywuux58u4f24uqkfy6qns2hx2x3rm670q40ksp84ke2j3dfk0jn04gr3w4jp6yl69w48mxy795p98xfp5mvw7tkdp2utzm8fxjwm0u7fm79sx0c5h78ghx", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 18, 0],
|
||||
["42874a6933bef7334702243232380781df8a71c5", nil, "4cea9549426d764dbd1b80c229e230a3bf3ca821b97c9847488afe37341634df27c3a634c2253436d98612", nil, nil, nil, "u1ufx6z3ck7ylkuph78pjpjgjflxh6dvvjx5aq7v8mwt4r3dlk4eyxqnk9tenck573vngsq555afelws0t5gm2rtuvswagsasff4naa4pkwnflcaxctxcvgy3m558mh7cgcgn26gq9a69", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 18, 5],
|
||||
["c7ce0d050e10a82486bfab0a16537829dc6cf018", nil, "02221bc1820ca2b1940e532f00042367ee96acfe9f83476661a1ca4131e5d7485f4a49e0992a8917380f8b", nil, nil, nil, "u15quy62m78qxdl4yw5dzvt89vs0d6euwsa4mj4csxhyp0t7q40tggrlfyl3vt85caa53mg3xyz64xutxuzg7mmkyqydqypta2c6g2g9kgk3nu75jrnk6xj7eprpu5l36v2esykxfz0wh", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 18, 7],
|
||||
[nil, nil, "8660070e3757ff6507060791fd694f6a631b8495a2b74ffa39236cf653caea5575b86af3200b010e513bab", "63b7b706d991169986aee56133f0a50b2a0c8225fba6dae95176007b1f023a1e97c1aa366e99bf970fda82", nil, nil, "u1vg62mgjddnlv5w6ldky2xe0c8tetmc82tu9vlzzkuynx49fnuqjvxjt5dgn3cm8t5n85zcq5ljrtg7zmwhk70h6rdmclf7scxxnguk5flvf2app76xu907cmjylxvsen25xe9v7v3krsxa9uy0v2jjq37kh4ymlafn8pevqalqa4dm67", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 19, 5],
|
||||
[nil, nil, "6d75a1a948a4e730db3b4b816dbc7d80b4eb1bc68de9ac87b0cd1f1b3e6068e677888e105ac727c0d14b49", "52692e9402a8c14a225ec9dcf75a5588392e4da69e416f124e32168ff483144973d7ac8c23e4277fde5cb0", nil, nil, "u1z8m2p8pzzsxdek3x784l5xkd56u68wvv708pn475tkvultp7h6u66r8kxf9kttyahqnpdhvg9rfrmudxsf5le0c9mjmk942jm0yr78epqnwptzjuawgdhgy60zus2l62403hk5nlzhqlet85atyg88xxrwwj8dmvx98cy47g7s7qdsq7", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 19, 11],
|
||||
[nil, nil, "38b14b44ed6f4a3ae8c5c3923e5770b786f9b41d46c65a149b13910f4a0a64e83bb9bc98e80d9576fbf76e", "4b42498b76509868e9e74d75357ba19be8e9d55d024adf4e06c756c830e74a46df5bceeaeee595a6ed333e", nil, nil, "u1yuv2ls5k0xaym2lc4je6mf3djvmkyqdrxhcue25d4243udr0e97pyzhs9u3yl9q5de24tzxxdl2wfy4vvdw3wmu78sggdjq8xrshdztxnk3p6lqe4hk952fnq7qxggyxmnvtlkl3pns09zysunxu288jme6qlvjlhh5ry0fqyg5rs00y", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 19, 15]
|
||||
]
|
79
changelog.md
79
changelog.md
|
@ -1,6 +1,82 @@
|
|||
# Unified Spending Keys
|
||||
|
||||
## Changes to Demo APP
|
||||
The demo application now uses the SDKSynchronizer to create addresses and
|
||||
shield funds.
|
||||
`DerivationToolViewController` was removed. See `DerivationTool` unit tests
|
||||
for sample code.
|
||||
`GetAddressViewController` now derives transparent and sapling addresses
|
||||
from Unified Address
|
||||
`SendViewController` uses Unified Spending Key and type-safe `Memo`
|
||||
|
||||
## Changes To SDK
|
||||
### `CompactBlockProcessor`
|
||||
`public func getUnifiedAddress(accountIndex: Int) -> UnifiedAddress?`
|
||||
`public func getSaplingAddress(accountIndex: Int) -> SaplingAddress?` derived from UA
|
||||
`public func getTransparentAddress(accountIndex: Int) -> TransparentAddress?`
|
||||
is derived from UA
|
||||
`public func getTransparentBalance(accountIndex: Int) throws -> WalletBalance` now
|
||||
fetches from account exclusively
|
||||
`func refreshUTXOs(tAddress: TransparentAddress, startHeight: BlockHeight) async throws -> RefreshedUTXOs`
|
||||
uses `TransparentAddress`
|
||||
|
||||
### Initializer
|
||||
Migration of DataDB and CacheDB are delegated to `librustzcash`
|
||||
|
||||
removed `public func getAddress(index account: Int = 0) -> String`
|
||||
|
||||
|
||||
### Wallet Types
|
||||
`UnifiedSpendingKey` to represent Unified Spending Keys. This is a binary
|
||||
encoded not meant to be stored or backed up. This only serves the purpuse
|
||||
of letting clients use the least priviledge keys at all times for every
|
||||
operation.
|
||||
|
||||
### Synchronizer
|
||||
`sendToAddress` and `shieldFunds` now take a `UnifiedSpendingKey` instead
|
||||
of the respective spending and transparent private keys.
|
||||
`refreshUTXOs` uses `TransparentAddress`
|
||||
|
||||
### KeyDeriving protocol
|
||||
Addresses should be obtained from the `Synchronizer` by using the `get_address` functions
|
||||
Transparent and Sapling receivers should be obtained by extracting the receivers of a UA
|
||||
````Swift
|
||||
public extension UnifiedAddress {
|
||||
/// Extracts the sapling receiver from this UA if available
|
||||
/// - Returns: an `Optional<SaplingAddress>`
|
||||
func saplingReceiver() -> SaplingAddress? {
|
||||
try? DerivationTool.saplingReceiver(from: self)
|
||||
}
|
||||
|
||||
/// Extracts the transparent receiver from this UA if available
|
||||
/// - Returns: an `Optional<TransparentAddress>`
|
||||
func transparentReceiver() -> TransparentAddress? {
|
||||
try? DerivationTool.transparentReceiver(from: self)
|
||||
}
|
||||
````
|
||||
|
||||
**Removed**
|
||||
`func deriveUnifiedFullViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey]`
|
||||
`func deriveViewingKey(spendingKey: SaplingExtendedSpendingKey) throws -> SaplingExtendedFullViewingKey`
|
||||
`func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [SaplingExtendedSpendingKey]`
|
||||
`func deriveUnifiedAddress(from ufvk: UnifiedFullViewingKey) throws -> UnifiedAddress`
|
||||
`func deriveTransparentAddress(seed: [UInt8], account: Int, index: Int) throws -> TransparentAddress`
|
||||
`func deriveTransparentAccountPrivateKey(seed: [UInt8], account: Int) throws -> TransparentAccountPrivKey`
|
||||
`func deriveTransparentAddressFromAccountPrivateKey(_ xprv: TransparentAccountPrivKey, index: Int) throws -> TransparentAddress`
|
||||
|
||||
**Added**
|
||||
`static func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress?`
|
||||
`static func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress?`
|
||||
`static func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes]`
|
||||
`func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) throws -> UnifiedSpendingKey`
|
||||
`public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) throws -> UnifiedFullViewingKey`
|
||||
|
||||
|
||||
|
||||
|
||||
# 0.16.10-beta
|
||||
- [#532] [0.16.x-beta] Download does not stop correctly
|
||||
|
||||
|
||||
Issue Reported:
|
||||
|
||||
When the synchronizer is stopped, the processor does not cancel
|
||||
|
@ -20,6 +96,7 @@ Mainnet
|
|||
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/1807500.json
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/1810000.json
|
||||
````
|
||||
|
||||
# 0.16.9-beta
|
||||
Checkpoints added:
|
||||
Mainnet
|
||||
|
|
Loading…
Reference in New Issue