Skip to main content

Ronin Waypoint Unity SDK

Overview

The Ronin Waypoint Unity SDK lets developers integrate the account and wallet features of the Ronin Waypoint service into Unity games deployed to mobile platforms (Android and iOS) and desktop platforms (Windows and macOS). After the integration, users can sign in to your game with their Ronin Waypoint account and connect their keyless wallet for instant in-game transactions.

User experience varies depending on the platform:

  • Mobile users interact with Ronin Waypoint through a native WebView.
  • Desktop users interact with Ronin Waypoint through an overlay window in the Mavis Hub app.

Whenever the implementation differs between platforms, this guide specifies the platform-specific steps.

GitHub repository: skymavis/waypoint-unity.

Features

  • Authorize users: let users sign in to your app with Ronin Waypoint and connect their wallet.
  • Send transactions: transfer RON, ERC-20 tokens, and make contract calls for in-game transactions.
  • Sign messages and typed data: have users sign messages and structured data to prove ownership of their wallet and authorize transactions.

Prerequisites

Unity version:

Desktop requirements:

  • To distribute your game through Mavis Hub, contact your Sky Mavis point of contact.
  • .Net v3.1 or later.

Mobile requirements:

  • An app created in the Developer Console.
  • Permission to use the Sky Mavis Account service. Request in the Developer Console under your app > App Permission > Sky Mavis Account (OAuth 2.0) > Request Access.
  • A client ID that you can find in the Developer Console under Products > Waypoint Service > CLIENT ID (APPLICATION ID).
  • A redirect URI registered in the Developer Console under Products > Waypoint Service > REDIRECT URI.
  • To deploy to Android, Android API level 24 or later.
  • To deploy to iOS, iOS 13.0 or later.

For more information about the initial setup, see Get started.

Example app

The Unity SDK includes an example app that demonstrates the SDK features. To run the app, follow these steps:

  1. Clone the skymavis/waypoint-unity repository, then add it as a new project in Unity Hub.
  2. In Build Settings, select the platform you want to deploy to, then click Switch Platform.
  3. Click Build and Run to open the app on the selected platform.

Make sure to fill in the client ID and redirect URI that you registered in the Developer Console.

For more information, see the official Unity documentation.

Setup

Installation

Sky Mavis distributes the SDK as a .unitypackage file on our GitHub repository. To install, follow these steps:

  1. Download the latest waypoint.unitypackage release from the GitHub repository.
  2. Import the waypoint.unitypackage file by selecting the Unity menu option Assets > Import package > Custom Package and importing waypoint.unitypackage.
  3. In Unity Editor, go to Build Settings, then choose the platform you are deploying, then click Switch Platform.

Next, configure the platform-specific settings.

  1. Go to Project Settings > Player > Settings for Android > Publishing Settings and select the following:

    • Custom Main Manifest
    • Custom Main Gradle Template
    • Custom Gradle Properties Template
  2. In the Assets/Plugins/Android directory of your Unity app, add required dependencies to the mainTemplate.gradle file:

    dependencies {
    implementation ("androidx.browser:browser:1.8.0")
    }

    Your mainTemplate.gradle file should look like this:

    apply plugin: 'com.android.library'
    **APPLY_PLUGINS**

    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation ("androidx.browser:browser:1.8.0")
    **DEPS**}

    Gradle automatically downloads the required dependencies when building the app.

  3. Instruct Gradle to use the AndroidX libraries by adding the following line to your gradleTemplate.properties file:

    android.useAndroidX=true

    Your gradleTemplate.properties file should look like this:

    org-gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
    org-gradle-parallel=true
    unityStreamingAssets=**STREAMING_ASSETS**
    android.useAndroidX=true
    **ADDITIONAL_PROPERTIES**

Initialization

Have your app initialize the SDK by calling Init once, ideally at app launch.

void Init(string appId, string deeplinkSchema, bool isTestnet = false)

Parameters:

  • appId: the client ID registered in the Developer Console.
  • deeplinkSchema: the redirect URI registered in the Developer Console.
  • isTestnet: set to true to use the Saigon testnet or false to use the Ronin mainnet.

Example:

