[#981] Send button disable check must include the fee
- the fee is now checked and it's coming from the SDK - unit test checking validity of the form when not enough Zatoshi for the fee has been implemented - brand new concept of handling the SDK constants inside the TCA has been implemented, will greatly simplify cleanup of all reducers (see #1058)
This commit is contained in:
parent
b668b15f04
commit
0faa37c243
|
@ -13,18 +13,22 @@ import DatabaseFiles
|
|||
import Models
|
||||
import ZcashSDKEnvironment
|
||||
|
||||
extension SDKSynchronizerClient {
|
||||
extension SDKSynchronizerClient: DependencyKey {
|
||||
public static let liveValue: SDKSynchronizerClient = Self.live()
|
||||
|
||||
public static func live(
|
||||
databaseFiles: DatabaseFilesClient = .liveValue,
|
||||
environment: ZcashSDKEnvironment = .liveValue,
|
||||
network: ZcashNetwork
|
||||
databaseFiles: DatabaseFilesClient = .liveValue
|
||||
) -> Self {
|
||||
@Dependency (\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||
|
||||
let network = zcashSDKEnvironment.network
|
||||
|
||||
let initializer = Initializer(
|
||||
cacheDbURL: databaseFiles.cacheDbURLFor(network),
|
||||
fsBlockDbRoot: databaseFiles.fsBlockDbRootFor(network),
|
||||
generalStorageURL: databaseFiles.documentsDirectory(),
|
||||
dataDbURL: databaseFiles.dataDbURLFor(network),
|
||||
endpoint: environment.endpoint(network),
|
||||
endpoint: zcashSDKEnvironment.endpoint(),
|
||||
network: network,
|
||||
spendParamsURL: databaseFiles.spendParamsURLFor(network),
|
||||
outputParamsURL: databaseFiles.outputParamsURLFor(network),
|
||||
|
|
|
@ -108,7 +108,7 @@ extension ZcashSDKEnvironment {
|
|||
static let streamingCallTimeoutInMillis = Int64(10 * 60 * 60 * 1000) // ten hours
|
||||
}
|
||||
|
||||
public static func endpoint(for network: ZcashNetwork) -> String {
|
||||
public static func endpointString(for network: ZcashNetwork) -> String {
|
||||
switch network.networkType {
|
||||
case .testnet:
|
||||
return ZcashSDKConstants.endpointTestnetAddress
|
||||
|
@ -119,10 +119,12 @@ extension ZcashSDKEnvironment {
|
|||
}
|
||||
|
||||
public struct ZcashSDKEnvironment {
|
||||
public var latestCheckpoint: (ZcashNetwork) -> BlockHeight //{ BlockHeight.ofLatestCheckpoint(network: network()) }
|
||||
public let endpoint: (ZcashNetwork) -> LightWalletEndpoint
|
||||
public var latestCheckpoint: BlockHeight
|
||||
public let endpoint: () -> LightWalletEndpoint
|
||||
public let memoCharLimit: Int
|
||||
public let mnemonicWordsMaxCount: Int
|
||||
public let network: ZcashNetwork
|
||||
public let requiredTransactionConfirmations: Int
|
||||
public let sdkVersion: String
|
||||
public let tokenName: String
|
||||
}
|
||||
|
|
|
@ -8,40 +8,44 @@
|
|||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension ZcashSDKEnvironment: DependencyKey {
|
||||
public static let liveValue = Self(
|
||||
latestCheckpoint: { network in BlockHeight.ofLatestCheckpoint(network: network) },
|
||||
endpoint: { network in
|
||||
// In case of mainnet network we may have stored server as a user action in advanced settings
|
||||
if network.networkType == .mainnet {
|
||||
@Dependency(\.userDefaults) var userDefaults
|
||||
|
||||
let udKey = ZcashSDKEnvironment.Servers.Constants.udServerKey
|
||||
|
||||
if let storedServerRaw = userDefaults.objectForKey(udKey) as? String,
|
||||
let storedServer = ZcashSDKEnvironment.Servers(rawValue: storedServerRaw) {
|
||||
if let endpoint = storedServer.lightWalletEndpoint(userDefaults) {
|
||||
// Some endpoint is set by a user so we initialize the SDK with this one
|
||||
return endpoint
|
||||
} else {
|
||||
// Initalization of LightWalletEndpoint failed, fallback to hardcoded one,
|
||||
// setting the mainnet key to the storage to reflect that
|
||||
userDefaults.setValue(ZcashSDKEnvironment.Servers.mainnet.rawValue, udKey)
|
||||
extension ZcashSDKEnvironment {
|
||||
public static func live(network: ZcashNetwork) -> Self {
|
||||
Self(
|
||||
latestCheckpoint: BlockHeight.ofLatestCheckpoint(network: network),
|
||||
endpoint: {
|
||||
// In case of mainnet network we may have stored server as a user action in advanced settings
|
||||
if network.networkType == .mainnet {
|
||||
@Dependency(\.userDefaults) var userDefaults
|
||||
|
||||
let udKey = ZcashSDKEnvironment.Servers.Constants.udServerKey
|
||||
|
||||
if let storedServerRaw = userDefaults.objectForKey(udKey) as? String,
|
||||
let storedServer = ZcashSDKEnvironment.Servers(rawValue: storedServerRaw) {
|
||||
if let endpoint = storedServer.lightWalletEndpoint(userDefaults) {
|
||||
// Some endpoint is set by a user so we initialize the SDK with this one
|
||||
return endpoint
|
||||
} else {
|
||||
// Initalization of LightWalletEndpoint failed, fallback to hardcoded one,
|
||||
// setting the mainnet key to the storage to reflect that
|
||||
userDefaults.setValue(ZcashSDKEnvironment.Servers.mainnet.rawValue, udKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hardcoded endpoint
|
||||
return LightWalletEndpoint(
|
||||
address: Self.endpoint(for: network),
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
)
|
||||
},
|
||||
memoCharLimit: MemoBytes.capacity,
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations,
|
||||
sdkVersion: "0.18.1-beta"
|
||||
)
|
||||
|
||||
// Hardcoded endpoint
|
||||
return LightWalletEndpoint(
|
||||
address: Self.endpointString(for: network),
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
)
|
||||
},
|
||||
memoCharLimit: MemoBytes.capacity,
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
network: network,
|
||||
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations,
|
||||
sdkVersion: "0.18.1-beta",
|
||||
tokenName: network.networkType == .testnet ? "TAZ" : "ZEC"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ import ZcashLightClientKit
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension ZcashSDKEnvironment: TestDependencyKey {
|
||||
public static let testnet = ZcashSDKEnvironment.liveValue
|
||||
public static let testnet = ZcashSDKEnvironment.live(network: ZcashNetworkBuilder.network(for: .testnet))
|
||||
|
||||
public static let testValue = Self(
|
||||
latestCheckpoint: { _ in 0 },
|
||||
endpoint: { _ in
|
||||
latestCheckpoint: 0,
|
||||
endpoint: {
|
||||
LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointTestnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
|
@ -24,7 +24,9 @@ extension ZcashSDKEnvironment: TestDependencyKey {
|
|||
},
|
||||
memoCharLimit: MemoBytes.capacity,
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
network: ZcashNetworkBuilder.network(for: .testnet),
|
||||
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations,
|
||||
sdkVersion: "0.18.1-beta"
|
||||
sdkVersion: "0.18.1-beta",
|
||||
tokenName: "TAZ"
|
||||
)
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ extension RootReducer {
|
|||
return .none
|
||||
}
|
||||
|
||||
let birthday = state.storedWallet?.birthday?.value() ?? zcashSDKEnvironment.latestCheckpoint(zcashNetwork)
|
||||
let birthday = state.storedWallet?.birthday?.value() ?? zcashSDKEnvironment.latestCheckpoint
|
||||
|
||||
try mnemonic.isValid(storedWallet.seedPhrase.value())
|
||||
let seedBytes = try mnemonic.toSeed(storedWallet.seedPhrase.value())
|
||||
|
|
|
@ -93,7 +93,7 @@ public struct SecurityWarningReducer: Reducer {
|
|||
do {
|
||||
// get the random english mnemonic
|
||||
let newRandomPhrase = try mnemonic.randomMnemonic()
|
||||
let birthday = zcashSDKEnvironment.latestCheckpoint(zcashNetwork)
|
||||
let birthday = zcashSDKEnvironment.latestCheckpoint
|
||||
|
||||
// store the wallet to the keychain
|
||||
try walletStorage.importWallet(newRandomPhrase, birthday, .english, false)
|
||||
|
|
|
@ -78,7 +78,9 @@ public struct SendFlowReducer: Reducer {
|
|||
}
|
||||
|
||||
public var isValidForm: Bool {
|
||||
transactionAmountInputState.amount.data > 0
|
||||
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||
|
||||
return transactionAmountInputState.amount.data > zcashSDKEnvironment.network.constants.defaultFee().amount
|
||||
&& transactionAddressInputState.isValidAddress
|
||||
&& !isInsufficientFunds
|
||||
&& memoState.isValid
|
||||
|
|
|
@ -12,6 +12,7 @@ import ZcashLightClientKit
|
|||
import SDKSynchronizer
|
||||
import Utils
|
||||
import Root
|
||||
import ZcashSDKEnvironment
|
||||
|
||||
@main
|
||||
struct SecantApp: App {
|
||||
|
@ -74,6 +75,6 @@ public enum TargetConstants {
|
|||
}
|
||||
}
|
||||
|
||||
extension SDKSynchronizerClient: DependencyKey {
|
||||
public static let liveValue: SDKSynchronizerClient = Self.live(network: TargetConstants.zcashNetwork)
|
||||
extension ZcashSDKEnvironment: DependencyKey {
|
||||
public static let liveValue: ZcashSDKEnvironment = Self.live(network: TargetConstants.zcashNetwork)
|
||||
}
|
||||
|
|
|
@ -409,6 +409,49 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func testValidForm_NoFees() async throws {
|
||||
let sendState = SendFlowReducer.State(
|
||||
addMemoState: true,
|
||||
memoState: .initial,
|
||||
scanState: .initial,
|
||||
transactionAddressInputState: .initial,
|
||||
transactionAmountInputState:
|
||||
TransactionAmountTextFieldReducer.State(
|
||||
amount: Int64(9_000).redacted,
|
||||
currencySelectionState: CurrencySelectionReducer.State(),
|
||||
maxValue: Int64(501_302).redacted,
|
||||
textFieldState:
|
||||
TCATextFieldReducer.State(
|
||||
validationType: .customFloatingPoint(usNumberFormatter),
|
||||
text: "0.00501301".redacted
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState
|
||||
) {
|
||||
SendFlowReducer(networkType: .testnet)
|
||||
}
|
||||
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.isZcashAddress = { _, _ in true }
|
||||
|
||||
let address = "t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po".redacted
|
||||
|
||||
await store.send(.transactionAddressInput(.textField(.set(address)))) { state in
|
||||
state.transactionAddressInputState.textFieldState.text = address
|
||||
// true is expected here because textField doesn't have any `validationType: String.ValidationType?`
|
||||
// isValid function returns true, `guard let validationType else { return true }`
|
||||
state.transactionAddressInputState.textFieldState.valid = true
|
||||
state.transactionAddressInputState.isValidAddress = true
|
||||
XCTAssertFalse(
|
||||
state.isValidForm,
|
||||
"Send Tests: `testValidForm` is expected to be false but it's \(state.isValidForm)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testInvalidForm_InsufficientFunds() async throws {
|
||||
let sendState = SendFlowReducer.State(
|
||||
addMemoState: true,
|
||||
|
|
Loading…
Reference in New Issue