Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cfded06
Adds new result type for `collectPaymentMethod` to sometimes return K…
mliberatore Mar 19, 2026
bf2d135
Adds helper extensions for payment details → KycInfo
mliberatore Mar 19, 2026
83dc992
Updates the CryptoOnrampCoordinator API and adapts the example app to…
mliberatore Mar 19, 2026
68b4522
Updates README about the API behavior addition
mliberatore Mar 19, 2026
30d5e8b
Also updates the ApplePay code path in PaymentView to maintain existi…
mliberatore Mar 19, 2026
30ee2ee
Merge branch 'master' into mliberatore/crypto-onramp-apple-pay-kyc
mliberatore Mar 19, 2026
43b06aa
Adds test code for testing the Apple Pay L0 KYC flow
mliberatore Mar 19, 2026
e0a517e
Revert "Adds test code for testing the Apple Pay L0 KYC flow"
mliberatore Mar 19, 2026
3228106
Merge branch 'master' into mliberatore/crypto-onramp-apple-pay-kyc
mliberatore Mar 19, 2026
3a61861
Adds docs to address extension
mliberatore Mar 19, 2026
caaca88
Adds unit test for billing contact → KycInfo conversion and Address.i…
mliberatore Mar 19, 2026
21fab80
Merge branch 'master' into mliberatore/crypto-onramp-apple-pay-kyc
Twigz Mar 25, 2026
6cb1cee
PR review cleanup, additional tests
Twigz Mar 31, 2026
592046a
Merge branch 'master' into mliberatore/crypto-onramp-apple-pay-kyc
Twigz Mar 31, 2026
90c1915
Fix linting
Twigz Mar 31, 2026
cbf48c3
Merge branch 'master' into mliberatore/crypto-onramp-apple-pay-kyc
Twigz Apr 6, 2026
fa2966c
Allow for proper cancellation of payment collection
Twigz Apr 7, 2026
c59f3d3
Merge branch 'master' into twigz/proper-payment-collection-cancellation
Twigz Apr 9, 2026
922899d
Merge branch 'master' into twigz/proper-payment-collection-cancellation
Twigz Apr 9, 2026
b5cf8e5
Previous selectedPaymentSource for ApplePay
Twigz Apr 9, 2026
f718c6f
Update CryptoOnrampCoordinator.swift
Twigz Apr 9, 2026
6a75425
Merge branch 'master' into twigz/proper-payment-collection-cancellation
mliberatore Apr 13, 2026
e0d0283
Renames `applePayPreviousPaymentSource` and adds clear docs
mliberatore Apr 13, 2026
a4615f7
Merge branch 'master' into twigz/proper-payment-collection-cancellation
mliberatore Apr 13, 2026
9845044
Merge branch 'master' into twigz/proper-payment-collection-cancellation
Twigz Apr 20, 2026
87ed9c1
Merge branch 'master' into twigz/proper-payment-collection-cancellation
Twigz Apr 21, 2026
5834398
Merge branch 'master' into twigz/proper-payment-collection-cancellation
Twigz Apr 21, 2026
73a636f
Applies Jean’s suggestion for reversing `paymentSourceBeforeApplePay`…
mliberatore Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ public final class CryptoOnrampCoordinator: NSObject, CryptoOnrampCoordinatorPro
private let appearance: LinkAppearance
private let analyticsClient: CryptoOnrampAnalyticsClient
private var applePayCompletionContinuation: CheckedContinuation<ApplePayPaymentStatus, Swift.Error>?

/// Apple Pay payment source created by `didCreatePaymentMethod` but not yet committed.
///
/// Apple Pay can create the payment method before the sheet reports final success. Keep it here
/// until `didCompleteWith(.success)`, then promote it to `selectedPaymentSource`. Cancellation
/// or failure leaves the existing selection untouched; this value is cleared when the Apple Pay
/// attempt starts, completes, or the user logs out.
private var pendingApplePayPaymentSource: SelectedPaymentSource?
private var selectedPaymentSource: SelectedPaymentSource?
private let cryptoCustomerState: CryptoCustomerState

Expand Down Expand Up @@ -478,7 +486,6 @@ public final class CryptoOnrampCoordinator: NSObject, CryptoOnrampCoordinatorPro
supportedPaymentMethodTypes: supportedPaymentMethodTypes,
collectName: type.requiresNameCollection
) else {
selectedPaymentSource = nil
return .canceled
}