void Start()
{
string appId = "${YOUR_CLIENT_ID}";
string deeplinkSchema = "mydapp";
SkyMavis.Waypoint.Init(AppId, deeplinkSchema, isTestnet: false);
}

Usage

User authorization and wallet connection

Use the OnAuthorize function to sign in to a Ronin Waypoint account, connect the user's wallet, and return an ID token and the user's keyless wallet address. For more information about the response format, see authorization response.

static string OnAuthorize()

Example:

public async void OnAuthorizeClicked()
{
_responseId = SkyMavis.Waypoint.OnAuthorize();
string responseData = await WaitForWaypointResponse(_responseId);
Debug.Log(responseData);
}

Wallet interactions

RON transfer

Use the SendTransaction function to send RON tokens to a recipient's address. The function returns a transaction response containing the transaction hash.

string SendTransaction(string receiverAddress, string value)

Parameters:

  • receiverAddress: the recipient address.
  • value: the amount of RON to send, specified in wei (1 RON = 10^18 wei).

Example: transfer 0.1 RON to another address.

public async void OnSendTransactionClicked()
{
string receiverAddress = "0xD36deD8E1927dCDD76Bfe0CC95a5C1D65c0a807a";
string value = "100000000000000000";

_responseId = SkyMavis.Waypoint.SendTransaction(receiverAddress, value);
string responseData = await WaitForWaypointResponse(_responseId);
Debug.Log(responseData);
}

Message signing

Use the OnPersonalSign function to sign plain text messages with the user's wallet. The function returns a transaction response containing the signature.

static string OnPersonalSign(string message)

Parameters:

  • message: the message to sign.

Example: sign the message accepting the terms and conditions.

public async void OnPersonalSignClicked()
{
// Message to sign
string message = "I accept the terms and conditions.";

// Sign the message using the SDK
_responseId = SkyMavis.Waypoint.OnPersonalSign(message);
// Wait for the response
string responseData = await WaitForWaypointResponse(_responseId);
Debug.Log(responseData);
}

Typed data signing

Use the OnSignTypeData function to sign typed data structured according to the EIP-712 standard, returning a transaction response containing the signature.

string OnSignTypeData(string typedData)

Parameters:

  • typedData: a JSON string that specifies the EIP-712 typed structured data to be signed by the user.

Example: sign typed data for an order on Axie Marketplace.

public void OnSignTypedDataClicked()
// Typed data to sign
{
string typedData = @"{""types"":{""Asset"":[{""name"":""erc"",""type"":""uint8""},{""name"":""addr"",""type"":""address""},{""name"":""id"",""type"":""uint256""},{""name"":""quantity"",""type"":""uint256""}],""Order"":[{""name"":""maker"",""type"":""address""},{""name"":""kind"",""type"":""uint8""},{""name"":""assets"",""type"":""Asset[]""},{""name"":""expiredAt"",""type"":""uint256""},{""name"":""paymentToken"",""type"":""address""},{""name"":""startedAt"",""type"":""uint256""},{""name"":""basePrice"",""type"":""uint256""},{""name"":""endedAt"",""type"":""uint256""},{""name"":""endedPrice"",""type"":""uint256""},{""name"":""expectedState"",""type"":""uint256""},{""name"":""nonce"",""type"":""uint256""},{""name"":""marketFeePercentage"",""type"":""uint256""}],""EIP712Domain"":[{""name"":""name"",""type"":""string""},{""name"":""version"",""type"":""string""},{""name"":""chainId"",""type"":""uint256""},{""name"":""verifyingContract"",""type"":""address""}]}, ""domain"":{""name"":""MarketGateway"",""version"":""1"",""chainId"":2021,""verifyingContract"":""0xfff9ce5f71ca6178d3beecedb61e7eff1602950e""},""primaryType"":""Order"",""message"":{""maker"":""0xd761024b4ef3336becd6e802884d0b986c29b35a"",""kind"":""1"",""assets"":[{""erc"":""1"",""addr"":""0x32950db2a7164ae833121501c797d79e7b79d74c"",""id"":""2730069"",""quantity"":""0""}],""expiredAt"":""1721709637"",""paymentToken"":""0xc99a6a985ed2cac1ef41640596c5a5f9f4e19ef5"",""startedAt"":""1705984837"",""basePrice"":""500000000000000000"",""endedAt"":""0"",""endedPrice"":""0"",""expectedState"":""0"",""nonce"":""0"",""marketFeePercentage"":""425""}}";
_responseId = SkyMavis.Waypoint.OnSignTypeData(typedData);
string responseData = await WaitForWaypointResponse(_responseId);
Debug.Log(responseData);
}

