Skip to content

Commit

Permalink
EIP-7702 Integration
Browse files Browse the repository at this point in the history
Experimenting on Odyssey for now
  • Loading branch information
0xFirekeeper committed Dec 18, 2024
1 parent b0631e7 commit c63c348
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 4 deletions.
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
}

0 comments on commit c63c348

Please sign in to comment.