Skip to content

Commit 91cec7c

Browse files
authored
Thirdweb Engine Relayer Integration (#177)
+ Contract.Write Improvements
1 parent bf98f94 commit 91cec7c

File tree

6 files changed

+43546
-42777
lines changed

6 files changed

+43546
-42777
lines changed

Assets/Thirdweb/Core/Scripts/Contract.cs

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -204,44 +204,21 @@ public async Task<TransactionResult> Write(string functionName, TransactionReque
204204
if (this.ABI == null)
205205
this.ABI = await FetchAbi(this.Address, await ThirdwebManager.Instance.SDK.Wallet.GetChainId());
206206

207-
var contract = ThirdwebManager.Instance.SDK.Session.Web3.Eth.GetContract(this.ABI, this.Address);
208-
209-
var function = contract.GetFunction(functionName);
210-
211-
var value = transactionOverrides?.value != null ? new HexBigInteger(BigInteger.Parse(transactionOverrides?.value)) : new HexBigInteger(0);
212-
213-
var gas =
214-
transactionOverrides?.gasLimit != null
215-
? new HexBigInteger(BigInteger.Parse(transactionOverrides?.gasLimit))
216-
: await function.EstimateGasAsync(await ThirdwebManager.Instance.SDK.Wallet.GetAddress(), null, value, args);
217-
218-
var gasPrice = transactionOverrides?.gasPrice != null ? new HexBigInteger(BigInteger.Parse(transactionOverrides?.gasPrice)) : null;
219-
220-
string hash;
221-
if (gasPrice == null)
207+
var service = new Nethereum.Contracts.Contract(null, this.ABI, this.Address);
208+
var function = service.GetFunction(functionName);
209+
var data = function.GetData(args);
210+
var input = new TransactionInput
222211
{
223-
var gasFees = await Utils.GetGasPriceAsync(await ThirdwebManager.Instance.SDK.Wallet.GetChainId());
224-
hash = await function.SendTransactionAsync(
225-
from: transactionOverrides?.from ?? await ThirdwebManager.Instance.SDK.Wallet.GetAddress(),
226-
gas: gas,
227-
value: value,
228-
maxFeePerGas: new HexBigInteger(gasFees.MaxFeePerGas),
229-
maxPriorityFeePerGas: new HexBigInteger(gasFees.MaxPriorityFeePerGas),
230-
args
231-
);
232-
}
233-
else
234-
{
235-
hash = await function.SendTransactionAsync(
236-
from: transactionOverrides?.from ?? await ThirdwebManager.Instance.SDK.Wallet.GetAddress(),
237-
gas: gas,
238-
gasPrice: gasPrice,
239-
value: value,
240-
args
241-
);
242-
}
243-
244-
return await Transaction.WaitForTransactionResult(hash);
212+
From = transactionOverrides?.from ?? await ThirdwebManager.Instance.SDK.Wallet.GetAddress(),
213+
To = this.Address,
214+
Data = data,
215+
Value = transactionOverrides?.value != null ? new HexBigInteger(BigInteger.Parse(transactionOverrides?.value)) : new HexBigInteger(0),
216+
Gas = transactionOverrides?.gasLimit != null ? new HexBigInteger(BigInteger.Parse(transactionOverrides?.gasLimit)) : null,
217+
GasPrice = transactionOverrides?.gasPrice != null ? new HexBigInteger(BigInteger.Parse(transactionOverrides?.gasPrice)) : null,
218+
};
219+
220+
var tx = new Transaction(input);
221+
return await tx.SendAndWaitForTransactionResult();
245222
}
246223
}
247224

Assets/Thirdweb/Core/Scripts/ThirdwebManager.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ public class ThirdwebManager : MonoBehaviour
5757
[Tooltip("IPFS Gateway Override")]
5858
public string storageIpfsGatewayUrl = null;
5959

60-
[Tooltip("Autotask URL")]
60+
[Tooltip("Find out more about relayers here https://portal.thirdweb.com/engine/features/relayers")]
6161
public string relayerUrl = null;
6262

63-
[Tooltip("Forwarders can be found here https://github.com/thirdweb-dev/ozdefender-autotask")]
63+
[Tooltip("Forwarder Contract Address (Defaults to 0xD04F98C88cE1054c90022EE34d566B9237a1203C if left empty)")]
6464
public string forwarderAddress = null;
6565