Contract function calls

Use the OnCallContract function to execute a function on a smart contract, returning a transaction response containing the transaction hash.

string OnCallContract(string contractAddress, string data, string value = "0x0")

Parameters:

  • contractAddress: the address of the smart contract on which to execute the transaction.
  • data: the transaction data to send to the smart contract, encoded as a hex string. For help with encoding, use Function data encoder utility.
  • value: the amount of RON in wei (1 RON = 10^18 wei) to send along with the transaction. For non-payable smart contracts, the value is 0x0.

Example: allow another contract to spend 1 AXS on user's behalf.

public async void OnApproveErc20Clicked()
{
// Contract address
string contractAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d";
// Readable ABI string for the function
string readableAbi = "function approve(address _spender, uint256 _value)";
// Approve 1 AXS
var approveParams = new { _spender = "0x6B190089ed7F75Fe17B3b0A17F6ebd69f72c3F63", _value = 1000000000000000000 };
try
{
var data = ABI.EncodeFunctionData(readableAbi, approveParams);
Debug.Log("Approve data: " + data);
_responseId = SkyMavis.Waypoint.OnCallContract(contractAddress, data);
string responseData = await WaitForWaypointResponse(_responseId);
Debug.Log(responseData);

}
catch (System.Exception e)
{
Debug.Log("Error in call contract: " + e.Message);
}

}

Utilities

Response handler

To handle responses from the SDK, define a callback method before sending a request.

public async Task<string> WaitForWaypointResponse(string id)
{
string responseData = null;
string currentId = id;
void dataCallback(string state, string data) { if (currentId == state) responseData = data; }
SkyMavis.Waypoint.BindOnResponse(dataCallback);
while (string.IsNullOrEmpty(responseData) && currentId == _responseId) await Task.Yield();
SkyMavis.Waypoint.UnBindOnResponse(dataCallback);
return responseData;
}

Function data encoder

The EncodeFunctionData utility encodes function data for smart contract interactions.

string EncodeFunctionData(string ABI, object values)

Parameters:

  • ABI: a readable ABI string that defines the function to call on the smart contract.
  • values: an array of values to pass as parameters to the smart contract function specified in the ABI.

The following sections provide some examples of how to use utility.

Example. Swap tokens on Katana

Sends a transaction to the Katana decentralized exchange to swap RON for AXS.

using SkyMavis.Utils;

public async void OnSwapRonToAxsClicked()
{
// Contract addresses
string katanaAddress = "0xDa44546C0715ae78D454fE8B84f0235081584Fe0";
string ronAddress = "0xa959726154953bae111746e265e6d754f48570e6";
string axsAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d";
// Wallet address
string walletAddress = "0x6B190089ed7F75Fe17B3b0A17F6ebd69f72c3F63";
// Readable ABI string for the function
string readableAbi = "function swapExactRONForTokens(uint256 _amountOutMin, address[] _path, address _to, uint256 _deadline)";

// Values to pass as parameters to the called function
var value = "1000000000000000000";

var swapParams = new
{
// 0.1 RON
_amountOutMin = "0",
_path = new string[] { ronAddress, axsAddress },
_to = walletAddress,
_deadline = "1814031305"
};

try
{
// Encode data using the EncodeFunctionData utility
var data = ABI.EncodeFunctionData(readableAbi, swapParams);
// Send transaction to Katana contract
_responseId = SkyMavis.Waypoint.OnCallContract(katanaAddress, data, value);
// Wait for the response
string responseData = await WaitForWaypointResponse(_responseId);
Debug.Log(responseData);
}
catch (System.Exception e)
{
Debug.Log("Error in call contract: " + e.Message);
}
}

Example. Activate Atia's Blessing

Sends a transaction to the Atia Shrine smart contract to activate the "Atia's Blessing" feature in Axie Infinity games.

