# Anticheat methods

## Recommended sequence of actions when working with transactions

1. Get response about a completed transaction from the payment system.
2. Either send data about the received transaction for verification by calling devtodev anti-cheat methods or use your own tools for transaction verification.
3. If the transaction has successfully passed verification, perform the Payment event. \
   If the transaction has not passed verification, do not perform the Payment event.&#x20;

## Payment Validation

The devtodev service allows you to validate transactions to prevent fraud from influencing your statistics. For this, you need to integrate **`DTDAntiCheat`** module.

{% hint style="danger" %}
We strongly discourage you from using verification results for deciding on allowing or denying users to receive their purchases! We do not recommend to mark users as cheaters based on the results of this verification! **Employ this method exclusively for preventing fraud transaction data from being sent to devtodev!**
{% endhint %}

{% tabs fullWidth="true" %}
{% tab title="App Store (iOS) Swift" %}
To validate the transaction you can use the **`verifyPayment(completionHandler: @escaping (DTDVerifyResponse) -> Void)`** method immediately during the transaction processing, e.g.:

```swift
extension Purchases: SKPaymentTransactionObserver {
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
                case .purchased:
                    DTDAntiCheat.verifyPayment { response in
                            switch response.receiptStatus {
                                case .receiptInternalError: 
                                  // your code
                                  break
                                case .receiptValid:
                                  // your code
                                  break
                                case .receiptSandbox:
                                  // your code
                                  break
                                case .receiptServerError:
                                  // your code
                                  break
                                case .receiptNotValid: 
                                  // your code
                                  break
                                @unknown default: break
                            }
                            SKPaymentQueue.default().finishTransaction(transaction)
                        }

                case .restored:
                    SKPaymentQueue.default().finishTransaction(transaction)

                case .failed:
                    SKPaymentQueue.default().finishTransaction(transaction)

                default:
                    break
            }
        }
    }
}

```

## `DTDVerifyResponse`

The DTDVerifyResponse object returned while validating the transaction has two properties:

| Property                 | Description                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| **`receiptStatus`**      | Enum type **`DTDReceiptStatus`** that represents the result of the transaction validation. |
| **`verificationResult`** | Additional information from the validation server.                                         |

## `DTDReceiptStatus`

The enum type returned as a result of validation can receive the following values:

| **Value**                    | Description                                                          |
| ---------------------------- | -------------------------------------------------------------------- |
| ***`receiptValid`***         | The payment is valid, the transaction is genuine.                    |
| ***`receiptNotValid`***      | The payment is invalid, the transaction may be a duplicate or fraud. |
| ***`receiptServerError`***   | Server error when validating the payment.                            |
| ***`receiptSandbox`***       | Test payment.                                                        |
| ***`receiptInternalError`*** | Internal SDK error.                                                  |

{% hint style="info" %}
We recommend calling the Real Currency Payment method in all cases except when you receive ***`receiptNotValid`*** or ***`receiptSandbox`*** as a result of the validation.
{% endhint %}
{% endtab %}

{% tab title="App Store (iOS) Objective-C" %}
To validate the transaction you can use the **`(void)verifyPaymentCompletion:( void (^ _Nonnull)(DTDVerifyResponse * _Nonnull))completionHandler;`** method immediately during the transaction processing, e.g.:

```objectivec
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    for(SKPaymentTransaction *transaction in transactions) {
        switch(transaction.transactionState){
            case SKPaymentTransactionStatePurchasing: {
                // Your code ...
                break;
            }

            case SKPaymentTransactionStatePurchased: {
                // Your code ...
                [DTDAntiCheat verifyPaymentCompletion:^(DTDVerifyResponse * _Nonnull response) {
                    switch ([response receiptStatus]) {
                        case ReceiptStatusReceiptInternalError: {

                            break;
                        }
                        case ReceiptStatusReceiptValid: {

                            break;
                        }
                        case ReceiptStatusReceiptSandbox: {

                            break;
                        }
                        case ReceiptStatusReceiptServerError: {

                            break;
                        }
                        case ReceiptStatusReceiptNotValid: {

                            break;
                        }
                    }
                }];
                break;
            }

            case SKPaymentTransactionStateRestored: {
                // Your code ...
                break;
            }

            case SKPaymentTransactionStateFailed: {
                // Your code ...
                break;
            }

            case SKPaymentTransactionStateDeferred: {
                // Your code ...
                break;
            }
        }
    }
}
```

## `DTDVerifyResponse`

The DTDVerifyResponse object returned while validating the transaction has two properties:

| Property                 | Description                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| **`receiptStatus`**      | Enum type **`DTDReceiptStatus`** that represents the result of the transaction validation. |
| **`verificationResult`** | Additional information from the validation server.                                         |

## `DTDReceiptStatus`

The enum type returned as a result of validation can receive the following values:

<table data-header-hidden><thead><tr><th width="373">Value</th><th>Description</th></tr></thead><tbody><tr><td><strong>Value</strong></td><td>Description</td></tr><tr><td><em><strong><code>receiptValid</code></strong></em></td><td>The payment is valid, the transaction is genuine.</td></tr><tr><td><em><strong><code>receiptNotValid</code></strong></em></td><td>The payment is invalid, the transaction may be a duplicate or fraud.</td></tr><tr><td><em><strong><code>receiptServerError</code></strong></em></td><td>Server error when validating the payment.</td></tr><tr><td><em><strong><code>receiptSandbox</code></strong></em></td><td>Test payment.</td></tr><tr><td><em><strong><code>receiptInternalError</code></strong></em></td><td>Internal SDK error.</td></tr></tbody></table>

{% hint style="info" %}
We recommend calling the Real Currency Payment method in all cases except when you receive ***`receiptNotValid`*** or ***`receiptSandbox`*** as a result of the validation.
{% endhint %}
{% endtab %}

{% tab title="Google Play (Kotlin)" %}
When Google Play sends the transaction back to your **`onActivityResult`**, validate it by calling the following method: **`verifyPayment(receipt: String, signature: String, publicKey: String, completionHandler:(DTDVerifyResponse) -> Unit)`** immediately during the transaction processing, e.g.:

```kotlin
DTDAntiCheat.verifyPayment(
    receipt = "receipt", 
    signature = "signature", 
    publickKey = "publickKey"
) { dtdVerifyResponse ->
    val verificationResult = dtdVerifyResponse.verificationResult
    /* your code here */
    when (dtdVerifyResponse.receiptStatus) {
        DTDReceiptStatus.ReceiptValid -> { /* your code here */ }
        DTDReceiptStatus.ReceiptNotValid -> { /* your code here */ }
        DTDReceiptStatus.ReceiptServerError -> { /* your code here */ }
        DTDReceiptStatus.ReceiptInternalError -> { /* your code here */ }
    }
}
```

## `DTDVerifyResponse`

The DTDVerifyResponse object returned while validating the transaction has two properties:

| Property                 | Description                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| **`receiptStatus`**      | Enum type **`DTDReceiptStatus`** that represents the result of the transaction validation. |
| **`verificationResult`** | Additional information from the validation server.                                         |

## `DTDReceiptStatus`

The enum type returned as a result of validation can receive the following values:

| **Value**                    | Description                                                          |
| ---------------------------- | -------------------------------------------------------------------- |
| ***`receiptValid`***         | The payment is valid, the transaction is genuine.                    |
| ***`receiptNotValid`***      | The payment is invalid, the transaction may be a duplicate or fraud. |
| ***`receiptServerError`***   | Server error when validating the payment.                            |
| ***`receiptInternalError`*** | Internal SDK error.                                                  |

{% hint style="info" %}
We recommend calling the Real Currency Payment method in all cases except when you receive ***`receiptNotValid`*** as a result of the validation.
{% endhint %}
{% endtab %}

{% tab title="Google Play (Java)" %}
When Google Play sends the transaction back to your **`onActivityResult`**, validate it by calling the following method: **`verifyPayment(receipt: String, signature: String, publicKey: String, completionHandler:(DTDVerifyResponse) -> Unit)`** immediately during the transaction processing, e.g.:

```java
DTDAntiCheat.INSTANCE.verifyPayment("receipt", "signature", "publickKey",
                dtdVerifyResponse -> {
                // your code
                    switch (dtdVerifyResponse.getReceiptStatus()) {
                        case ReceiptValid:
                            // your code
                            break;
                        case ReceiptNotValid:
                            // your code
                            break;
                        case ReceiptInternalError:
                            // your code
                            break;
                        case ReceiptServerError:
                            // your code
                            break;
                    }
                    return null;
                });
```

## `DTDVerifyResponse`

The DTDVerifyResponse object returned while validating the transaction has two properties:

| Property                 | Description                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| **`receiptStatus`**      | Enum type **`DTDReceiptStatus`** that represents the result of the transaction validation. |
| **`verificationResult`** | Additional information from the validation server.                                         |

## `DTDReceiptStatus`

The enum type returned as a result of validation can receive the following values:

| **Value**                    | Description                                                          |
| ---------------------------- | -------------------------------------------------------------------- |
| ***`receiptValid`***         | The payment is valid, the transaction is genuine.                    |
| ***`receiptNotValid`***      | The payment is invalid, the transaction may be a duplicate or fraud. |
| ***`receiptServerError`***   | Server error when validating the payment.                            |
| ***`receiptInternalError`*** | Internal SDK error.                                                  |

{% hint style="info" %}
We recommend calling the Real Currency Payment method in all cases except when you receive ***`receiptNotValid`*** as a result of the validation.
{% endhint %}
{% endtab %}