6666
[Tooltip("Forwarder Domain Override (Defaults to GSNv2 Forwarder if left empty)")]
@@ -206,14 +206,14 @@ public void Initialize(string chainIdentifier)
206206
{
207207
options.storage = new ThirdwebSDK.StorageOptions() { ipfsGatewayUrl = storageIpfsGatewayUrl };
208208
}
209-
if (!string.IsNullOrEmpty(relayerUrl) && !string.IsNullOrEmpty(forwarderAddress))
209+
if (!string.IsNullOrEmpty(relayerUrl))
210210
{
211-
options.gasless = new ThirdwebSDK.GaslessOptions()
211+
options.gasless = new ThirdwebSDK.RelayerOptions()
212212
{
213-
openzeppelin = new ThirdwebSDK.OZDefenderOptions()
213+
engine = new ThirdwebSDK.EngineRelayerOptions()
214214
{
215215
relayerUrl = this.relayerUrl,
216-
relayerForwarderAddress = this.forwarderAddress,
216+
relayerForwarderAddress = string.IsNullOrEmpty(this.forwarderAddress) ? "0xD04F98C88cE1054c90022EE34d566B9237a1203C" : this.forwarderAddress,
217217
domainName = string.IsNullOrEmpty(this.forwarderDomainOverride) ? "GSNv2 Forwarder" : this.forwarderDomainOverride,
218218
domainVersion = string.IsNullOrEmpty(this.forwaderVersionOverride) ? "0.0.1" : this.forwaderVersionOverride
219219
}

Assets/Thirdweb/Core/Scripts/ThirdwebSDK.cs

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public class ThirdwebSDK
1717
public struct Options
1818
{
1919
/// <summary>
20-
/// Gasless configuration options for the Thirdweb SDK.
20+
/// Gasless relayer configuration options for Thirdweb Engine..
2121
/// </summary>
22-
public GaslessOptions? gasless;
22+
public RelayerOptions? gasless;
2323

2424
/// <summary>
2525
/// Storage configuration options for the Thirdweb SDK.
@@ -204,33 +204,16 @@ public struct StorageOptions
204204
}
205205

206206
/// <summary>
207-
/// Gasless configuration options.
207+
/// Thirdweb Engine Relayer configuration options.
208208
/// </summary>
209209
[System.Serializable]
210-
public struct GaslessOptions
210+
public struct RelayerOptions
211211
{
212-
/// <summary>
213-
/// OpenZeppelin Defender Gasless configuration options.
214-
/// </summary>
215-
public OZDefenderOptions? openzeppelin;
216-
217-
/// <summary>
218-
/// [Obsolete] Biconomy Gasless configuration options. Biconomy is not fully supported and will be removed soon. Use OpenZeppelin Defender instead.
219-
/// </summary>
220-
[System.Obsolete("Biconomy is not fully supported and will be removed soon. Use OpenZeppelin Defender instead.")]
221-
public BiconomyOptions? biconomy;
222-
223-
/// <summary>
224-
/// Indicates whether experimental chainless support is enabled.
225-
/// </summary>
226-
public bool experimentalChainlessSupport;
212+
public EngineRelayerOptions engine;
227213
}
228214

229-
/// <summary>
230-
/// OpenZeppelin Defender Gasless configuration options.
231-
/// </summary>
232215
[System.Serializable]
233-
public struct OZDefenderOptions
216+
public struct EngineRelayerOptions
234217
{
235218
/// <summary>
236219
/// The URL of the relayer service.
@@ -253,23 +236,6 @@ public struct OZDefenderOptions
253236
public string domainVersion;
254237
}
255238

256-
/// <summary>
257-
/// Biconomy Gasless configuration options.
258-
/// </summary>
259-
[System.Serializable]
260-
public struct BiconomyOptions
261-
{
262-
/// <summary>
263-
/// The API ID for Biconomy.
264-
/// </summary>
265-
public string apiId;
266-
267-
/// <summary>
268-
/// The API key for Biconomy.
269-
/// </summary>
270-
public string apiKey;
271-
}
272-
273239
private readonly string chainOrRPC;
274240

275241
/// <summary>

Assets/Thirdweb/Core/Scripts/Transaction.cs

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Nethereum.Contracts;
1212
using Nethereum.ABI.FunctionEncoding;
1313
using System;
14+
using Newtonsoft.Json.Linq;
1415

1516
#pragma warning disable CS0618
1617

@@ -341,9 +342,9 @@ public async Task<string> Send(bool? gasless = null)
341342
await EstimateAndSetGasLimitAsync();
342343
if (Input.Value == null)
343344
Input.Value = new HexBigInteger(0);
344-
bool isGaslessSetup = ThirdwebManager.Instance.SDK.Session.Options.gasless.HasValue && ThirdwebManager.Instance.SDK.Session.Options.gasless.Value.openzeppelin.HasValue;
345+
bool isGaslessSetup = ThirdwebManager.Instance.SDK.Session.Options.gasless.HasValue && !string.IsNullOrEmpty(ThirdwebManager.Instance.SDK.Session.Options.gasless?.engine.relayerUrl);
345346
if (gasless != null && gasless.Value && !isGaslessSetup)
346-
throw new UnityException("Gasless transactions are not enabled. Please enable them in the SDK options.");
347+
throw new UnityException("Gasless relayer transactions are not enabled. Please enable them in the SDK options.");
347348
bool sendGaslessly = gasless == null ? isGaslessSetup : gasless.Value;
348349
if (sendGaslessly)
349350
return await SendGasless();
@@ -484,10 +485,10 @@ private async Task<string> SendGasless()
484485
}
485486
else
486487
{
487-
string relayerUrl = ThirdwebManager.Instance.SDK.Session.Options.gasless.Value.openzeppelin?.relayerUrl;
488-
string forwarderAddress = ThirdwebManager.Instance.SDK.Session.Options.gasless.Value.openzeppelin?.relayerForwarderAddress;
489-
string forwarderDomain = ThirdwebManager.Instance.SDK.Session.Options.gasless.Value.openzeppelin?.domainName;
490-
string forwarderVersion = ThirdwebManager.Instance.SDK.Session.Options.gasless.Value.openzeppelin?.domainVersion;
488+
string relayerUrl = ThirdwebManager.Instance.SDK.Session.Options.gasless?.engine.relayerUrl ?? throw new UnityException("Relayer URL not set in SDK options.");
489+
string forwarderAddress = ThirdwebManager.Instance.SDK.Session.Options.gasless?.engine.relayerForwarderAddress ?? "0xD04F98C88cE1054c90022EE34d566B9237a1203C";
490+
string forwarderDomain = ThirdwebManager.Instance.SDK.Session.Options.gasless?.engine.domainName ?? "GSNv2 Forwarder";
491+
string forwarderVersion = ThirdwebManager.Instance.SDK.Session.Options.gasless?.engine.domainVersion ?? "0.0.1";
491492

492493
Input.Nonce = (
493494
await TransactionManager.ThirdwebRead<MinimalForwarder.GetNonceFunction, MinimalForwarder.GetNonceOutputDTO>(
@@ -506,6 +507,8 @@ private async Task<string> SendGasless()
506507
Data = Input.Data
507508
};
508509

510+
ThirdwebDebug.Log($"Forwarding request: {JsonConvert.SerializeObject(request)}");
511+
509512
var signature = await EIP712.GenerateSignature_MinimalForwarder(
510513
forwarderDomain,
511514
forwarderVersion,
@@ -514,7 +517,13 @@ private async Task<string> SendGasless()
514517
request
515518
);
516519

517-
var postData = new RelayerRequest(request, signature, forwarderAddress);
520+
var postData = new RelayerRequest()
521+
{
522+
Type = "forward",
523+
Request = request,
524+
Signature = signature,
525+
ForwarderAddress = forwarderAddress,
526+
};
518527

519528
using UnityWebRequest req = UnityWebRequest.Post(relayerUrl, "");
520529
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(postData));
@@ -530,17 +539,32 @@ private async Task<string> SendGasless()
530539
}
531540
else
532541
{
533-
var response = JsonConvert.DeserializeObject<RelayerResponse>(req.downloadHandler.text);
534-
if (response.status != "success")
535-
{
536-
throw new UnityException(
537-
$"Forward Request Failed!\nError: {req.downloadHandler.text}\nRelayer URL: {relayerUrl}\nRelayer Forwarder Address: {forwarderAddress}\nRequest: {request}\nSignature: {signature}\nPost Data: {postData}"
538-
);
539-
}
540-
var result = JsonConvert.DeserializeObject<RelayerResult>(response.result);
541-
return result.txHash;
542+
var queueId = JsonConvert.DeserializeObject<JObject>(req.downloadHandler.text)["result"]["queueId"].ToString();
543+
ThirdwebDebug.Log($"Forwarded request to relayer with queue ID: {queueId}");
544+
return await FetchTxHashFromQueueId(new Uri(relayerUrl).GetLeftPart(UriPartial.Authority), queueId);
545+
}
546+
}
547+
}
548+
549+
private async Task<string> FetchTxHashFromQueueId(string engineUrl, string queueId)
550+
{
551+
string txHash = null;
552+
while (string.IsNullOrEmpty(txHash) && Application.isPlaying)
553+
{
554+
using UnityWebRequest req = UnityWebRequest.Get($"{engineUrl}/transaction/status/{queueId}");
555+
await new WaitForSeconds(1f);
556+
await req.SendWebRequest();
557+
if (req.result != UnityWebRequest.Result.Success)
558+
{
559+
throw new UnityException($"Failed to fetch transaction hash from queue ID {queueId}.\nError: {req.downloadHandler.text}");
560+
}
561+
else
562+
{
563+
txHash = JsonConvert.DeserializeObject<JObject>(req.downloadHandler.text)["result"]["transactionHash"].ToString();
542564
}
543565
}
566+
ThirdwebDebug.Log($"Transaction hash fetched from queue ID {queueId}: {txHash}");
567+
return txHash;
544568
}
545569

