---
updatedAt: 2025-07-26T15:15:54.000Z
agentTools:
  projectIndex: https://docs.metakeep.xyz/llms.txt
---

# Sign Transaction

## Sign EVM Transaction

Once you have built an Ethereum transaction object, you can ask the user to sign it by using the`signTransaction` function in MetaKeep Mobile SDK. The function expects a non-empty `reason` which is shown to the user at the time of transaction signing.

The operation result is returned in the [callback object](https://docs.metakeep.xyz/reference/mobile-sdk-101#sdk-operation-callback) passed to the `signTransaction` function or the `Promise` object returned by the `signTransaction` function.

This function is compliant with the official Ethereum sign transaction API <https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction>

```kotlin EVM Txn Android - Kotlin
val txnString =
    """
    {
        "type": 2,
        "to": "0x97706df14a769e28ec897dac5ba7bcfa5aa9c444",
        "value": "0x2710",
        "nonce": "0x1",
        "data": "0x0123456789",
        "chainId": "0x13881"
        "gas": "0x17",
        "maxFeePerGas": "0x3e8",
        "maxPriorityFeePerGas": "0x3e7"
    }
    """

sdk.signTransaction(
    // Txn as a JsonObject
    JsonRequest(txnString),
    // signing reason
    "reason",
    // Callback
    Callback(
        onSuccess = { response: JsonResponse ->
            Log.d("onSuccess", response.toString())
        },
        onFailure = { error: JsonResponse ->
            Log.d("onFailure", error.toString())
        },
    ),
)
```
```swift EVM Txn iOS - Swift
let txnString =
  """
      {
        "type": 2,
        "to": "0x97706df14a769e28ec897dac5ba7bcfa5aa9c444",
        "value": "0x2710",
        "nonce": "0x1",
        "data": "0x0123456789",
        "chainId": "0x13881"
        "gas": "0x17",
        "maxFeePerGas": "0x3e8",
        "maxPriorityFeePerGas": "0x3e7"
      }
  """

sdk.signTransaction(
  // Txn as a JsonObject
  transaction: try JsonRequest(jsonString: txnString),
  // signing reason
  reason: reason,
  // Callback
  callback: Callback(
    onSuccess: { (result: JsonResponse) in
      print("onSuccess")
      print(result.description)
    },
    onFailure: { (error: JsonResponse) in
      print("onFailure")
      print(error.description)
    }
  )
)
```
```javascript EVM Txn - React Native
await sdk.signTransaction(
  {
    type: 2,
    to: '0x97706df14a769e28ec897dac5ba7bcfa5aa9c444',
    value: '0x2710',
    nonce: '0x1',
    chainId: "0x13881"
    data: '0x0123456789',
    gas: '0x17',
    maxFeePerGas: '0x3e8',
    maxPriorityFeePerGas: '0x3e7',
  },
  // signing reason
  'reason for signing',
);
```
```javascript EVM Txn - Flutter
await sdk.signTransaction({
        "type": 2,
        "to": "0x97706df14a769e28ec897dac5ba7bcfa5aa9c444",
        "value": "0x2710",
        "nonce": "0x1",
        "data": "0x0123456789",
        "chainId": "0x13881",
        "gas": "0x17",
        "maxFeePerGas": "0x3e8",
        "maxPriorityFeePerGas": "0x3e7"
    },
    // signing reason
    'reason for signing',
);
```

## Sign Solana Transaction

Once you have built a Solana transaction object, you can ask the user to sign it by using the`signTransaction` function in the MetaKeep SDK. The function expects a non-empty `reason` which is shown to the user at the time of transaction signing. You need to serialize the transaction object before sending it to the MetaKeep SDK.

> 👍 Solana versioned transactions are supported

```kotlin Solana Txn Android - Kotlin
// First build the Solana txn and serialize the txn message to hex string
val serializedTransactionMessageHex = "0x123456........."

val txnObject =
    """
    {
        "serializedTransactionMessage": \(serializedTransactionMessageHex)
    }
    """

sdk.signTransaction(
    // Txn as a JsonObject
    JsonRequest(txnObject),
    // signing reason
    "reason",
    // Callback
    Callback(
        onSuccess = { response: JsonResponse ->
            Log.d("onSuccess", response.toString())
        },
        onFailure = { error: JsonResponse ->
            Log.d("onFailure", error.toString())
        },
    ),
)
```
```swift Solana Txn iOS - Swift
// First build the Solana txn and serialize the txn message to hex string
let serializedTransactionMessageHex = "0x123456........."

let txnObject =
  """
      {
				"serializedTransactionMessage": ${serializedTransactionMessageHex}
      }
  """

sdk.signTransaction(
  // Txn as a JsonObject
  transaction: try JsonRequest(jsonString: txnObject),
  // signing reason
  reason: reason,
  // Callback
  callback: Callback(
    onSuccess: { (result: JsonResponse) in
      print("onSuccess")
      print(result.description)
    },
    onFailure: { (error: JsonResponse) in
      print("onFailure")
      print(error.description)
    }
  )
)
```
```javascript Solana Txn - React Native
// Serialized transaction message in hex format.
// This is the data that needs to be signed
const serializedTransactionMessage = "0xabcd.........."

await sdk.signTransaction(
  // Serialized Solana transaction message
  {
    serializedTransactionMessage: serializedTransactionMessage
  },
  // signing reason
  "transfer 1 SOL"
);
```
```javascript Solana Transaction - Flutter
// Serialized transaction message in hex format.
// This is the data that needs to be signed
const serializedTransactionMessage = "0xabcd.........."

await sdk.signTransaction(
  // Serialized Solana transaction message
  {
    serializedTransactionMessage: serializedTransactionMessage
  },
  // signing reason
  "transfer 1 SOL"
);
```

## Sign EOS Transaction

Once you have built a raw EOS transaction, you can ask the user to sign it by using the`signTransaction` function in the MetaKeep SDK. If the signature generation also requires a chainId, you can send it in the `extraSigningData` field. **Note that the action data needs to be sent as a serialized hex string.**

The function also expects a non-empty `reason` which is shown to the user at the time of transaction signing.

```kotlin EOS Txn Android - Kotlin
val txnString =
  """
    {
        "rawTransaction": {
            "expiration": "2023-05-06T01:23:45",
            "ref_block_num": 12345,
            "ref_block_prefix": 67890,
            "max_net_usage_words": 0,
            "max_cpu_usage_ms": 0,
            "delay_sec": 0,
            "context_free_actions": [],
            "actions": [{
                "account": "eosio.token",
                "name": "transfer",
                "authorization": [{
                    "actor": "myaccount",
                    "permission": "active"
                }],
                "data": "0000000000ea305500000000487a2b000000000000000004454f530000000000"
            }],
            "transaction_extensions": []
        },
        "extraSigningData": {
            "chainId": "b20901380af44ef59c5918439a1f9a41d83669020319a80574b804a5f95cbd7e"
        }
    }
  """

sdk.signTransaction(
    // Txn as a JsonObject
    JsonRequest(txnString),
    // signing reason
    "reason",
    // Callback
    Callback(
        onSuccess = { response: JsonResponse ->
            Log.d("onSuccess", response.toString())
        },
        onFailure = { error: JsonResponse ->
            Log.d("onFailure", error.toString())
        },
    ),
)
```
```swift EOS Txn iOS - Swift
let txnString =
    """
    {
        "rawTransaction": {
            "expiration": "2023-05-06T01:23:45",
            "ref_block_num": 12345,
            "ref_block_prefix": 67890,
            "max_net_usage_words": 0,
            "max_cpu_usage_ms": 0,
            "delay_sec": 0,
            "context_free_actions": [],
            "actions": [{
                "account": "eosio.token",
                "name": "transfer",
                "authorization": [{
                    "actor": "myaccount",
                    "permission": "active"
                }],
                "data": "0000000000ea305500000000487a2b000000000000000004454f530000000000"
            }],
            "transaction_extensions": []
        },
        "extraSigningData": {
            "chainId": "b20901380af44ef59c5918439a1f9a41d83669020319a80574b804a5f95cbd7e"
        }
    }
    """

sdk.signTransaction(
  // Txn as a JsonObject
  transaction: try JsonRequest(jsonString: txnString),
  // signing reason
  reason: reason,
  // Callback
  callback: Callback(
    onSuccess: { (result: JsonResponse) in
      print("onSuccess")
      print(result.description)
    },
    onFailure: { (error: JsonResponse) in
      print("onFailure")
      print(error.description)
    }
  )
)
```
```javascript EOS Txn - React Native
await sdk.signTransaction(
    // Transaction object
    {
        // Raw EOS transaction
        "rawTransaction": {
            "expiration": "2023-05-06T01:23:45",
            "ref_block_num": 12345,
            "ref_block_prefix": 67890,
            "max_net_usage_words": 0,
            "max_cpu_usage_ms": 0,
            "delay_sec": 0,
            "context_free_actions": [],
            "actions": [{
                "account": "eosio.token",
                "name": "transfer",
                "authorization": [{
                    "actor": "myaccount",
                    "permission": "active"
                }],
                // Send action data as a serialized hex string.
                "data": "0000000000ea305500000000487a2b000000000000000004454f530000000000"
            }],
            "transaction_extensions": []
        },
        "extraSigningData": {
            // If chainId is part of the signature generation,
            // send it inside extraSigningData field.
            "chainId": "b20901380af44ef59c5918439a1f9a41d83669020319a80574b804a5f95cbd7e"
        }
    },
    // signing reason
    "reason",
);
```
```javascript EOS Txn - Flutter
await sdk.signTransaction(
    // Transaction object
    {
        // Raw EOS transaction
        "rawTransaction": {
            "expiration": "2023-05-06T01:23:45",
            "ref_block_num": 12345,
            "ref_block_prefix": 67890,
            "max_net_usage_words": 0,
            "max_cpu_usage_ms": 0,
            "delay_sec": 0,
            "context_free_actions": [],
            "actions": [{
                "account": "eosio.token",
                "name": "transfer",
                "authorization": [{
                    "actor": "myaccount",
                    "permission": "active"
                }],
                // Send action data as a serialized hex string.
                "data": "0000000000ea305500000000487a2b000000000000000004454f530000000000"
            }],
            "transaction_extensions": []
        },
        "extraSigningData": {
            // If chainId is part of the signature generation,
            // send it inside extraSigningData field.
            "chainId": "b20901380af44ef59c5918439a1f9a41d83669020319a80574b804a5f95cbd7e"
        }
    },
    // signing reason
    "reason",
);
```

## Response

On success, the callback `onSuccess` or the `Promise resolve` function is called with the signed transaction data as a `JsonResponse` object. This is what the data looks like:

```json Sign EVM Transaction Response
{
  status: "SUCCESS",
  //The RLP encoded transaction, ready to be sent using web3.eth.sendSignedTransaction.
  signedRawTransaction: "0x02f86c8189018203e78203e8179497706df14a769e28ec897dac5ba7bcfa5aa9c444822710850123456789c080a01a84678f385553358386051464a252fa25d019335deb20262eb231d4ec146730a00e6f1944e872430b7e04af6dd68ece90e2a9995a7abd827b50588602523b5256",
  // The transaction hash for the RLP encoded transaction.
  transactionHash: "0xe02497f6d7d4b52197a35db6115633b34802f90eaa98e894791999ca0d6b11f8",
  // Signature of the signed transaction. The signature encodes the r, s and v parameters 
  // from appendix F of the yellow paper in big-endian format. 
  // Bytes 0…32 contain the r parameter, bytes 32…64 the s parameter and the last byte the v parameter.
  signature: "0x1a84678f385553358386051464a252fa25d019335deb20262eb231d4ec1467300e6f1944e872430b7e04af6dd68ece90e2a9995a7abd827b50588602523b525600",
  r: "0x1a84678f385553358386051464a252fa25d019335deb20262eb231d4ec146730",
  s: "0x0e6f1944e872430b7e04af6dd68ece90e2a9995a7abd827b50588602523b5256",
  v: "0x0"
}
```
```json Sign Solana Transaction Response
{
  "status": "SUCCESS",
  // Signature in hex format
  "signature": "0x023d9a5700b77971b8de539936143e0d82808809b856cc9ab9bcc41a02a3794ec516a44db6ed666f3e4f7549ae91939062ce076a9ef419febc21c41eebb98f0a"
}
```
```json Sign EOS Transaction Response
{
  "status": "SUCCESS",
  "signature": "SIG_K1_K1YY3maW1vHjQmmtciiQkkzPaUcpPdCQ631oMqayz4Z3TG9xhjNQwzqL3VCQPV1ZfYTQ14hkoRBkFaUwwrAngLedAxhog6"
}
```

## Error status

Callback `onFailure` or the `Promise reject` function is called when the user cancels the operation or if there's an error. The error object contains a status field which is a string indicating the status of the operation. Here's what the error object looks like:

```json Error object
{
  status: "USER_CONSENT_DENIED"
}
```

Here's a table of all possible error status returned by the SDK

<Table align={["left","left"]}>
  <thead>
    <tr>
      <th>
        Status
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        USER\_REQUEST\_DENIED
      </td>

      <td>
        User has denied the sign operation.\
        In this case, you should ask the user if they want to try again.
      </td>
    </tr>

    <tr>
      <td>
        INVALID\_REQUEST
      </td>

      <td>
        Invalid data passed to sign operation.\
        Please get in touch with us if you are unable to fix this.
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_NONCE
      </td>

      <td>
        The nonce is missing. Please specify `nonce` for the transaction.
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_GAS
      </td>

      <td>
        Gas is missing. Please specify `gas` for the transaction.
      </td>
    </tr>

    <tr>
      <td>
        INVALID\_GAS\_FEE\_PARAMS
      </td>

      <td>
        The transaction contains `gasPrice` `maxFeePerGas` and `maxPriorityFeePerGas`. Please specify either `gasPrice` or `maxFeePerGas` and `maxPriorityFeePerGas`
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_GAS\_PRICE
      </td>

      <td>
        Gas price is missing for type 1 transactions. Please specify `gasPrice`.
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_MAX\_FEE\_PER\_GAS
      </td>

      <td>
        The max fee per gas is missing for type 2 transactions. Please specify both `maxFeePerGas` and `maxPriorityFeePerGas`
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_MAX\_PRIORITY\_FEE\_PER\_GAS
      </td>

      <td>
        The max priority fee per gas is missing for type 2 transactions. Please specify both `maxFeePerGas` and `maxPriorityFeePerGas`
      </td>
    </tr>

    <tr>
      <td>
        APP\_ID\_REQUIRED
      </td>

      <td>
        No app id provided when initializing the SDK.\
        You can find the app id in MetaKeep Developer Console.
      </td>
    </tr>

    <tr>
      <td>
        APP\_NOT\_FOUND
      </td>

      <td>
        Provided app id is invalid.\
        You can find the correct app id in MetaKeep Developer Console.
      </td>
    </tr>

    <tr>
      <td>
        SOMETHING\_WENT\_WRONG
      </td>

      <td>
        Unknown error happened.\
        Please get in touch with us if you continue seeing this error.
      </td>
    </tr>
  </tbody>
</Table>

© Copyright 2024, Passbird Research Inc.