Unity
Before using, please review the prerequisites, All unity SDKs are open source, click here to view
Initialize the SDK
Drag prefab to your scene
Drag the ParticleAA.prefab to your first scene(Required)
Before using the SDK, you have to call init(Required)
(Optional) The biconomyApiKeys comes from Biconomy, visit Biconomy Dashboard to learn more.
var biconomyApiKeys = new Dictionary<int, string>
{
{ 1, "your ethereum mainnet key" },
{ 5, "your ethereum goerli key" },
{ 137, "your polygon mainnet key" },
{ 80001, "your polygon mumbai key" }
};
// AccountName support BICONOMY_V1 | BICONOMY_V2 | SIMPLE | CYBERCONNECT
ParticleAAInteraction.Init(AAAccountName.BICONOMY_V1(), biconomyApiKeys);
2. Drag prefab to your scene
Drag the ParticleAA.prefab to your first scene(Required)
Is deploy AA wallet
try
{
var eoaAddress = ParticleAuthServiceInteraction.GetAddress();
var nativeResultData = await ParticleAA.Instance.IsDepoly(eoaAddress);
Debug.Log("result" + nativeResultData.data);
if (nativeResultData.isSuccess)
{
var isDeploy = Convert.ToBoolean(nativeResultData.data);
Debug.Log($"isDeploy {isDeploy}");
}
else
{
var errorData = JsonConvert.DeserializeObject<NativeErrorData>(nativeResultData.data);
Debug.Log(errorData);
}
}
catch (Exception e)
{
Debug.LogError($"An error occurred: {e.Message}");
}
Is AA mode enable
var result = ParticleAAInteraction.IsAAModeEnable();
Enable AA mode
ParticleAAInteraction.EnableAAMode();
Disable AA mode
ParticleAAInteraction.DisableAAMode();
Get smart account address
public async void GetSmartAccount()
{
try
{
var eoaAddress = "your EOA address";
var smartAccountResult = await EvmService.GetSmartAccount(new[]
{
new SmartAccountObject(AAAccountName.BICONOMY_V1(), eoaAddress)
});
var smartAccountAddress = (string)JObject.Parse(smartAccountResult)["result"][0]["smartAccountAddress"];
}
catch (Exception e)
{
Debug.LogError($"An error occurred: {e.Message}");
}
}
Send transaction
You should use ParticleAuth | ParticleConnect | ParticleAuthCore to send transaction, all of them have a function called signAndSendTransaction
or evmSendTransaction
, a parameter called feeMode
is used with AA service.
feeMode
support native, gasless and token, just as its name implies, it tells how to pay gas fee.
SignAndSendTransaction with Connect Service
Show how to send transaction with particle-connect, use native token to pay gas fee.
try
{
var eoaAddress = "your EOA address";
var smartAccountResult = await EvmService.GetSmartAccount(new[] { new SmartAccountObject(AAAccountName.BICONOMY_V1(), eoaAddress) });
var smartAccountAddress = (string)JObject.Parse(smartAccountResult)["result"][0]["smartAccountAddress"];
var transaction = await TransactionHelper.GetEVMTransactionWithConnect(smartAccountAddress);
// check if enough native for gas fee
var feeQuotesResult =
await ParticleAA.Instance.RpcGetFeeQuotes(eoaAddress, new List<string> { transaction });
var verifyingPaymasterNative = JObject.Parse(feeQuotesResult.data)["verifyingPaymasterNative"];
var feeQuote = verifyingPaymasterNative["feeQuote"];
var fee = BigInteger.Parse((string)feeQuote["fee"]);
var balance = BigInteger.Parse((string)feeQuote["balance"]);
if (balance < fee)
{
Debug.Log("native balance if not enough for gas fee");
return;
}
// pass result from rpcGetFeeQuotes to send pay with native
var nativeResultData =
await ParticleConnect.Instance.SignAndSendTransaction(WalletType.MetaMask, eoaAddress, transaction,
AAFeeMode.Native(JObject.Parse(feeQuotesResult.data)));
Debug.Log(nativeResultData.data);
if (nativeResultData.isSuccess)
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Success:{nativeResultData.data}");
Debug.Log($"signature {nativeResultData.data}");
}
else
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Failed:{nativeResultData.data}");
var errorData = JsonConvert.DeserializeObject<NativeErrorData>(nativeResultData.data);
Debug.Log(errorData);
}
}
catch (Exception e)
{
Debug.LogError($"An error occurred: {e.Message}");
}
Show how to send transaction with particle-connect, gasless.
try
{
var eoaAddress = "0x498c9b8379E2e16953a7b1FF94ea11893d09A3Ed";
var smartAccountResult = await EvmService.GetSmartAccount(new[] { new SmartAccountObject(AAAccountName.BICONOMY_V1(), eoaAddress) });
var smartAccountAddress = (string)JObject.Parse(smartAccountResult)["result"][0]["smartAccountAddress"];
var transaction = await TransactionHelper.GetEVMTransactionWithConnect(smartAccountAddress);
// check if gasless available
var feeQuotesResult =
await ParticleAA.Instance.RpcGetFeeQuotes(eoaAddress, new List<string> { transaction });
var verifyingPaymasterGasless = JObject.Parse(feeQuotesResult.data)["verifyingPaymasterGasless"];
if (verifyingPaymasterGasless.Type == JTokenType.Null)
{
print("gasless is not available");
return;
}
// pass result from rpcGetFeeQuotes to send gasless
var nativeResultData =
await ParticleConnect.Instance.SignAndSendTransaction(WalletType.MetaMask, eoaAddress, transaction,
AAFeeMode.Gasless(JObject.Parse(feeQuotesResult.data)));
Debug.Log(nativeResultData.data);
if (nativeResultData.isSuccess)
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Success:{nativeResultData.data}");
Debug.Log($"signature {nativeResultData.data}");
}
else
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Failed:{nativeResultData.data}");
var errorData = JsonConvert.DeserializeObject<NativeErrorData>(nativeResultData.data);
Debug.Log(errorData);
}
}
catch (Exception e)
{
Debug.LogError($"An error occurred: {e.Message}");
}
Show how to send transaction with particle-connect, use token to pay gas fee.
try
{
var eoaAddress = "";
var smartAccountResult = await EvmService.GetSmartAccount(new[] { new SmartAccountObject(AAAccountName.BICONOMY_V1(), eoaAddress) });
var smartAccountAddress = (string)JObject.Parse(smartAccountResult)["result"][0]["smartAccountAddress"];
var transaction = await TransactionHelper.GetEVMTransactionWithConnect(smartAccountAddress);
// select a feeQuote
var feeQuotesResult =
await ParticleAA.Instance.RpcGetFeeQuotes(eoaAddress, new List<string> { transaction });
JArray feeQuotes = (JArray)(JObject.Parse(feeQuotesResult.data)["tokenPaymaster"]["feeQuotes"]);
var overFeeQuotes = feeQuotes
.Where(jt =>
{
var fee = BigInteger.Parse(jt["fee"].Value<string>());
var balance = BigInteger.Parse((string)jt["balance"].Value<string>());
return balance >= fee;
})
.ToList();
if (overFeeQuotes.Count == 0)
{
Debug.Log("no valid token fro gas fee");
return;
}
// select the first feeQuote
var feeQuote = overFeeQuotes[0];
var tokenPaymasterAddress =
JObject.Parse(feeQuotesResult.data)["tokenPaymaster"]["tokenPaymasterAddress"].Value<string>();
Debug.Log($"feeQuote {feeQuote}");
Debug.Log($"tokenPaymasterAddress {tokenPaymasterAddress}");
var nativeResultData =
await ParticleConnect.Instance.SignAndSendTransaction(WalletType.MetaMask, eoaAddress, transaction,
AAFeeMode.Token(feeQuote, tokenPaymasterAddress));
Debug.Log(nativeResultData.data);
if (nativeResultData.isSuccess)
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Success:{nativeResultData.data}");
Debug.Log($"signature {nativeResultData.data}");
}
else
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Failed:{nativeResultData.data}");
var errorData = JsonConvert.DeserializeObject<NativeErrorData>(nativeResultData.data);
Debug.Log(errorData);
}
}
catch (Exception e)
{
Debug.LogError($"An error occurred: {e.Message}");
}
If you are using ParticleAuth to send transaction, the difference is which to call signAndSendTransaction
method.
If you are uing ParticleAuthCore to send transaction, the difference is call evmSendTransaction method.
Rpc get fee quotes
Use with send transaction, fill parameter feeMode
.
try
{
var eoaAddress = ParticleAuthServiceInteraction.GetAddress();
// get your smart account by account name and version.
var smartAccountResult = await EvmService.GetSmartAccount(new[] { new SmartAccountObject(AAAccountName.BICONOMY_V1(), eoaAddress) });
var smartAccountAddress = (string)JObject.Parse(smartAccountResult)["result"][0]["smartAccountAddress"];
var transaction = await TransactionHelper.GetEVMTransacion(smartAccountAddress);
var nativeResultData =
await ParticleAA.Instance.RpcGetFeeQuotes(eoaAddress, new List<string> { transaction });
Debug.Log(nativeResultData.data);
if (nativeResultData.isSuccess)
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Success:{nativeResultData.data}");
Debug.Log(nativeResultData.data);
}
else
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Failed:{nativeResultData.data}");
var errorData = JsonConvert.DeserializeObject<NativeErrorData>(nativeResultData.data);
Debug.Log(errorData);
}
}
catch (Exception e)
{
Debug.LogError($"An error occurred: {e.Message}");
}
Batch send transactions
Merge multiple transactions and send them together
try
{
var eoaAddress = "0x498c9b8379E2e16953a7bEvmService1FF94ea11893d09A3Ed";
var smartAccountResult = await EvmService.GetSmartAccount(new[] { new SmartAccountObject(AAAccountName.BICONOMY_V1(), eoaAddress) });
var smartAccountAddress = (string)JObject.Parse(smartAccountResult)["result"][0]["smartAccountAddress"];
var transaction = await TransactionHelper.GetEVMTransactionWithConnect(smartAccountAddress);
// check if enough native for gas fee
var feeQuotesResult =
await ParticleAA.Instance.RpcGetFeeQuotes(eoaAddress, new List<string> { transaction });
var verifyingPaymasterNative = JObject.Parse(feeQuotesResult.data)["verifyingPaymasterNative"];
var feeQuote = verifyingPaymasterNative["feeQuote"];
var fee = BigInteger.Parse((string)feeQuote["fee"]);
var balance = BigInteger.Parse((string)feeQuote["balance"]);
if (balance < fee)
{
Debug.Log("native balance if not enough for gas fee");
return;
}
// pass result from rpcGetFeeQuotes to send pay with native
var nativeResultData =
await ParticleConnect.Instance.SignAndSendTransaction(WalletType.MetaMask, eoaAddress, transaction,
AAFeeMode.Native(JObject.Parse(feeQuotesResult.data)));
Debug.Log(nativeResultData.data);
if (nativeResultData.isSuccess)
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Success:{nativeResultData.data}");
Debug.Log($"signature {nativeResultData.data}");
}
else
{
ShowToast($"{MethodBase.GetCurrentMethod()?.Name} Failed:{nativeResultData.data}");
var errorData = JsonConvert.DeserializeObject<NativeErrorData>(nativeResultData.data);
Debug.Log(errorData);
}
}
catch (Exception e)
{
Debug.LogError($"An error occurred: {e.Message}");
}
If you are using ParticleAuth/ParticleAuthCore to send transaction, the difference is which to call batchSendTransactions
method.
Last updated