| 
1 | 1 | using System.Numerics;  | 
2 | 2 | using Nethereum.ABI.EIP712;  | 
3 | 3 | using Nethereum.Hex.HexConvertors.Extensions;  | 
 | 4 | +using Nethereum.Model;  | 
4 | 5 | using Nethereum.RLP;  | 
5 | 6 | using Nethereum.Signer;  | 
 | 7 | +using Nethereum.Signer.Crypto;  | 
6 | 8 | using Nethereum.Signer.EIP712;  | 
 | 9 | +using Nethereum.Util;  | 
7 | 10 | using Newtonsoft.Json;  | 
8 | 11 | 
 
  | 
9 | 12 | namespace Thirdweb  | 
@@ -46,29 +49,15 @@ IThirdwebWallet signer  | 
46 | 49 |         )  | 
47 | 50 |         {  | 
48 | 51 |             var typedData = GetTypedDefinition_ZkSyncTransaction(domainName, version, chainId, transaction.From);  | 
49 |  | -            return await signer.SignTypedDataV4(transaction, typedData);  | 
50 |  | -        }  | 
51 |  | - | 
52 |  | -        // private static EthECDSASignature ParseSignature(string signatureHex)  | 
53 |  | -        // {  | 
54 |  | -        //     var signatureBytes = signatureHex.HexToByteArray();  | 
55 |  | -        //     if (signatureBytes.Length != 65)  | 
56 |  | -        //     {  | 
57 |  | -        //         throw new ArgumentException("Invalid signature length.");  | 
58 |  | -        //     }  | 
59 |  | - | 
60 |  | -        //     var r = new byte[32];  | 
61 |  | -        //     var s = new byte[32];  | 
62 |  | -        //     var v = new byte[1];  | 
63 |  | - | 
64 |  | -        //     Array.Copy(signatureBytes, 0, r, 0, 32);  | 
65 |  | -        //     Array.Copy(signatureBytes, 32, s, 0, 32);  | 
66 |  | -        //     Array.Copy(signatureBytes, 64, v, 0, 1);  | 
67 | 52 | 
 
  | 
68 |  | -        //     var vValue = (v[0] == 0 || v[0] == 1) ? v[0] + 27 : v[0]; // Adjust v value if necessary  | 
69 |  | - | 
70 |  | -        //     return new EthECDSASignature(new Org.BouncyCastle.Math.BigInteger(r), new Org.BouncyCastle.Math.BigInteger(s), vValue.ToBytesForRLPEncoding());  | 
71 |  | -        // }  | 
 | 53 | +            var typedDataSigner = new Eip712TypedDataSigner();  | 
 | 54 | +            var encodedTypedData = typedDataSigner.EncodeTypedData(transaction, typedData);  | 
 | 55 | +            var hash = new Sha3Keccack().CalculateHash(encodedTypedData);  | 
 | 56 | +            var signatureHex = await signer.EthSign(hash);  | 
 | 57 | +            var signatureRaw = ECDSASignatureFactory.ExtractECDSASignature(signatureHex);  | 
 | 58 | +            var serializedTx = SerializeEip712(transaction, signatureRaw, signatureHex, chainId);  | 
 | 59 | +            return serializedTx;  | 
 | 60 | +        }  | 
72 | 61 | 
 
  | 
73 | 62 |         public static TypedData<Domain> GetTypedDefinition_SmartAccount(string domainName, string version, BigInteger chainId, string verifyingContract)  | 
74 | 63 |         {  | 
@@ -118,61 +107,39 @@ public static TypedData<Domain> GetTypedDefinition_ZkSyncTransaction(string doma  | 
118 | 107 |             };  | 
119 | 108 |         }  | 
120 | 109 | 
 
  | 