Expand All @@ -492,7 +499,8 @@ public final class CryptoOnrampCoordinator: NSObject, CryptoOnrampCoordinatorPro
analyticsClient.log(.collectPaymentMethodCompleted(paymentMethodType: type.analyticsValue))
return .completed(displayData: preview, kycInfo: nil)
case .applePay(let paymentRequest):
// This presents Apple Pay and fills the selected payment source in the delegate.
// This presents Apple Pay and promotes the pending payment source on success.
pendingApplePayPaymentSource = nil
do {
let status = try await presentApplePay(using: paymentRequest, from: viewController)
switch status {
Expand Down Expand Up @@ -524,10 +532,10 @@ public final class CryptoOnrampCoordinator: NSObject, CryptoOnrampCoordinatorPro

return .completed(displayData: paymentMethodPreview, kycInfo: kycInfo)
case .canceled:
selectedPaymentSource = nil
return .canceled
}
} catch {
pendingApplePayPaymentSource = nil
analyticsClient.log(.errorOccurred(during: .collectPaymentMethod, errorMessage: error.localizedDescription))
throw error
}
Expand Down Expand Up @@ -629,6 +637,8 @@ public final class CryptoOnrampCoordinator: NSObject, CryptoOnrampCoordinatorPro

public func logOut() async throws {
do {
pendingApplePayPaymentSource = nil
selectedPaymentSource = nil
try await linkController.logOut()
analyticsClient.log(.userLoggedOut)
} catch {
Expand All @@ -647,26 +657,29 @@ extension CryptoOnrampCoordinator: ApplePayContextDelegate {
didCreatePaymentMethod paymentMethod: StripeAPI.PaymentMethod,
paymentInformation: PKPayment
) async throws -> String {
selectedPaymentSource = .applePay(paymentMethod, KycInfo(payment: paymentInformation))
pendingApplePayPaymentSource = .applePay(paymentMethod, KycInfo(payment: paymentInformation))

return STPApplePayContext.COMPLETE_WITHOUT_CONFIRMING_INTENT
}

public func applePayContext(_ context: STPApplePayContext, didCompleteWith status: STPApplePayContext.PaymentStatus, error: Swift.Error?) {
switch status {
case .success:
applePayCompletionContinuation?.resume(returning: .success)
if let pendingApplePayPaymentSource {
selectedPaymentSource = pendingApplePayPaymentSource
applePayCompletionContinuation?.resume(returning: .success)
} else {
applePayCompletionContinuation?.resume(throwing: ApplePayPaymentStatus.Error.applePayFallbackError)
}
case .userCancellation:
selectedPaymentSource = nil
applePayCompletionContinuation?.resume(returning: .canceled)
case .error:
selectedPaymentSource = nil
applePayCompletionContinuation?.resume(throwing: error ?? ApplePayPaymentStatus.Error.applePayFallbackError)
@unknown default:
selectedPaymentSource = nil
applePayCompletionContinuation?.resume(throwing: error ?? ApplePayPaymentStatus.Error.applePayFallbackError)
}

pendingApplePayPaymentSource = nil
applePayCompletionContinuation = nil
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ import UIKit
with email: String?,
supportedPaymentMethodTypes: [LinkPaymentMethodType] = LinkPaymentMethodType.allCases,
collectName: Bool = false,
completion: @escaping () -> Void
completion: @escaping (_ didSelectPaymentMethod: Bool) -> Void
) {
var configuration = self.configuration
configuration.defaultBillingDetails.email = email
Expand All @@ -395,12 +395,12 @@ import UIKit
if shouldClearSelection {
self?.internalPaymentOption = nil
}
completion()
completion(false)
return
}

self?.internalPaymentOption = .link(option: confirmOption)
completion()
completion(true)
}
}

Expand Down Expand Up @@ -1037,9 +1037,9 @@ extension LinkController: LinkFullConsentViewControllerDelegate {
with: email,
supportedPaymentMethodTypes: supportedPaymentMethodTypes,
collectName: collectName
) { [weak self] in
) { [weak self] didSelectPaymentMethod in
guard let self else { return }
continuation.resume(returning: self.paymentMethodPreview)
continuation.resume(returning: didSelectPaymentMethod ? self.paymentMethodPreview : nil)
}
}
}
Expand Down
Loading