Sign EVM Transaction
Once you have built an Ethereum transaction object, you can ask the user to sign it by using thesignTransaction
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 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
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())
},
),
)
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)
}
)
)
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',
);
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 thesignTransaction
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
// 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())
},
),
)
// 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)
}
)
)
// 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"
);
// 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 thesignTransaction
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.
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())
},
),
)
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)
}
)
)
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",
);
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:
{
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"
}
{
"status": "SUCCESS",
// Signature in hex format
"signature": "0x023d9a5700b77971b8de539936143e0d82808809b856cc9ab9bcc41a02a3794ec516a44db6ed666f3e4f7549ae91939062ce076a9ef419febc21c41eebb98f0a"
}
{
"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:
{
status: "USER_CONSENT_DENIED"
}
Here's a table of all possible error status returned by the SDK
Status | Description |
---|---|
USER_REQUEST_DENIED | User has denied the sign operation. In this case, you should ask the user if they want to try again. |
INVALID_REQUEST | Invalid data passed to sign operation. Please get in touch with us if you are unable to fix this. |
MISSING_NONCE | The nonce is missing. Please specify nonce for the transaction. |
MISSING_GAS | Gas is missing. Please specify gas for the transaction. |
INVALID_GAS_FEE_PARAMS | The transaction contains gasPrice maxFeePerGas and maxPriorityFeePerGas . Please specify either gasPrice or maxFeePerGas and maxPriorityFeePerGas |
MISSING_GAS_PRICE | Gas price is missing for type 1 transactions. Please specify gasPrice . |
MISSING_MAX_FEE_PER_GAS | The max fee per gas is missing for type 2 transactions. Please specify both maxFeePerGas and maxPriorityFeePerGas |
MISSING_MAX_PRIORITY_FEE_PER_GAS | The max priority fee per gas is missing for type 2 transactions. Please specify both maxFeePerGas and maxPriorityFeePerGas |
APP_ID_REQUIRED | No app id provided when initializing the SDK. You can find the app id in MetaKeep Developer Console. |
APP_NOT_FOUND | Provided app id is invalid. You can find the correct app id in MetaKeep Developer Console. |
SOMETHING_WENT_WRONG | Unknown error happened. Please get in touch with us if you continue seeing this error. |
© Copyright 2024, Passbird Research Inc.