using SkyMavis.Utils;
public async void onAtiaBlessingClicked()
{
// Wallet address
string walletAddress = "0x6B190089ed7F75Fe17B3b0A17F6ebd69f72c3F63";
// Atia Shrine contract address
string atiaShrineContractAddress = "0xd5c5afefad9ea288acbaaebeacec5225dd3d6d2b";
// Readable ABI string for the function
string readableAbi = "function activateStreak(address to)";
Debug.Log(readableAbi);
// Values to pass as parameters to the called function
var values = new string[] { walletAddress };

try
{
// Encode data using the EncodeFunctionData utility
var data = ABI.EncodeFunctionData(readableAbi, values);
// Send transaction to Atia Shrine contract
_responseId = SkyMavis.Waypoint.OnCallContract(atiaShrineContractAddress, data);
// Wait for the response
string responseData = await WaitForWaypointResponse(_responseId);
Debug.Log(responseData);
}
catch (System.Exception e)
{
Debug.Log("Error in Atia's blessing: " + e.Message);
}
}

Smart contract reader

The Skynet class provides methods to read data from smart contracts using the Skynet REST API.

Before using the Skynet class, initialize it with the required parameters:

class Skynet(ApiKey, ownerAddress, NftContractAddresses, ERC20ContractAddresses);

Parameters:

  • ApiKey: your app's API key from the Developer Console.
  • ownerAddress: the user's keyless wallet address.
  • NftContractAddresses: an array of contract addresses for ERC-721 tokens.
  • ERC20ContractAddresses: an array of contract addresses for ERC-20 tokens.

Example:

var SkynetAPI = "${SKYNET_API_KEY}";
var ownerAddress = "${RONIN_WALLET_ADDRESS}";
var NftContractAddresses = new string[] { Constants.Mainnet.ERC721.AxieContractAddress };
var ERC20ContractAddresses = new string[] { Constants.Mainnet.ERC20.AXSContractAddress, Constants.Mainnet.ERC20.SLPContractAddress, Constants.Mainnet.ERC20.WRONContractAddress, Constants.Mainnet.ERC20.WETHContractAddress };
var skynet = Skynet(SkynetAPI, ownerAddress, NftContractAddresses, ERC20ContractAddresses);

The following sections provide examples of how to use the Skynet class.

Example. Get total NFTs of address

Fetches the total count of NFTs defined in NftContractAddresses for the specified ownerAddress.

async Task<object> GetTotalNFTs()

Returns:

{
items: object[] {
createdAtBlock: string,
createdAtBlockTime: integer,
ownerAddresses: string,
rawMetadata: array,
tokenId: integer,
tokenName: string,
tokenStandard: string,
tokenSymbol: string,
tokenURI: string,
updatedAtBlock: integer,
updatedAtBlockTime: integer
},
paging: object {
total: integer
}
}

Example:

// Initialize Skynet
var skynet = InitializeSkynet();

// Get the total NFTs of the owner address
var response = await skynet.GetTotalNFTs();

Debug.Log("Result: Total NFTs of address: " + response);

Example. Get NFT metadata by token ID

Fetches metadata for an NFT using its token ID within the specified NftContractAddresses and ownerAddress.

async Task<object> GetNFTsMetadata(string[] tokenIds)

Parameters:

  • tokenIds: an array of token IDs for which to retrieve metadata.

Example:

// Initialize Skynet
var skynet = InitializeSkynet();

// Get the NFT metadata by token ID
var tokenIds = new string[] {${NFT_TOKEN_ID}};
var response = await skynet.GetNFTsMetadata(tokenIds);

Debug.Log("Result: NFT metadata with tokenIds: " + response);

Example. Get total ERC-20 balances of address

Fetches the total balance of ERC-20 tokens defined in Erc20ContractAddresses for the specified ownerAddress.

async Task<object> GetERC20TokenBalances()

Returns:

items: object[] {
balance: string
contractAddress: string
decimals: integer
ownerAddress: string
tokenId: string
tokenName: string
tokenStandard: string
tokenSymbol: string
},
paging : object {
total : integer
}

Example:

// Initialize Skynet
var skynet = InitializeSkynet();
// Get the total ERC-20 balances of the owner address
var response = await skynet.GetERC20TokenBalances();
var result = await response.Content.ReadAsStringAsync();

Debug.Log("Result: Total token balances of owner address: " + result);