546570
private string GetTxBuilderRoute(string action)
@@ -550,44 +574,19 @@ private string GetTxBuilderRoute(string action)
550574
}
551575
}
552576

553-
[System.Serializable]
554-
public struct RelayerResponse
555-
{
556-
[JsonProperty("status")]
557-
public string status;
558-
559-
[JsonProperty("result")]
560-
public string result;
561-
}
562-
563-
[System.Serializable]
564-
public struct RelayerResult
565-
{
566-
[JsonProperty("txHash")]
567-
public string txHash;
568-
}
569-
570577
[System.Serializable]
571578
public struct RelayerRequest
572579
{
580+
[JsonProperty("type")]
581+
public string Type;
582+
573583
[JsonProperty("request")]
574-
public MinimalForwarder.ForwardRequest request;
584+
public MinimalForwarder.ForwardRequest Request;
575585

576586
[JsonProperty("signature")]
577-
public string signature;
587+
public string Signature;
578588

579589
[JsonProperty("forwarderAddress")]
580-
public string forwarderAddress;
581-
582-
[JsonProperty("type")]
583-
public string type;
584-
585-
public RelayerRequest(MinimalForwarder.ForwardRequest request, string signature, string forwarderAddress)
586-
{
587-
this.request = request;
588-
this.signature = signature;
589-
this.forwarderAddress = forwarderAddress;
590-
this.type = "forward";
591-
}
590+
public string ForwarderAddress;
592591
}
593592
}

Assets/Thirdweb/Editor/ThirdwebManagerEditor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,12 @@ public override void OnInspectorGUI()
263263

264264
// OZ Defender Options
265265
sectionExpanded[3] = DrawSectionWithExpand(
266-
"OpenZeppelin Defender Options",
266+
"Gasless Relayer Options",
267267
sectionExpanded[3],
268268
() =>
269269
{
270270
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
271271
EditorGUILayout.PropertyField(relayerUrlProperty);
272-
EditorGUILayout.PropertyField(forwarderAddressProperty);
273272

274273
EditorGUI.BeginChangeCheck();
275274
showGaslessOptionalFields = EditorGUILayout.ToggleLeft("Show Optional Fields", showGaslessOptionalFields);
@@ -280,6 +279,7 @@ public override void OnInspectorGUI()
280279

281280
if (showGaslessOptionalFields)
282281
{
282+
EditorGUILayout.PropertyField(forwarderAddressProperty);
283283
EditorGUILayout.PropertyField(forwarderDomainOverrideProperty);
284284
EditorGUILayout.PropertyField(forwaderVersionOverrideProperty);
285285
}

0 commit comments

Comments
 (0)