The Unreal Engine is aimed at Developers wanting to implement blockchain features into their game. The Unreal Engine allows the game to connect and interact with the blockchain.
View Demo
Β·
Table of Contents
- Download 'MirageSDK.zip' package from latest release.
- Unzip MirageSDK.zip package to your Unreal Project's Plugins folder.
- Delete Binaries, Intermediate, Saved folders.
- Generate Visual Studio (or Xcode) project by Right-Clicking .uproject and select Generate Visual Studio project (or Services->Generate Xcode project) respectively.
- Open the generated Visual Studio (or Xcode) project and check if the plugin in included inside the Game project.
- There are two ways you can create an instance of MirageClient object which are shown below:
(6a) Open any of your blueprint, call "Construct Object From Class", select MirageClient and store the reference in a variable.
(6b) Locate your GameInstance.h if already created. If not Add C++ class from Content Browser in Unreal Engine, check 'Show All Classes' and select GameInstance. Name your class 'MyGameInstance'.
- Open MyGameInstance.h and include the following code:
#include "MirageClient.h"
UPROPERTY()
UMirageClient* mirageClient;
UFUNCTION(BlueprintCallable, Category = "MIRAGE SDK")
UMirageClient* GetMirageClient();
- Open MyGameInstance.cpp and include the following code:
UMirageClient* UMyGameInstance::GetMirageClient()
{
if (mirageClient == nullptr)
{
mirageClient = NewObject<UMirageClient>();
}
return mirageClient;
}
- Add "MirageSDK" to your Unreal Project/Source/Unreal Project/Build.cs as shown below:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "MirageSDK" });
-
Click Edit->Project Settings->Maps and Modes and select your newly created or already created GameInstance from the GameInstance Class dropdown.
-
Now you can call all the functions in blueprint by getting GetGameInstance->GetMirageClient.
MirageSDK is used to interact with the blockchain using the latest Unreal Engine 5+
- Front End - Unreal Engine 5+
- Back End
- Mirage handles all communication with the blockchain
- The Unreal Engine calls the Mirage API to interact with the blockchain.
Currently, the Unreal Engine serves three Use Cases.
- Connect Wallet (MetaMask) and Authenticate User
- Update NFT by signing and sending Transactions
- Wearables NFT (Minting)
- Smart Contracts must be deployed on the blockchain.
- Smart Contract addresses and ABI
ConnectWallet is used to connect to the wallet app on your mobile device, on desktop a QR Code will be generated at the time the login button is pressed. The session is saved to a variable for later use.
To Connect wallet call the C++ ConnectWallet in Blueprint shown below:
void UMirageClient::ConnectWallet(const FMirageCallCompleteDynamicDelegate& Result);
-
If Login is required, wallet app will be opened on your mobile device to connect to.
-
If already logged in then GetWalletInfo is used to the get the wallet information.
To Get wallet information call the C++ GetWalletInfo in Blueprint shown below:
void UMirageClient::GetWalletInfo(const FMirageCallCompleteDynamicDelegate& Result);
SendTransaction is used to send a transaction and a ticket will be generated. Metamask will show popup to confirm the ticket generated by the transaction.
void UMirageClient::SendTransaction(FString contract, FString abi_hash, FString method, FString args, const FMirageCallCompleteDynamicDelegate& Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"device_id", UPayloadBuilder::FStringToJsonValue(UMirageUtility::GetDeviceID())},
{"contract_address", UPayloadBuilder::FStringToJsonValue(contract)},
{"abi_hash", UPayloadBuilder::FStringToJsonValue(abi_hash)},
{"method", UPayloadBuilder::FStringToJsonValue(method)},
{"args", UPayloadBuilder::FStringToJsonValue(args)}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_SEND_TRANSACTION, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("MirageClient - SendTransaction - response: %s"), *content);
FString ticket = jsonObject->GetStringField("ticket");
#if PLATFORM_ANDROID || PLATFORM_IOS
FPlatformProcess::LaunchURL(UMirageUtility::GetSession().GetCharArray().GetData(), NULL, NULL);
#endif
UMirageUtility::SetLastRequest("SendTransaction");
callback.ExecuteIfBound(content, ticket, "", -1, false);
}, Result, true);
}
If you want to send transactions, use the function SendTransaction
with parameters having, device_id
, contract_address
, abi_hash
, method
and args
.
Check status of tickets by calling GetTicketResult
.
For example, if you come back to the game, check the status of the ticket with GetTicketResult function with parameters device_id
, ticket
.
Returns the status of the result.
Successful or unsuccessful.
CallMethod is used to call a function from the contract and is only readable so will not change the state of the contract.
void UMirageClient::CallMethod(FString contract, FString abi_hash, FString method, FString args, const FMirageCallCompleteDynamicDelegate& Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"device_id", UPayloadBuilder::FStringToJsonValue(UMirageUtility::GetDeviceID())},
{"contract_address", UPayloadBuilder::FStringToJsonValue(contract)},
{"abi_hash", UPayloadBuilder::FStringToJsonValue(abi_hash)},
{"method", UPayloadBuilder::FStringToJsonValue(method)},
{"args", UPayloadBuilder::FStringToJsonValue(args)}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_CALL_METHOD, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("MirageClient - CallMethod - response: %s"), *content);
callback.ExecuteIfBound(content, content, "", -1, false);
}, Result, false);
}
SendABI is used to get the hash of the abi.
void UMirageClient::SendABI(FString abi, const FMirageCallCompleteDynamicDelegate& Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"abi", UPayloadBuilder::FStringToJsonValue(abi)}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_ABI, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("MirageClient - SendABI - response: %s"), *content);
FString abi = jsonObject->GetStringField("abi");
callback.ExecuteIfBound(content, abi, "", -1, false);
}, Result, false);
}
SignMessage is used to sign a message Metamask will show popup to sign or cancel the signing of the message.
void UMirageClient::SignMessage(FString message, const FMirageCallCompleteDynamicDelegate & Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"device_id", UPayloadBuilder::FStringToJsonValue(UMirageUtility::GetDeviceID())},
{"message", UPayloadBuilder::FStringToJsonValue(message)}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_SIGN_MESSAGE, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("MirageClient - SignMessage - response: %s"), *content);
FString ticket = jsonObject->GetStringField("ticket");
#if PLATFORM_ANDROID || PLATFORM_IOS
FPlatformProcess::LaunchURL(UMirageUtility::GetSession().GetCharArray().GetData(), NULL, NULL);
#endif
UMirageUtility::SetLastRequest("SignMessage");
callback.ExecuteIfBound(content, ticket, "", -1, false);
}, Result, true);
}
GetSignature is used to get the result whether the user has signed the message or cancelled the signing.
void UMirageClient::GetSignature(FString ticket, const FMirageCallCompleteDynamicDelegate& Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"ticket", UPayloadBuilder::FStringToJsonValue(ticket)}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_RESULT, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("MirageClient - GetSignature - response: %s"), *content);
TSharedPtr<FJsonObject> data = jsonObject->GetObjectField("data");
FString signature = data->GetStringField("signature");
callback.ExecuteIfBound(content, signature, "", -1, false);
}, Result, false);
}
VerifyMessage is used to verify if the connected user has signed the message.
void UMirageClient::VerifyMessage(FString message, FString signature, const FMirageCallCompleteDynamicDelegate& Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"device_id", UPayloadBuilder::FStringToJsonValue(UMirageUtility::GetDeviceID())},
{"message", UPayloadBuilder::FStringToJsonValue(message)},
{"signature", UPayloadBuilder::FStringToJsonValue(signature)}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_VERIFY_MESSAGE, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("MirageClient - VerifyMessage - response: %s"), *content);
FString address = jsonObject->GetStringField("address");
callback.ExecuteIfBound(content, address, "", -1, false);
}, Result, false);
}
Getting NFTs and Making updates to the NFT.
GetNFTInfo is used to get the NFT information.
void UUpdateNFTExample::GetNFTInfo(FString abi_hash, int tokenId, FMirageCallCompleteDynamicDelegate Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"device_id", UPayloadBuilder::FStringToJsonValue(UMirageUtility::GetDeviceID())},
{"contract_address", UPayloadBuilder::FStringToJsonValue(ContractAddress)},
{"abi_hash", UPayloadBuilder::FStringToJsonValue(abi_hash)},
{"method", UPayloadBuilder::FStringToJsonValue("getTokenDetails")},
{"args", UPayloadBuilder::FStringToJsonValue(FString::FromInt(tokenId))}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_CALL_METHOD, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("UpdateNFTExample - GetNFTInfo - response: %s"), *content);
callback.ExecuteIfBound(content, content, "", -1, false);
}, Result, false);
}
UpdateNFT is used to update the information on the NFT. Metamask will show popup to sign or confirm the transaction for that ticket.
void UUpdateNFTExample::UpdateNFT(FString abi_hash, int _tokenId, int _itemType, int _strength, int _level, int _expireTime, FMirageCallCompleteDynamicDelegate Result)
{
TSharedPtr<FJsonObject> item = UPayloadBuilder::GetBuilder();
item->SetNumberField("tokenId", _tokenId);
item->SetNumberField("itemType", _itemType);
item->SetNumberField("strength", _strength);
item->SetNumberField("level", _level);
item->SetNumberField("expireTime", _expireTime);
item->SetStringField("signature", FString("0x"));
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddNestedObject(args, item);
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", ContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "updateTokenWithSignedMessage");
builder->SetArrayField("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_SEND_TRANSACTION, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("UpdateNFTExample - UpdateNFT - response: %s"), *content);
FString ticket = jsonObject->GetStringField("ticket");
callback.ExecuteIfBound(content, ticket, "", -1, false);
#if PLATFORM_ANDROID || PLATFORM_IOS
UMirageUtility::SetLastRequest("UpdateNFT");
FPlatformProcess::LaunchURL(UMirageUtility::GetSession().GetCharArray().GetData(), NULL, NULL);
#endif
}, Result, true);
}
MintCharacter is used to mint a character to the wallet address. Metamask will show popup to sign or confirm the transaction for that ticket.
void UWearableNFTExample::MintCharacter(FString abi_hash, FString to, FMirageCallCompleteDynamicDelegate Result)
{
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddArrayItem(args, to);
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameCharacterContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "safeMint");
builder->SetArrayField ("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_SEND_TRANSACTION, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - MintCharacter - response: %s"), *content);
FString ticket = jsonObject->GetStringField("ticket");
UMirageUtility::SetLastRequest("MintCharacter");
callback.ExecuteIfBound(content, ticket, "", -1, false);
#if PLATFORM_ANDROID || PLATFORM_IOS
FPlatformProcess::LaunchURL(UMirageUtility::GetSession().GetCharArray().GetData(), NULL, NULL);
#endif
}, Result, true);
}
MintItems is used to mint items in a batch. Metamask will show popup to sign or confirm the transaction for that ticket.
void UWearableNFTExample::MintItems(FString abi_hash, FString to, FMirageCallCompleteDynamicDelegate Result)
{
const TArray<FString> items = { BlueHatAddress, RedHatAddress, BlueShoesAddress, WhiteShoesAddress, RedGlassesAddress, WhiteGlassesAddress };
TArray<TSharedPtr<FJsonValue>> itemsArray;
for (int32 i = 0; i < items.Num(); i++)
{
UPayloadBuilder::AddArrayItem(itemsArray, items[i]);
}
const TArray<int> indices = { 1, 2, 3, 4, 5, 6 };
TArray<TSharedPtr<FJsonValue>> indicesArray;
for (int32 i = 0; i < indices.Num(); i++)
{
UPayloadBuilder::AddArrayItem(indicesArray, indices[i]);
}
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddArrayItem (args, to);
UPayloadBuilder::AddNestedArray(args, itemsArray);
UPayloadBuilder::AddNestedArray(args, indicesArray);
UPayloadBuilder::AddArrayItem (args, FString("0x"));
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameItemContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "mintBatch");
builder->SetArrayField ("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_SEND_TRANSACTION, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - MintItems - response: %s"), *content);
FString ticket = jsonObject->GetStringField("ticket");
UMirageUtility::SetLastRequest("MintItems");
callback.ExecuteIfBound(content, ticket, "", -1, false);
#if PLATFORM_ANDROID || PLATFORM_IOS
FPlatformProcess::LaunchURL(UMirageUtility::GetSession().GetCharArray().GetData(), NULL, NULL);
#endif
}, Result, true);
}
GameItemSetApproval is used to set an approval for the call operator. Metamask will show popup to sign or confirm the transaction for that ticket.
void UWearableNFTExample::GameItemSetApproval(FString abi_hash, FString callOperator, bool approved, FMirageCallCompleteDynamicDelegate Result)
{
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddArrayItem(args, GameCharacterContractAddress);
UPayloadBuilder::AddArrayItem(args, true);
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameItemContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "setApprovalForAll");
builder->SetArrayField("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_SEND_TRANSACTION, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GameItemSetApproval - response: %s"), *content);
FString data = content;
bool result = jsonObject->GetBoolField("result");
if (result)
{
FString ticket = jsonObject->GetStringField("ticket");
data = ticket;
}
UMirageUtility::SetLastRequest("GameItemSetApproval");
callback.ExecuteIfBound(content, data, "", -1, false);
#if PLATFORM_ANDROID || PLATFORM_IOS
FPlatformProcess::LaunchURL(UMirageUtility::GetSession().GetCharArray().GetData(), NULL, NULL);
#endif
}, Result, true);
}
GetCharacterBalance is used to get the token balance that the user has in their wallet. The 'data' shows the number of tokens that the user holds.
void UWearableNFTExample::GetCharacterBalance(FString abi_hash, FString address, FMirageCallCompleteDynamicDelegate Result)
{
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddArrayItem(args, address);
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameCharacterContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "balanceOf");
builder->SetArrayField("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_CALL_METHOD, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GetCharacterBalance - response: %s"), *content);
FString data = jsonObject->GetStringField("data");
callback.ExecuteIfBound(content, data, "", -1, false);
}, Result, false);
}
GetCharacterTokenId is used to get the token Id at the specified index. The 'data' shows the id of the character.
void UWearableNFTExample::GetCharacterTokenId(FString abi_hash, int tokenBalance, FString owner, FString index, FMirageCallCompleteDynamicDelegate Result)
{
if (tokenBalance <= 0)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GetCharacterTokenId - You don't own any of these tokens - tokenBalance: %d"), tokenBalance);
return;
}
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddArrayItem(args, owner);
UPayloadBuilder::AddArrayItem(args, index);
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameCharacterContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "tokenOfOwnerByIndex");
builder->SetArrayField("args", args);
const FString payload = UPayloadBuilder::Build(builder);
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GetCharacterTokenId - payload: %s"), *payload);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_CALL_METHOD, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GetCharacterTokenId - response: %s"), *content);
FString data = jsonObject->GetStringField("data");
callback.ExecuteIfBound(content, data, "", -1, false);
}, Result, false);
}
ChangeHat is used to change the hat of the character to another available hat. Metamask will show popup to sign or confirm the transaction for that ticket.
void UWearableNFTExample::ChangeHat(FString abi_hash, int characterId, FString hatAddress, FAnkrCallCompleteDynamicDelegate Result)
{
if (characterId < 0)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - ChangeHat - CharacterID or HatID is null"));
return;
}
if (hatAddress.Equals(BlueHatAddress)) UAnkrUtility::SetLastRequest("ChangeHatBlue");
else if (hatAddress.Equals(RedHatAddress)) UAnkrUtility::SetLastRequest("ChangeHatRed");
else if (hatAddress.Equals(RedHatAddress)) UAnkrUtility::SetLastRequest("ChangeHatWhite");
TSharedPtr<FJsonObject> gas = UPayloadBuilder::GetBuilder();
gas->SetNumberField("gasLimit", 200000);
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddArrayItem(args, FString::FromInt(characterId));
UPayloadBuilder::AddArrayItem(args, hatAddress);
//UPayloadBuilder::AddNestedObject(args, gas);
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameCharacterContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "changeHat");
builder->SetArrayField("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_SEND_TRANSACTION, "POST", payload, [this, hatAddress](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - ChangeHat - response: %s"), *content);
FString ticket = jsonObject->GetStringField("ticket");
callback.ExecuteIfBound(content, ticket, "", -1, false);
#if PLATFORM_ANDROID || PLATFORM_IOS
FPlatformProcess::LaunchURL(UMirageUtility::GetSession().GetCharArray().GetData(), NULL, NULL);
#endif
}, Result, true);
}
GetHat is used to get the current hat of the character. The 'data' shows the token address that the player has.
void UWearableNFTExample::GetHat(FString abi_hash, int characterId, FMirageCallCompleteDynamicDelegate Result)
{
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddArrayItem(args, FString::FromInt(characterId));
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameCharacterContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "getHat");
builder->SetArrayField("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_CALL_METHOD, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GetHat - response: %s"), *content);
FString data = jsonObject->GetStringField("data");
callback.ExecuteIfBound(content, data, "", -1, false);
}, Result, false);
}
GetWearableNFTResult is used to get the result of the ticket. The 'status' shows whether the result for the ticket signed has a success with a transaction hash. The 'code' shows a code number related to a specific failure or success.
void UWearableNFTExample::GetWearableNFTResult(FString ticketId, FMirageCallCompleteDynamicDelegate Result)
{
const FString payload = UPayloadBuilder::BuildPayload(
{
{"ticket", UPayloadBuilder::FStringToJsonValue(ticketId)}
});
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_RESULT, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GetWearableNFTResult - response: %s"), *content);
FString status;
FString txHash;
bool hasTxHash = false;
bool result = jsonObject->GetBoolField("result");
if (result)
{
TSharedPtr<FJsonObject> object = jsonObject->GetObjectField("data");
status = object->GetStringField("status");
hasTxHash = object->TryGetStringField("tx_hash", txHash);
if (hasTxHash)
{
UE_LOG(LogTemp, Warning, TEXT("tx_hash: %s"), *txHash);
}
}
callback.ExecuteIfBound(content, txHash, status, -1, hasTxHash);
}, Result, false);
}
GetItemsBalance is used to get the balance of items in a batch. The 'data' shows a response of an array of balances for each token, in the sequence that were sent as a request.
void UWearableNFTExample::GetItemsBalance(FString abi_hash, FString address, FMirageCallCompleteDynamicDelegate Result)
{
TArray<TSharedPtr<FJsonValue>> addressArray;
for (int32 i = 0; i < 9; i++)
{
UPayloadBuilder::AddArrayItem(addressArray, UMirageUtility::GetWalletAddress());
}
const TArray<FString> items = { BlueHatAddress, RedHatAddress, WhiteHatAddress, BlueShoesAddress, RedShoesAddress, WhiteShoesAddress, BlueGlassesAddress, RedGlassesAddress, WhiteGlassesAddress };
TArray<TSharedPtr<FJsonValue>> itemsArray;
for (int32 i = 0; i < items.Num(); i++)
{
UPayloadBuilder::AddArrayItem(itemsArray, items[i]);
}
TArray<TSharedPtr<FJsonValue>> args;
UPayloadBuilder::AddNestedArray(args, addressArray);
UPayloadBuilder::AddNestedArray(args, itemsArray);
TSharedPtr<FJsonObject> builder = UPayloadBuilder::GetBuilder();
builder->SetStringField("device_id", UMirageUtility::GetDeviceID());
builder->SetStringField("contract_address", GameItemContractAddress);
builder->SetStringField("abi_hash", abi_hash);
builder->SetStringField("method", "balanceOfBatch");
builder->SetArrayField("args", args);
const FString payload = UPayloadBuilder::Build(builder);
SendRequest(UMirageUtility::GetUrl() + ENDPOINT_CALL_METHOD, "POST", payload, [this](const TArray<uint8> bytes, const FString content, const FMirageCallCompleteDynamicDelegate& callback, TSharedPtr<FJsonObject> jsonObject)
{
UE_LOG(LogTemp, Warning, TEXT("WearableNFTExample - GetItemsBalance - response: %s"), *content);
FString data = jsonObject->GetStringField("data");
callback.ExecuteIfBound(content, data, "", -1, false);
}, Result, false);
}
We have two ERC proposals.
ERC-4884 Rentable NFT Standard
ERC-4911 Composability Extension For ERC-721 Standard