Example. Execute an RPC call

Executes an RPC call to Ronin.

Task<string> CallRPC(string contractAddress, string data)

Parameters:

  • contractAddress: the address of the smart contract to call.
  • data: the data to send to the smart contract, encoded as a hex string.

Example:

using SkyMavis.Utils;

// Initialize Skynet
var skynet = InitializeSkynet();
// ABI for the allowance function
var allowanceOfABI = @"{""constant"":true,""inputs"":[{""internalType"":""address"",""name"":""_owner"",""type"":""address""},{""internalType"":""address"",""name"":""_spender"",""type"":""address""}],""name"":""allowance"",""outputs"":[{""internalType"":""uint256"",""name"":""_value"",""type"":""uint256""}],""payable"":false,""stateMutability"":""view"",""type"":""function""}";
// Assign values for the ABI parameters
var args = new object[] { "0x2d62c27ce2e9e66bb8a667ce1b60f7cb02fa9810", Constants.Mainnet.KatanaAddress };
// Encode data using the EncodeFunctionData utility
var data = ABI.EncodeFunctionData(allowanceOfABI, args);
// Send RPC call to check amount of AXS tokens user allowed Katana contract to spend
var result = await skynet.CallRPC(Constants.Mainnet.ERC20.AXSContractAddress, data);
// Process result: remove "0x", parse hex string to BigInteger, and format value to get Ether balance
result = result.StartsWith("0x") ? result.Substring(2) : result;
BigInteger weiValue = BigInteger.Parse(result, System.Globalization.NumberStyles.HexNumber);
BigInteger divisor = BigInteger.Pow(10, 18);
decimal formatedValue = (decimal)weiValue / (decimal)divisor;

Debug.Log("Formatted Ether balance: " + formatedValue);

Reference

Function summary

FunctionDescriptionUse case
OnAuthorizeSigns user in to Ronin Waypoint and returns their wallet address.Used for user sign-in and wallet connection.
SendTransactionSends RON tokens to a recipient address.Supports in-game purchases or token transfers.
OnPersonalSignSigns plain text messages with the user's wallet.Proves wallet ownership or agreement to terms.
OnSignTypeDataSigns structured data following the EIP-712 standard.Useful for complex data structures, such as marketplace orders.
OnCallContractExecutes functions on smart contracts.Supports in-game ERC-20 token transfers, approvals, and other contract interactions.

Response types

Authorization response

On Android and iOS, Ronin Waypoint returns an authorization response after a user connects their wallet to your app.

Authorization success
mydapp://callback?state=2ab49965-249a-48c7-896e-90967778383b&method=auth&version=1.4&type=success&data=ey...&address=0x16...ac

Response parameters:

  • state: a unique random identifier used to manage requests from the client to Ronin Waypoint.
  • method: the method used for the request (auth).
  • version: the version of the Ronin Waypoint service.
  • type: the response type (success).
  • data: the ID token that contains encoded user information.
  • address: the user's keyless wallet address.
Authorization error
mydapp://callback?state=84d18549-df10-451f-8235-184b594e3706&method=auth&version=1.4&type=fail&code=1000&message=%5BWALLET_USER_CANCEL%5D+User+rejected

Response parameters:

  • type: the response type (fail).
  • code: the error code.
  • message: a message describing the error. For more information, see Error codes.

Transaction response

Ronin Waypoint returns a transaction response after a user sends a transaction, signs a message, signs typed data, or calls a contract on the blockchain.

Transaction success
mydapp://callback?state=0bccde82-01d5-4403-90fd-f8edcfdd2ed4&method=send&version=1.4&type=success&data=0x3a...0d

Response parameters:

  • state: a unique random identifier used to manage requests from the client to Ronin Waypoint.
  • method: the method used for the request (send for transactions and sign for signing).
  • version: the version of the Ronin Waypoint service.
  • type: the response type (success).
  • data: the transaction hash.
Transaction error
mydapp://callback?state=84d18549-df10-451f-8235-184b594e3706&method=send&version=1.4&type=fail&code=1000&message=%5BWALLET_USER_CANCEL%5D+User+rejected

Response parameters:

  • type: the response type (fail).
  • code: the error code.
  • message: a message describing the error.