121 |  | -        // private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction transaction, EthECDSASignature signature, BigInteger chainId)  | 
122 |  | -        // {  | 
123 |  | -        //     if (transaction.From == null)  | 
124 |  | -        //     {  | 
125 |  | -        //         throw new ArgumentException("Explicitly providing `from` field is required for EIP712 transactions!");  | 
126 |  | -        //     }  | 
127 |  | - | 
128 |  | -        //     var fields = new List<byte[]>  | 
129 |  | -        //     {  | 
130 |  | -        //         RLP.EncodeElement(transaction.Nonce.ToByteArray()),  | 
131 |  | -        //         RLP.EncodeElement(transaction.MaxPriorityFeePerGas.ToByteArray()),  | 
132 |  | -        //         RLP.EncodeElement(transaction.MaxFeePerGas.ToByteArray()),  | 
133 |  | -        //         RLP.EncodeElement(transaction.GasLimit.ToByteArray()),  | 
134 |  | -        //         RLP.EncodeElement(transaction.To.HexToByteArray()),  | 
135 |  | -        //         RLP.EncodeElement(transaction.Value.ToByteArray()),  | 
136 |  | -        //         RLP.EncodeElement(transaction.Data)  | 
137 |  | -        //     };  | 
138 |  | - | 
139 |  | -        //     if (signature != null)  | 
140 |  | -        //     {  | 
141 |  | -        //         fields.Add(RLP.EncodeElement(signature.V));  | 
142 |  | -        //         fields.Add(RLP.EncodeElement(signature.R));  | 
143 |  | -        //         fields.Add(RLP.EncodeElement(signature.S));  | 
144 |  | -        //     }  | 
145 |  | -        //     else  | 
146 |  | -        //     {  | 
147 |  | -        //         fields.Add(RLP.EncodeElement(chainId.ToByteArray()));  | 
148 |  | -        //         fields.Add(RLP.EncodeElement(Array.Empty<byte>()));  | 
149 |  | -        //         fields.Add(RLP.EncodeElement(Array.Empty<byte>()));  | 
150 |  | -        //     }  | 
151 |  | - | 
152 |  | -        //     fields.Add(RLP.EncodeElement(chainId.ToByteArray()));  | 
153 |  | -        //     fields.Add(RLP.EncodeElement(transaction.From.HexToByteArray()));  | 
154 |  | - | 
155 |  | -        //     // Add meta  | 
156 |  | -        //     fields.Add(RLP.EncodeElement(transaction.GasPerPubdataByteLimit.ToByteArray()));  | 
157 |  | -        //     fields.Add(RLP.EncodeList(Array.Empty<byte[]>()));  | 
158 |  | - | 
159 |  | -        //     if (transaction.PaymasterInput.Length == 0)  | 
160 |  | -        //     {  | 
161 |  | -        //         throw new ArgumentException("Empty signatures are not supported!");  | 
162 |  | -        //     }  | 
163 |  | -        //     fields.Add(RLP.EncodeElement(transaction.PaymasterInput));  | 
164 |  | - | 
165 |  | -        //     if (transaction.Paymaster != null)  | 
166 |  | -        //     {  | 
167 |  | -        //         fields.Add(RLP.EncodeList(new byte[][] { RLP.EncodeElement(transaction.Paymaster.HexToByteArray()), RLP.EncodeElement(transaction.PaymasterInput) }));  | 
168 |  | -        //     }  | 
169 |  | -        //     else  | 
170 |  | -        //     {  | 
171 |  | -        //         fields.Add(RLP.EncodeList(Array.Empty<byte[]>()));  | 
172 |  | -        //     }  | 
 | 110 | +        private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction transaction, ECDSASignature signature, string signatureHex, BigInteger chainId)  | 
 | 111 | +        {  | 
 | 112 | +            if (chainId == 0)  | 
 | 113 | +            {  | 
 | 114 | +                throw new ArgumentException("Chain ID must be provided for EIP712 transactions!");  | 
 | 115 | +            }  | 
173 | 116 | 
 
  | 
174 |  | -        //     var rlpEncoded = RLP.EncodeList(fields.ToArray());  | 
175 |  | -        //     return "0x" + BitConverter.ToString(rlpEncoded).Replace("-", "");  | 
176 |  | -        // }  | 
 | 117 | +            if (string.IsNullOrEmpty(transaction.From))  | 
 | 118 | +            {  | 
 | 119 | +                throw new ArgumentException("From address must be provided for EIP712 transactions!");  | 
 | 120 | +            }  | 
 | 121 | + | 
 | 122 | +            return "0x71"  | 
 | 123 | +                + RLP.EncodeList(  | 
 | 124 | +                        transaction.Nonce.ToBytesForRLPEncoding(),  | 
 | 125 | +                        transaction.MaxPriorityFeePerGas.ToBytesForRLPEncoding(),  | 
 | 126 | +                        transaction.MaxFeePerGas.ToBytesForRLPEncoding(),  | 
 | 127 | +                        transaction.GasLimit.ToBytesForRLPEncoding(),  | 
 | 128 | +                        transaction.To.ToBytesForRLPEncoding(),  | 
 | 129 | +                        transaction.Value.ToBytesForRLPEncoding(),  | 
 | 130 | +                        transaction.Data.ToHex().ToBytesForRLPEncoding(),  | 
 | 131 | +                        signature.V.ToHex().ToBytesForRLPEncoding(),  | 
 | 132 | +                        signature.R.ToByteArray().ToHex().ToBytesForRLPEncoding(),  | 
 | 133 | +                        signature.S.ToByteArray().ToHex().ToBytesForRLPEncoding(),  | 
 | 134 | +                        chainId.ToBytesForRLPEncoding(),  | 
 | 135 | +                        transaction.From.ToBytesForRLPEncoding(),  | 
 | 136 | +                        transaction.GasPerPubdataByteLimit.ToBytesForRLPEncoding(),  | 
 | 137 | +                        transaction.FactoryDeps.ToHex().ToBytesForRLPEncoding() ?? Array.Empty<byte>().ToHex().ToBytesForRLPEncoding(),  | 
 | 138 | +                        signatureHex.ToBytesForRLPEncoding(),  | 
 | 139 | +                        transaction.Paymaster.ToBytesForRLPEncoding(),  | 
 | 140 | +                        transaction.PaymasterInput.ToHex().ToBytesForRLPEncoding()  | 
 | 141 | +                    )  | 
 | 142 | +                    .ToHex();  | 
 | 143 | +        }  | 
177 | 144 |     }  | 
178 | 145 | }  | 
0 commit comments