Skip to content

Commit

Permalink
(ios) Display swap-in grace period & timeouts (#454)
Browse files Browse the repository at this point in the history
  • Loading branch information
robbiehanson authored Oct 24, 2023
1 parent 47c950b commit 7a29411
Show file tree
Hide file tree
Showing 16 changed files with 963 additions and 682 deletions.
6 changes: 6 additions & 0 deletions phoenix-ios/phoenix-ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@
DC81B79F25BF2AA200F5A52C /* MVI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC81B79E25BF2AA200F5A52C /* MVI.swift */; };
DC82EED629789853007A5853 /* TxHistoryExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC82EED529789853007A5853 /* TxHistoryExporter.swift */; };
DC89857F25914747007B253F /* UIApplicationState+Phoenix.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC89857E25914747007B253F /* UIApplicationState+Phoenix.swift */; };
DC9130A02AE045FA00F9B8C6 /* Sequence+Sum.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC59377027516296003B4B53 /* Sequence+Sum.swift */; };
DC9473FA261270B4008D7242 /* MVI+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9473F9261270B4008D7242 /* MVI+Mock.swift */; };
DC9545C429490321008FCEF4 /* NotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9545C329490321008FCEF4 /* NotificationContent.swift */; };
DC9545C5294905FB008FCEF4 /* NotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9545C329490321008FCEF4 /* NotificationContent.swift */; };
Expand Down Expand Up @@ -275,6 +276,7 @@
DCFAEFC92A72F48700330088 /* SwapInWalletDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFAEFC82A72F48700330088 /* SwapInWalletDetails.swift */; };
DCFB8DF72A94066100947698 /* Task+Sleep.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB8DF62A94066100947698 /* Task+Sleep.swift */; };
DCFB8DF92A94112A00947698 /* Dictionary+MapKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB8DF82A94112A00947698 /* Dictionary+MapKeys.swift */; };
DCFBC5592AE2CFEF00E3A418 /* BizNotificationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFBC5582AE2CFEF00E3A418 /* BizNotificationCell.swift */; };
DCFC72042862237400D6B293 /* Asserts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFC72032862237400D6B293 /* Asserts.swift */; };
DCFD079126D84A380020DD8E /* HorizontalActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFD079026D84A380020DD8E /* HorizontalActivity.swift */; };
F4AED298257A50CD009485C1 /* LogsConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AED296257A50CD009485C1 /* LogsConfigurationView.swift */; };
Expand Down Expand Up @@ -593,6 +595,7 @@
DCFAEFC82A72F48700330088 /* SwapInWalletDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapInWalletDetails.swift; sourceTree = "<group>"; };
DCFB8DF62A94066100947698 /* Task+Sleep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Task+Sleep.swift"; sourceTree = "<group>"; };
DCFB8DF82A94112A00947698 /* Dictionary+MapKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+MapKeys.swift"; sourceTree = "<group>"; };
DCFBC5582AE2CFEF00E3A418 /* BizNotificationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BizNotificationCell.swift; sourceTree = "<group>"; };
DCFC72032862237400D6B293 /* Asserts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Asserts.swift; sourceTree = "<group>"; };
DCFD079026D84A380020DD8E /* HorizontalActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalActivity.swift; sourceTree = "<group>"; };
F4AED296257A50CD009485C1 /* LogsConfigurationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogsConfigurationView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1015,6 +1018,7 @@
DC355E242A45FDD3008E8A8E /* NoticeMonitor.swift */,
DC355E1E2A44A235008E8A8E /* NotificationCell.swift */,
DC355E202A44D838008E8A8E /* NotificationsView.swift */,
DCFBC5582AE2CFEF00E3A418 /* BizNotificationCell.swift */,
);
path = notifications;
sourceTree = "<group>";
Expand Down Expand Up @@ -1753,6 +1757,7 @@
DC27E4C42791C58C00C777CC /* PaymentsBackupView.swift in Sources */,
DC59377127516297003B4B53 /* Sequence+Sum.swift in Sources */,
DCA125752A27EDDB00DA2F7F /* MempoolRecommendedResponse.swift in Sources */,
DCFBC5592AE2CFEF00E3A418 /* BizNotificationCell.swift in Sources */,
DC46CB1228D9AAB000C4EAC7 /* LockState.swift in Sources */,
DC2F431427B6972C0006FCC4 /* SwapInView.swift in Sources */,
DC71E7352728A5720063613D /* KotlinIdentifiable.swift in Sources */,
Expand Down Expand Up @@ -1786,6 +1791,7 @@
DC641C7328208B7F00862DCD /* UserDefaults+Codable.swift in Sources */,
DCA6DED1282ABA930073C658 /* KeychainConstants.swift in Sources */,
DCEB2796282D7AAB0096B87E /* KotlinTypes.swift in Sources */,
DC9130A02AE045FA00F9B8C6 /* Sequence+Sum.swift in Sources */,
DCB511CA281AED58001BC525 /* NotificationService.swift in Sources */,
DCA6DEC82829C3150073C658 /* GenericPasswordStore.swift in Sources */,
DCA6DECD282AB10C0073C658 /* SharedSecurity.swift in Sources */,
Expand Down
49 changes: 49 additions & 0 deletions phoenix-ios/phoenix-ios/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1985,6 +1985,9 @@
}
}
}
},
"A deposit will expire soon." : {

},
"A fee of %@ (≈ %@) may be needed to receive this payment." : {
"localizations" : {
Expand Down Expand Up @@ -2858,6 +2861,7 @@
}
},
"An on-chain wallet derived from your seed.\n\nThe swap-in wallet is a bridge to Lightning. Funds on this wallet will automatically be moved to Lightning according to your liquidity policy setting." : {
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
Expand Down Expand Up @@ -3388,8 +3392,12 @@
}
}
}
},
"Background payments disabled." : {

},
"Background payments disabled. " : {
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
Expand Down Expand Up @@ -4184,6 +4192,9 @@
}
}
}
},
"Cancelled Funds" : {

},
"capacity" : {
"localizations" : {
Expand Down Expand Up @@ -4466,6 +4477,7 @@
}
},
"Check it " : {
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
Expand Down Expand Up @@ -7730,6 +7742,7 @@
}
},
"Error: invalid hash" : {
"extractionState" : "stale",
"localizations" : {
"ar" : {
"stringUnit" : {
Expand Down Expand Up @@ -8489,6 +8502,7 @@
}
},
"Fix " : {
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
Expand Down Expand Up @@ -8839,6 +8853,9 @@
}
}
}
},
"Funds not swapped **after 4 months** are recoverable on-chain" : {

},
"Funds sent" : {
"localizations" : {
Expand Down Expand Up @@ -10618,6 +10635,7 @@
}
},
"Last Attempt" : {
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
Expand All @@ -10632,6 +10650,9 @@
}
}
}
},
"Last attempt failed" : {

},
"layer 1 -> 2" : {
"comment" : "Transaction Info: Explanation",
Expand Down Expand Up @@ -10752,6 +10773,7 @@
}
},
"Let's go " : {
"extractionState" : "stale",
"localizations" : {
"ar" : {
"stringUnit" : {
Expand Down Expand Up @@ -12045,6 +12067,7 @@
}
},
"More info " : {
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
Expand Down Expand Up @@ -15720,6 +15743,7 @@
}
},
"See how Phoenix is affected" : {
"extractionState" : "stale",
"localizations" : {
"ar" : {
"stringUnit" : {
Expand Down Expand Up @@ -18405,6 +18429,9 @@
}
}
}
},
"The swap-in wallet is a bridge to Lightning. Funds on this wallet will automatically be moved to Lightning according to your liquidity policy setting." : {

},
"The transaction may take 30 minutes or more to confirm on the bitcoin blockchain" : {
"localizations" : {
Expand Down Expand Up @@ -18475,6 +18502,15 @@
}
}
}
},
"These funds were not swapped in time. Use the wallet's descriptor to access them." : {

},
"These funds will be available from %lld days onwards." : {

},
"These funds will be available from 1 day onwards." : {

},
"This address is derived from your seed and belongs to you." : {
"localizations" : {
Expand Down Expand Up @@ -18823,6 +18859,12 @@
}
}
}
},
"This swap will expire in %lld days" : {

},
"This swap will expire in 1 day" : {

},
"This will reset the app, as if you had just installed it." : {
"localizations" : {
Expand Down Expand Up @@ -18883,6 +18925,9 @@
}
}
}
},
"Timed-Out Funds" : {

},
"timestamp" : {
"comment" : "Label in DetailsView_IncomingPayment",
Expand Down Expand Up @@ -20777,8 +20822,12 @@
}
}
}
},
"Watchtower disabled." : {

},
"Watchtower disabled. " : {
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
Expand Down
2 changes: 1 addition & 1 deletion phoenix-ios/phoenix-ios/extensions/Sequence+Sum.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Foundation

extension Sequence where Element: AdditiveArithmetic {
func sum() -> Element { reduce(.zero, +) }
func sum() -> Element { reduce(.zero, +) }
}
67 changes: 62 additions & 5 deletions phoenix-ios/phoenix-ios/kotlin/KotlinExtensions+Lightning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,89 @@ extension Lightning_kmpConnection {
extension Lightning_kmpWalletState.WalletWithConfirmations {

var unconfirmedBalance: Bitcoin_kmpSatoshi {
let balance = unconfirmed.map { $0.amount }.reduce(Int64(0)) { $0 + $1.toLong() }
let balance = unconfirmed.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

var weaklyConfirmedBalance: Bitcoin_kmpSatoshi {
let balance = weaklyConfirmed.map { $0.amount }.reduce(Int64(0)) { $0 + $1.toLong() }
let balance = weaklyConfirmed.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

var deeplyConfirmedBalance: Bitcoin_kmpSatoshi {
let balance = deeplyConfirmed.map { $0.amount }.reduce(Int64(0)) { $0 + $1.toLong() }
let balance = deeplyConfirmed.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

var lockedUntilRefundBalance: Bitcoin_kmpSatoshi {
let balance = lockedUntilRefund.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

var readyForRefundBalance: Bitcoin_kmpSatoshi {
let balance = readyForRefund.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

var anyConfirmedBalance: Bitcoin_kmpSatoshi {
let anyConfirmedTx = weaklyConfirmed + deeplyConfirmed
let balance = anyConfirmedTx.map { $0.amount }.reduce(Int64(0)) { $0 + $1.toLong() }
let balance = anyConfirmedTx.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

var totalBalance: Bitcoin_kmpSatoshi {
let allTx = unconfirmed + weaklyConfirmed + deeplyConfirmed
let balance = allTx.map { $0.amount }.reduce(Int64(0)) { $0 + $1.toLong() }
let balance = allTx.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

/// The `deeplyConfirmed` property contains UTXO's that are also represented in
/// `lockedUntilRefund` & `readyForRefund`. This property is a subset of
/// `deeplyConfirmed` that excludes those 2 categories.
///
var readyForSwap: [Lightning_kmpWalletState.Utxo] {
let timedOut = Set(self.lockedUntilRefund + self.readyForRefund)
return deeplyConfirmed.filter {
!timedOut.contains($0)
}
}

var readyForSwapBalance: Bitcoin_kmpSatoshi {
let balance = readyForSwap.map { $0.amount.toLong() }.sum()
return Bitcoin_kmpSatoshi(sat: balance)
}

/// Returns non-nil if any "ready for swap" UTXO's have an expiration date that
/// is less than 30 days away.
func expirationWarningInDays() -> Int? {

let maxConfirmations = swapInParams.maxConfirmations
let remainingConfirmationsList = readyForSwap.map {
maxConfirmations - confirmations(utxo: $0)
}

if let minRemainingConfirmations = remainingConfirmationsList.min() {
let days: Double = Double(minRemainingConfirmations) / 144.0
let result = Int(days.rounded(.awayFromZero))
if result < 30 {
return result
}
}

return nil
}

#if DEBUG
func fakeBlockHeight(plus diff: Int32) -> Lightning_kmpWalletState.WalletWithConfirmations {

return Lightning_kmpWalletState.WalletWithConfirmations(
swapInParams: self.swapInParams,
currentBlockHeight: self.currentBlockHeight + diff,
all: self.all
)
}
#endif

static func empty() -> Lightning_kmpWalletState.WalletWithConfirmations {
return Lightning_kmpWalletState.WalletWithConfirmations(
swapInParams: LightningExposureKt.defaultSwapInParams(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ fileprivate struct ConfigurationList: View {
case .backgroundPayments : newNavLinkTag = .PaymentOptions ; delay *= 2
case .liquiditySettings : newNavLinkTag = .ChannelManagement ; delay *= 1
case .forceCloseChannels : newNavLinkTag = .ForceCloseChannels ; delay *= 1
case .swapInWallet : newNavLinkTag = .WalletInfo ; delay *= 2
}

if let newNavLinkTag = newNavLinkTag {
Expand Down
Loading

0 comments on commit 7a29411

Please sign in to comment.