Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,33 @@ public static async Task<string> Send(ThirdwebTransaction transaction)

var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value);
string hash;
if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false) && transaction.Input.ZkSync.HasValue)

if (transaction.Input.AuthorizationList != null)
{
var authorization = transaction.Input.AuthorizationList[0];
hash = await rpc.SendRequestAsync<string>(
"wallet_sendTransaction",
new
{
authorizationList = new[]
{
new
{
address = authorization.Address,
chainId = authorization.ChainId.HexToBigInt(),
nonce = authorization.Nonce.HexToBigInt(),
r = authorization.R,
s = authorization.S,
yParity = authorization.YParity == "0x00" ? 0 : 1
}
},
data = transaction.Input.Data,
to = transaction.Input.To,
}
)
.ConfigureAwait(false);
}
else if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false) && transaction.Input.ZkSync.HasValue)
{
var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false);
var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet).ConfigureAwait(false);
Expand Down
40 changes: 39 additions & 1 deletion Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public ThirdwebTransactionInput(
string data = null,
BigInteger? maxFeePerGas = null,
BigInteger? maxPriorityFeePerGas = null,
ZkSyncOptions? zkSync = null
ZkSyncOptions? zkSync = null,
EIP7702Authorization? authorization = null
)
{
this.ChainId = chainId > 0 ? new HexBigInteger(chainId) : throw new ArgumentException("Invalid Chain ID");
Expand All @@ -40,6 +41,7 @@ public ThirdwebTransactionInput(
this.MaxFeePerGas = maxFeePerGas == null ? null : new HexBigInteger(maxFeePerGas.Value);
this.MaxPriorityFeePerGas = maxPriorityFeePerGas == null ? null : new HexBigInteger(maxPriorityFeePerGas.Value);
this.ZkSync = zkSync;
this.AuthorizationList = authorization == null ? null : new List<EIP7702Authorization> { authorization.Value };
}

/// <summary>
Expand Down Expand Up @@ -123,6 +125,11 @@ public string Data
/// </summary>
[JsonProperty(PropertyName = "zkSyncOptions", NullValueHandling = NullValueHandling.Ignore)]
public ZkSyncOptions? ZkSync { get; set; }

#nullable enable
[JsonProperty(PropertyName = "authorizationList", NullValueHandling = NullValueHandling.Ignore)]
public List<EIP7702Authorization>? AuthorizationList { get; set; }
#nullable disable
}

/// <summary>
Expand Down Expand Up @@ -179,3 +186,34 @@ public ZkSyncOptions(string paymaster = null, string paymasterInput = null, BigI
}
}
}

public struct EIP7702Authorization
{
[JsonProperty(PropertyName = "chainId")]
public string ChainId { get; set; }

[JsonProperty(PropertyName = "address")]
public string Address { get; set; }

[JsonProperty(PropertyName = "nonce")]
public string Nonce { get; set; }

[JsonProperty(PropertyName = "yParity")]
public string YParity { get; set; }

[JsonProperty(PropertyName = "r")]
public string R { get; set; }

[JsonProperty(PropertyName = "s")]
public string S { get; set; }

public EIP7702Authorization(BigInteger chainId, string address, BigInteger nonce, byte[] yParity, byte[] r, byte[] s)
{
this.ChainId = new HexBigInteger(chainId).HexValue;
this.Address = address.EnsureHexPrefix();
this.Nonce = new HexBigInteger(nonce).HexValue;
this.YParity = yParity.BytesToHex();
this.R = r.BytesToHex();
this.S = s.BytesToHex();
}
}
13 changes: 11 additions & 2 deletions Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Nethereum.ABI.EIP712;
using System.Numerics;
using Nethereum.ABI.EIP712;
using Newtonsoft.Json;

namespace Thirdweb;
Expand Down Expand Up @@ -150,7 +151,7 @@ Task<List<LinkedAccount>> LinkAccount(
Action<string> browserOpenAction = null,
string mobileRedirectScheme = "thirdweb://",
IThirdwebBrowser browser = null,
System.Numerics.BigInteger? chainId = null,
BigInteger? chainId = null,
string jwt = null,
string payload = null
);
Expand All @@ -166,6 +167,14 @@ Task<List<LinkedAccount>> LinkAccount(
/// </summary>
/// <returns>A list of <see cref="LinkedAccount"/> objects.</returns>
Task<List<LinkedAccount>> GetLinkedAccounts();

/// <summary>
/// Signs an EIP-7702 authorization to invoke contract functions to an externally owned account.
/// </summary>
/// <param name="chainId">The chain ID of the contract.</param>
/// <param name="contractAddress">The address of the contract.</param>
/// <returns>The signed authorization as an <see cref="EIP7702Authorization"/> that can be used with <see cref="ThirdwebTransactionInput.AuthorizationList"/>.</returns>
Task<EIP7702Authorization> SignAuthorization(BigInteger chainId, string contractAddress);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -931,5 +931,10 @@ public virtual Task<string> RecoverAddressFromTypedDataV4<T, TDomain>(T data, Ty
return Task.FromResult(address);
}

public Task<EIP7702Authorization> SignAuthorization(BigInteger chainId, string contractAddress)
{
throw new NotImplementedException();
}

#endregion
}
12 changes: 12 additions & 0 deletions Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Nethereum.Hex.HexConvertors.Extensions;
using Nethereum.Hex.HexTypes;
using Nethereum.Model;
using Nethereum.RLP;
using Nethereum.Signer;
using Nethereum.Signer.EIP712;

Expand Down Expand Up @@ -385,5 +386,16 @@ public Task<List<LinkedAccount>> UnlinkAccount(LinkedAccount accountToUnlink)
throw new InvalidOperationException("UnlinkAccount is not supported for private key wallets.");
}

public async Task<EIP7702Authorization> SignAuthorization(BigInteger chainId, string contractAddress)
{
var nonce = await this.GetTransactionCount(chainId);
var authorizationHash = Utils.HashMessage(
Utils.HexConcat("0x05", RLP.EncodeList(new HexBigInteger(chainId).HexValue.HexToBytes(), contractAddress.HexToBytes(), new HexBigInteger(nonce).HexValue.HexToBytes()).BytesToHex()[2..])
);
var authorizationSignature = await this.PersonalSign(authorizationHash);
var ecdsa = EthECDSASignatureFactory.ExtractECDSASignature(authorizationSignature);
return new EIP7702Authorization(chainId, contractAddress, nonce, ecdsa.V, ecdsa.R, ecdsa.S);
}

#endregion
}
5 changes: 5 additions & 0 deletions Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,5 +1225,10 @@ public async Task<List<LinkedAccount>> GetLinkedAccounts()
}
}

public Task<EIP7702Authorization> SignAuthorization(BigInteger chainId, string contractAddress)
{
return this._personalAccount.SignAuthorization(chainId, contractAddress);
}

#endregion
}
Loading