Skip to main content

Unity SDK reference

Overview

The MPC Unity SDK provides a collection of MPC features, giving players of your Unity game the ability to create wallets and transfer assets between addresses without leaving the game environment.

The SDK offers two ways to handle asynchronous operations—using await with an async method, or using Action with a callback function. The following example demonstrates both ways:

public static async Task<(return_type)> FuncName(params, Action<(return_type)> onComplete = null) {...}

private async void FuncAsync()
{
var result = await FuncName(...);
// Continue to do something
}

private void FuncNormal()
{
FuncName(..., onComplete = (return_type result) => {
// Continue to do something
}
);
}

For simplicity, all methods mentioned in the documentation omit the return type and the onComplete action. All main methods are static and are under the MPC class.

Requirements

Installation

Download the Unity package from the GitHub release page and import it into your project.

Initialization

Task<(bool success, MPCError error)> MPC.Initialize(accessToken : string, env : Environment);

Parameters:

NameTypeDescription
accessTokenStringValid access token returned from an OAuth 2.0 provider.
envEnvironmentDefines the environment. Use Staging for the staging or testing environment. Use Production when the game is running in a live, production environment, serving real users. The default value is Staging.

Examples:

Staging
await MPC.Initialize(CreateAccessToken(userId), Environment.Staging);
Production
await MPC.Initialize(CreateAccessToken(userId), Environment.Production);

If the user's access token changes during the game session, call the UpdateAccessToken method to update it.

MPC.UpdateAccessToken(AccessToken);

Methods

Main methods:

MethodDescription
MPC.InitializeInitializes the MPC SDK with the specified access token and environment. All other SDK methods must be called after this one.
MPC.KeygenGenerates an MPC private key, encrypts it, and automatically backs it up to the Sky Mavis backup server.
MPC.EncryptDataEncrypts the user's private key shard.
MPC.DecryptDataDecrypts the user's private key shard.
MPC.BackupKeyCreates a backup copy of the user's encrypted private key shard on the Sky Mavis backup server.
MPC.GetBackupKeyPulls the backup copy of the user's encrypted private key shard from the Sky Mavis backup server.
MPC.SignMessageSigns a message using the encrypted private key and the provided password.
MPC.TransferNativeTokenTransfers a native token, such as RON, to a specified address.
MPC.TransferERC20TokenTransfers an ERC20 token, such as AXS or SLP, to a specified address.
MPC.ApproveERC20TokenApproves an ERC20 token for a specific contract address and amount.
MPC.CallContractCalls a contract asynchronously.

Utilities:

MethodDescription
MPC.WalletAddressRetrieves the user's public wallet address from the server.
MPC.HasBackupKeyVerifies if the user has a backup of the private key shard.
MPC.HasPrivateKeyVerifies if the user already has an MPC private key.
MPC.LogoutLogs the user out of the current session and deletes all local data.
MPC.GetRONBalanceRetrieves the RON token balance for a given token address.
MPC.GetERC20BalanceRetrieves an ERC20 token balance for a given token address.
MPC.UpdateAccessTokenUsed to update the user's access token if it changes during the game session.
MPC.EstimateTransferNativeTokenGasEstimates the gas required for transferring native tokens, such as RON.
[MPC.EstimateERC20TokenGas](#estimate-gas-for-erc20-token-transferEstimates the gas required for transferring ERC20 tokens, such as AXS or SLP.
MPC.ConvertAmountConvert an amount of tokens to HexString to use in a transaction's input data.

Generate MPC key

Task<(bool success, MPCError error)> MPC.Keygen(string password);

Parameters:

NameTypeDescription
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string password = $"{RECOVERY_PASSWORD}";

var privateKeyShard = await MPC.Keygen(password);
if (privateKeyShard.error != null) {
Debug.LogError($"Error when generating a key: {privateKeyShard.error.message}");
} else {
Debug.Log($"Key generation result: {privateKeyShard}");
}

Encrypt private key shard

Task<(string, MPCError)> MPC.EncryptData(string privateKeyShard, string password);

Parameters:

NameTypeDescription
privateKeyShardString (HexString)Private key generated after completing the key generation process, exclusively owned by the user. This key participates in all transaction signing processes along with the key stored in the Sky Mavis backend.
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string privateKeyShard = $"{PRIVATE_KEY}";
string password = $"{RECOVERY_PASSWORD}";
var (encryptedKey, error) = await MPC.EncryptData(privateKeyShard, password);
if (error != null)
{
Debug.LogError($"Error when getting encrypted data: {error.message}");
}
else
{
Debug.Log($"Encrypted private key shard: {encryptedKey}");
}

Decrypt private key shard

Task<(string, MPCError)> MPC.DecryptData(string encryptedKey, string password);

Parameters:

NameTypeDescription
encryptedKeyStringPrivate key shard encrypted using the user's password.
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string encryptedKey = $"{ENCRYPTED_KEY}";
string password = $"{RECOVERY_PASSWORD}";
var (privateKeyShard, error) = await MPC.DecryptData(encryptedKey, password);
if (error != null) {
Debug.LogError($"Error when getting decrypted data: {error.message}");
}
else {
Debug.Log($"Decrypted private key shard: {privateKeyShard}");
}

Back up private key shard

Task<(bool success, MPCError error)> MPC.BackupKey(string password)

Parameters:

NameTypeDescription
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

var (result, error) = await MPC.BackupKey(password);
if (error != null)
{
Debug.LogError($"Error when creating backup of private key shard: {error.message}");
}
else
{
Debug.Log($"Key backup saved to server: {result}");
}

Get backup of private key shard

Task<(string, MPCError)> MPC.GetBackupKey()

Example:

var (encryptedKey, error) = await MPC.GetBackupKey();
if (error != null) {
Debug.LogError($"Error when getting backup of private key shard: {error.message}");
}
else {
Debug.Log($"Key backup retrieved from server: {encryptedKey}");
}

Transfer native token

Task<(string txHash, MPCError error)> MPC.TransferNativeToken(string toAddress, string amount, string password);

Parameters:

NameTypeDescription
toAddressStringRecipient's address.
amountString (HexString)HexString representation of the amount to transfer.
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string toAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string amount = "0xde0b6b3a7640000"; // 1 RON
string password = $"{RECOVERY_PASSWORD}";

await MPC.Initialize(CreateAccessToken(userId));
var (txHash, error) = await MPC.TransferNativeToken(toAddress, amount, password);
if (error != null)
{
Debug.LogError($"Error transferring native token: {error.message}");
}
else
{
Debug.Log($"Transaction hash of transferring 1 RON: {txHash}");
}

Transfer ERC20 token

Task<(string txHash, MPCError error)> MPC.TransferERC20Token(string tokenAddress, string toAddress, string amount, string password);

Parameters:

NameTypeDescription
tokenAddressStringAddress of the ERC20 token's contract.
toAddressStringRecipient's address.
amountString (HexString)HexString representation of the amount to transfer.
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string tokenAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
string toAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string amount = "0xde0b6b3a7640000"; // 1 AXS
string password = $"{RECOVERY_PASSWORD}";

var (txHash, error) = await MPC.TransferERC20Token(tokenAddress, toAddress, amount, password);
if (error != null)
{
Debug.LogError($"Error when transferring ERC20: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of transferring 1 AXS: {txHash}");
}

Approve ERC20 token

Task<(string txHash, MPCError error)> MPC.ApproveERC20Token(string spenderAddress, string tokenAddress, string amount, string password);

Parameters:

NameTypeDescription
spenderAddressStringSpender address, to which you allow to spend the specified token.
tokenAddressStringAddress of the ERC20 token's contract.
amountString (HexString)HexString representation of the amount to spend.
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string spenderAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string tokenAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
string amount = "0xde0b6b3a7640000"; // 1 AXS
string password = $"{RECOVERY_PASSWORD}";

var (txHash, error) = await MPC.ApproveERC20Token(spenderAddress, tokenAddress, amount, password);
if (error != null)
{
Debug.LogError($"Error when approving ERC20: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of approving 1 AXS: {txHash}");
}

Sign message

Task<(string signedMessage, MPCError error)> MPC.SignMessage(string message, string password);

Parameters:

NameTypeDescription
messageStringMessage to sign.
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string message = "Sign this message to breed Axie #223495 with Axie #123232";
string password = $"{RECOVERY_PASSWORD}";

var (data, error) = await MPC.SignMessage(message, password);
if (error != null)
{
Debug.LogError($"Error when signing message: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Signature: {JsonConvert.SerializeObject(data)}");
}

Call contract

Task<(string txHash, MPCError error)> MPC.CallContract(string from, string to, string value, string input, string password);

Parameters:

NameTypeDescription
fromStringUser's wallet address.
toStringContract address.
valueString (HexString)HexString representation of the token amount.
inputStringTransaction's input data.
passwordStringRecovery password set by the user to protect privateKeyShard. Only the user with the correct password can access the private key.

Example:

string from = "0xB980D30Dc0c318BccFf6C760eDf465Fa9D2950Bd";
string to = "0xDa44546C0715ae78D454fE8B84f0235081584Fe0";
string value = "0xde0b6b3a7640000"; // 1 RON
string password = $"{RECOVERY_PASSWORD}";
string input = "0x7da5cd66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000002082d1fedd8c2d2408c22869c49000f5e375ddbb000000000000000000000000000000000000000000000000000000006593f08b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a959726154953bae111746e265e6d754f48570e60000000000000000000000003c4e17b9056272ce1b49f6900d8cfd6171a1869d";

var (txHash, error) = await MPC.CallContract(from, to, value, input, password);
if (error != null)
{
Debug.LogError($"Error when calling contract: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of calling contract to swap 1 RON to AXS: {txHash}");
}

Get wallet address

// Initialize the MPC environment
await MPC.Initialize(CreateAccessToken(userId), Environment.Staging);
Debug.Log($"Wallet address: {MPC.WalletAddress}");

Verify if user has backup of private key shard

bool hasBackupKey = MPC.HasBackupKey;
Debug.Log($"User has backup key: {hasBackupKey}");

Verify if user has MPC key

bool hasPrivateKey = MPC.HasPrivateKey;
Debug.Log($"Is new wallet: {hasPrivateKey}");

Log user out

MPC.Logout();

Get native token balance

Task<(string balance, MPCError error)> MPC.GetRONBalance();

Example:

var result = await MPC.GetRONBalance();
if (result.error != null)
{
Debug.LogError($"Error when getting RON balance: {result.error}");
}
else
{
Debug.Log($"RON balance: {result.balance.HexToBigInt()}");
}

Get ERC20 token balance

Task<(string balance, MPCError error)> MPC.GetERC20Balance(string tokenAddress);

Parameters:

NameTypeDescription
tokenAddressStringAddress of the ERC20 token's contract.

Example:

string tokenAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract

var result = await MPC.GetERC20Balance(axsAddress);
if (result.error != null) {
Debug.LogError($"Error when getting ERC20 balance: {result.error}");
}
else {
Debug.Log($"ERC20 balance: {result.balance.HexToBigInt()}");
}

Update access token

void MPC.UpdateAccessToken(string accessToken);

Parameters:

NameTypeDescription
accessTokenStringValid access token returned from an OAuth 2.0 provider.

Estimate gas for native token transfer

Task<(EstimateGas data, MPCError error)> MPC.EstimateTransferNativeTokenGas(string toAddress, string amount);

Parameters:

NameTypeDescription
toAddressStringRecipient's address.
amountString (hexString)HexString representation of the amount to transfer.

Example:

string toAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string amount = "0xde0b6b3a7640000"; // 1 RON
var (data, error) = await MPC.EstimateTransferNativeTokenGas(toAddress, amount);
if (error != null) {
Debug.LogError($"Error estimating gas: {error}");
} else {
Debug.Log($"Gas: {data.gas} - {data.gas.HexToBigInt()}");
Debug.Log($"Gas price: {data.gasPrice} - {data.gasPrice.HexToBigInt()}");
}

Estimate gas for ERC20 token transfer

 Task<(EstimateGas data, MPCError error)> MPC.EstimateERC20TokenGas(string signature, string tokenAddress, string toAddress, string amount);

Parameters:

NameTypeDescription
signatureStringSignature of the smart contract's function.
tokenAddressStringAddress of the ERC20 token's contract.
toAddressStringRecipient's address.
amountString (HexString)HexString representation of the amount to transfer.

Example:

string tokenAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
string toAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string amount = "0xde0b6b3a7640000"; // 1 AXS

var (data, error) = await MPC.EstimateERC20TokenGas(MPCConstants.kSignatureApprove, tokenAddress, toAddress, amount);

if (error != null) {
Debug.LogError($"Error estimating gas: {error}");
}
else {
Debug.Log($"Gas: {data.gas} - {data.gas.HexToBigInt()}");
Debug.Log($"Gas price: {data.gasPrice} - {data.gasPrice.HexToBigInt()}");
}

Convert amount

BigInteger MPCUtils.ConvertAmount(string amount, int power);

Example:

  1. Convert the amount from a string to a BigInteger:
var amount = MPCUtils.ConvertAmount("10", 18);
Debug.Log($"BigInteger amount: {amount}");
  1. Transform BigInt to HexString for transaction usage:
var amount = MPCUtils.ConvertAmount("10", 18);
Debug.Log($"Hex amount: {amount.BigIntToHex()}");

Error handling

When making requests to our APIs, you may encounter two types of errors: SDK errors and server errors.

  • SDK errors are static, client-side errors that typically arise from issues in the syntax or semantics of your code using the MPC SDK.
  • Server errors are dynamic errors that occur on the MPC server itself.

When a user encounters an error, the system's response may include an SDK error code and a server error code. SDK errors occur before the user interacts with the Sky Mavis server, while server errors indicate issues with the server itself. The error response may also contain a 4xx HTTP status code, which points to a problem with the request sent by your game to Sky Mavis, such as an invalid format or missing information.

Error response syntax

{
"code": <CODE>,
"errorMessage": <MESSAGE>,
"serverErrorCode": <SERVER_ERROR_CODE>,
"closedReason": <SOCKET_CLOSED_REASON>
}
PropertyTypeDescription
codeNumberError code triggered by the SDK.
errorMessageStringCombination of the error code and name, and information on how to address the error.
serverErrorCodeNumberError code returned from the MPC server.
closedReasonStringUsed for server-side errors when the server closes the socket abruptly. Contains the name of the error and information on how to address it.

Sample response:

{
code: 20,
errorMessage: "error: code=110 message=hit ratelimit, retry later in 60.000000 seconds",
serverErrorCode: 110,
closedReason: "hit ratelimit, retry later in 60.000000 seconds"
}

Error codes

SDK error codes and server error codes have the same definitions. You can find these definitions in the following table.

CodeNameDefinitionGenerated by
0OKNot an error. Returned on success.Client
1CancelledThe operation is cancelled, typically by the caller.Server
2UnknownUnknown error. An example of where this error may be returned is if a status value received from another address space belongs to an error-space that is not known in this address space. Also errors raised by APIs that do not return enough error information may be converted to this error.Client and server
3InvalidArgumentThe client specified an invalid argument.Client and server
4DeadlineExceededThe operation expired before completion. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from the server could have been delayed long enough for the deadline to expire.Client
5NotFoundA requested entity, such as a file or directory, is not found.Client and server
6AlreadyExistsAn attempt to create an entity failed because one already exists.Server
7PermissionDeniedThe caller doesn't have the permission to execute the specified operation. Don't use this for rejections caused by exhausting some resource—use ResourceExhausted instead. Also don't use if the caller can't be identified—use Unauthenticated instead.Server
8ResourceExhaustedA resource is exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.Server
10AbortedThe operation is aborted, typically due to a concurrency issue.Server
12UnimplementedThis method or this SDK isn't implemented yet and can't be used.Client and server
13InternalSome invariants expected by the underlying system are broken.Server
14UnavailableThe data isn't ready to accept this request.Server
16UnauthenticatedThe request doesn't have valid authentication credentials for the operation.Client
20MPCInitializeProtocolFailedThe MPC protocol failed to initialize.Client and server
21MPCHandshakeProtocolFailedFailed to handshake with the other party in the MPC protocol.Client and server
22MPCBadSignatureThe resultant MPC signature is malformed.Client and server
23MPCSignatureVerifyFailedThe signature is received, but an attempt to verify the data with this signature failed.Client
24MPCServerStoreKeyFailedFailed to store the key on the keystore server.Client and server
25MPCBadResultThe MPC protocol successfully completed, but an unexpected bad result occurred.Client and server
26MPCSendTxRequestFailedFailed to send the transaction request to the server.Client
27MPCBadKeyThe user's private key shard is malformed or invalid.Client and server
28MPCSignMessageFailedThe message signing phase failed.Client and server
29MPCSendTxFailedFailed to send the transaction to RPC.Client and server
30MPCAddressAlreadyExistedThe MPC wallet address already exists.Server
31MPCChallengeFailedIn the backup flow, the MPCChallenge is a phase that verifies whether the user owns the key. This error returns when that phase failed.Server
100DialSocketFailedFailed to dial a WebSocket server.Client
101WriteDataFailedFailed to write data to a WebSocket channel.Client and server
102ReadDataFailedFailed to read data from a WebSocket channel.Client and server
103BadRPCDataReceived an invalid MPC protocol message.Client and server
104BadSignMessageDataReceived malformed or invalid message signing data.Client and server
105BadTxDataReceived malformed or invalid transaction data.Client and server
106InitHTTPFailedFailed to initialize the process of the HTTP connection, preventing the app from establishing a valid connection to the server or resource.Client
107DoHTTPFailedFailed when calling JSON-RPC API or RESTful API.Client
108BadHTTPDataReceived unexpected data from the server.Client
109DialRPCNodeFailedWhen sending a transaction or any action that requires interaction with an RPC node, the server couldn't connect to the RPC node.Server
110HitRateLimitUUIDThe rate limit exceeded, try again later (up to 60 seconds).Server
1001PolicyFailedThe user exceeded the limit set by a transaction policy. For example, exceeded the limit of RON transfers or tried to call a smart contract that isn't allowlisted.Server

HTTP status codes

CodeNameDefinition
400Bad RequestThe API request itself is incorrect and contains invalid or incorrect values.
401UnauthorizedThe API request is sent with invalid authentication information (for example, bad JWT).
403ForbiddenThe API request is trying to perform something that the user is not allowed to do.
404Not FoundThe API request is trying to query a page that doesn’t exist.
429Too Many RequestsThe rate limit is exceeded. For more information, see Rate limits.
Was this helpful?
Happy React is loading...