{% tab title="Microsoft Store (UWP)" %}
devtodev sends a request for transaction verification to the payment platform and then forwards the answer to the app.\
To validate the transaction you can use the **`Task<DTDReceiptStatus> VerifyPayment(string: receipt)`** method. As an argument pass the **`PurchaseResults.ReceiptXml`** property. More information about it [here](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.store.purchaseresults.receiptxml?view=winrt-20348#Windows_ApplicationModel_Store_PurchaseResults_ReceiptXml).

Example of verification:

```csharp
var result = await DTDAntiCheat.VerifyPayment("receipt");
switch (result)
{
    case DTDReceiptStatus.Valid:
        break;
    case DTDReceiptStatus.Invalid:
        break;
    case DTDReceiptStatus.ServerError:
        break;
    case DTDReceiptStatus.InternalError:
        break;
    default:
        throw new ArgumentOutOfRangeException();
}
```

## `DTDVerifyResponse`

The DTDVerifyResponse object returned while validating the transaction has two properties:

| Property                 | Description                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| **`ReceiptStatus`**      | Enum type **`DTDReceiptStatus`** that represents the result of the transaction validation. |
| **`VerificationResult`** | Additional information from the validation server.                                         |

## `DTDReceiptStatus`

The enum type returned as a result of validation can receive the following values:

| Value                      | Description                                                         |
| -------------------------- | ------------------------------------------------------------------- |
| ***`Valid = 0L`***         | The payment is valid, the transaction went through successfully     |
| ***`Invalid = 1L`***       | The payment is invalid, the transaction may be a duplicate or fraud |
| ***`ServerError = 2L`***   | Server error when validating the payment                            |
| ***`InternalError = 4L`*** | Internal SDK error                                                  |

{% hint style="info" %}
We recommend calling the Real Currency Payment method in all cases except when you receive ***`Invalid`*** as a result of the validation.
{% endhint %}
{% endtab %}

{% tab title="Unity (3 stores )" %}

## Google Play

If you use Unity IAP for payment validation, call the following method: **`void VerifyPayment(string publicKey, string receipt, Action completionHandler)`**

Example:

```csharp
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
    DTDAntiCheat.VerifyPayment(yourPublicKey, e.purchasedProduct.receipt, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}
```

To validate data received from Google Play, use **`void VerifyPayment(string publicKey, string receipt, string signature,Action<DTDVerifyResponse> completionHandler)`** when handling the transaction.

```csharp
public void MyNativeCallback (string publicKey, string receipt, string signature)
{
    DTDAntiCheat.VerifyPayment(publicKey, receipt, signature, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}
```

Here's how to find your app's public key for licensing (for Google Play platform only, for other platforms the publicKey is not used):

1. Go to the Google Play Console and sign in. Make sure that you sign in to the account from which the app you are licensing is published (or will be published).
2. In the app details page, locate the Services & APIs link and click it.
3. In the Services & APIs page, locate the Licensing & In-App Billing section. Your public key for licensing is given in the Your License Key For This Application field.

## App Store

If you use Unity IAP for payment validation, call the following method: **`void VerifyPayment(string receipt, Action completionHandler)`**

```csharp
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
    DTDAntiCheat.VerifyPayment(e.purchasedProduct.receipt, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}
```

## Windows Store (UWP)

If you use Unity IAP for payment validation, call the following method: **`void VerifyPayment(string receipt, Action completionHandler)`**

```csharp
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
    DTDAntiCheat.VerifyPayment(e.purchasedProduct.receipt, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}
```

{% hint style="info" %}
N.B. You can pass a native XML recipe to the **receipt** argument.
{% endhint %}

## `DTDVerifyResponse`

The DTDVerifyResponse object returned while validating the transaction has two properties:

| Property                 | Description                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| **`receiptStatus`**      | Enum type **`DTDReceiptStatus`** that represents the result of the transaction validation. |
| **`verificationResult`** | Additional information from the validation server.                                         |

## `DTDReceiptStatus`

The enum type returned as a result of validation can receive the following values:

<table data-header-hidden><thead><tr><th width="373">Value</th><th>Description</th></tr></thead><tbody><tr><td><strong>Value</strong></td><td>Description</td></tr><tr><td><em><strong><code>receiptValid</code></strong></em></td><td>The payment is valid, the transaction is genuine.</td></tr><tr><td><em><strong><code>receiptNotValid</code></strong></em></td><td>The payment is invalid, the transaction may be a duplicate or fraud.</td></tr><tr><td><em><strong><code>receiptServerError</code></strong></em></td><td>Server error when validating the payment.</td></tr><tr><td><em><strong><code>receiptSandbox</code></strong></em></td><td>Test payment.</td></tr><tr><td><em><strong><code>receiptInternalError</code></strong></em></td><td>Internal SDK error.</td></tr></tbody></table>

{% hint style="info" %}
We recommend calling the Real Currency Payment method in all cases except when you receive ***`receiptNotValid`*** or ***`receiptSandbox`*** as a result of the validation.
{% endhint %}
{% endtab %}
{% endtabs %}
