Using Smart Wallets
To use smart wallets, you could use the EIP1193 provider or use a backend. This guide teaches how to make different requests to the smart wallet with the backend and Unity (it's easier to do so in the context of gaming because no need to encode transactions with Unity).
Sign message
To sign message with the smart wallet simply call the Openfort's signMessage
or signTypedData
method like so:
SignMessageRequest signMessageRequest = new SignMessageRequest("Hello World!");
string signature = await openfort.embeddedWallet.signMessage(signMessageRequest);
Transactions
1. Create a transaction- Server side
Create a request to your backend to create a transaction. In the body of the request:
- Include the
player
that signs the transaction. - Include the
policy
that interacts with the contract for gas. If non-existent the user will need to have gas tokens. - Include
optimistic
if you want the transactions to be confirmed faster.
Depending on the type of transaction you're creating you'll define interactions
. The interactions
field is an array of objects that contain the information of the contract to interact with, the function to call, and the arguments to pass to the function.
- the interactions field contains the
contract
that has previously been added to Openfort. - the
functionName
defines the function to call from within the contract. - If there exist more than one function with the same name, the
functionArgs
will be used to determine which function to call.
curl https://api.openfort.io/v1/transaction_intents \
-H "Authorization: Bearer $YOUR_SECRET_KEY" \
-d player="pla_..." \
-d policy="pol_..." \
-d chainId=80002 \
-d optimistic=true \
-d "interactions[0][contract]"="con_..." \
-d "interactions[0][functionName]"="mint" \
-d "interactions[0][functionArgs][0]"="0x63B7...484f"
Native
Send the value of native tokens in the smallest denomination of the native currency i.e. wei (10^18) and as a string
.
curl https://api.openfort.io/v1/transaction_intents \
-H "Authorization: Bearer $YOUR_SECRET_KEY" \
-d player="pla_..." \
-d policy="pol_..." \
-d chainId=80002 \
-d optimistic=true \
-d "interactions[0][value]=1000" \
-d "interactions[0][to]=pla_..."
For a useful resource for computing the Wei, you can visit the wei calculator.
Batch
Smart accounts support batching transactions, allowing multiple actions to be rolled into one. This feature significantly simplifies Web3 interactions for your users. For example, instead of executing approve()
and then transfer()
, your user can perform both in a single transaction.
Batching transactions offers several key benefits:
- Users only wait for one transaction to complete instead of multiple.
- Users save on gas fees.
- If any transaction in the batch fails, the entire batch reverts, preventing users from ending up in an inconsistent state. This characteristic is known as "atomicity."
Fore security reasons, there is a limit of 9 interactions per transaction intent.
In the case that, in your contract, you have multiple functions with the same functionName
and number of arguments, you can also include the functionName
together with the argument types e.g. mint(address)
curl https://api.openfort.io/v1/transaction_intents \
-H "Authorization: Bearer $YOUR_SECRET_KEY" \
-d player="pla_...", \
-d policy="pol_..." \
-d chainId=80002 \
-d optimistic=true \
-d "interactions[0][contract]=con_..." \
-d "interactions[0][functionName]=mint" \
-d "interactions[0][functionArgs][0]=0x63B7...484f" \
-d "interactions[1][contract]=con_..." \
-d "interactions[1][functionName]=transfer" \
-d "interactions[1][functionArgs][0]=0x32B7...213d"
2. Sign the transaction. - Client side
Use the nextAction
returned by the backend to sign the transaction with the embedded wallet.
The transaction will be automatically signed and broadcasted by using the sendSignatureTransactionIntentRequest
method.
private async void Mint() {
// your backend that creates a mint request
var webRequest = UnityWebRequest.Post("https://your-backend.com/api/mint", "");
webRequest.SetRequestHeader("Authorization", "Bearer " + AccessToken);
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.SetRequestHeader("Accept", "application/json");
await SendWebRequestAsync(webRequest);
Debug.Log("Mint request sent");
if (webRequest.result != UnityWebRequest.Result.Success) {
Debug.Log("Mint Failed: " + webRequest.error);
return;
}
var responseText = webRequest.downloadHandler.text;
Debug.Log("Mint Response: " + responseText);
var responseJson = JsonConvert.DeserializeObject < RootObject > (responseText);
var id = responseJson.Data.Id;
if (responseJson.Data.NextAction == null) {
Debug.Log("No Next Action");
return;
}
var nextAction = responseJson.Data.NextAction.Payload.UserOpHash;
Debug.Log("Next Action: " + nextAction);
// This example assumes you have already checked that Openfort 'embeddedState' is
// `ready` and the user is `authenticated`
var intentResponse = await Openfort.SendSignatureTransactionIntentRequest(id, nextAction);
Debug.Log("Intent Response: " + intentResponse);
}
private Task SendWebRequestAsync(UnityWebRequest webRequest) {
TaskCompletionSource < bool > tcs = new TaskCompletionSource < bool > ();
webRequest.SendWebRequest().completed += _ => {
switch (webRequest.result) {
case UnityWebRequest.Result.Success:
tcs.SetResult(true);
break;
default:
tcs.SetException(new Exception(webRequest.error));
break;
}
};
return tcs.Task;
}
Examples
Unity Sample Android
An integration with Google Play Games using Firebase Auth as a third party auth provider to create a non-custodial embedded wallet.
Unity Sample WebGL
An integration with Openfort Auth with non-custodial embedded wallet.