         }
     }
     
-    static let maxChallengeRetries = 3
+    static let maxChallengeRetries = 2
     func _markChallengeCompleted(withCompletion completion: @escaping STPBooleanSuccessBlock, retryCount: Int = maxChallengeRetries) {
         guard let currentAction = currentAction,
             let threeDSSourceID = currentAction.nextAction()?.useStripeSDK?.threeDSSourceID

        {

            currentAction.apiClient.retrieveSetupIntent(
                withClientSecret: setupIntent.clientSecret
            ) { retrievedSetupIntent, error in
                currentAction.setupIntent = retrievedSetupIntent
                if let error = error {
                    currentAction.complete(
                        with: STPPaymentHandlerActionStatus.failed, error: error as NSError?)
                } else {
                    let requiresAction: Bool = self._handleSetupIntentStatus(
                        forAction: currentAction)

                    if requiresAction {
                        // If the status is still RequiresAction, the user exited from the redirect before the
                        // payment intent was updated. Consider it a cancel, unless it's a valid terminal next action
                        if self.isNextActionSuccessState(nextAction: setupIntent.nextAction) {
                            currentAction.complete(with: .succeeded, error: nil)
                        } else {
                            // If the status is still RequiresAction, the user exited from the redirect before the
                            // setup intent was updated. Consider it a cancel
                            self._markChallengeCanceled(withCompletion: { _, _ in
                                // We don't forward cancelation errors
                                currentAction.complete(
                                    with: STPPaymentHandlerActionStatus.canceled, error: nil)
                            })
                        }
                    }
                }

            fatalError()
        }
    }
    
    func _retryWithExponentialDelay(retryCount: Int, block: @escaping STPVoidBlock) {
        // Add some backoff time:
        let delayTime = TimeInterval(
            pow(Double(1 + Self.maxChallengeRetries - retryCount), Double(2))
        )
        
        DispatchQueue.main.asyncAfter(deadline: .now() + delayTime) {
            block()
        }
    }

    func _retrieveAndCheckIntentForCurrentAction(retryCount: Int = maxChallengeRetries) {
        // Alipay requires us to hit an endpoint before retrieving the PI, to ensure the status is up to date.
        let pingMarlinIfNecessary:
            ((STPPaymentHandlerPaymentIntentActionParams, @escaping STPVoidBlock) -> Void) = {
