1
1
using System . Numerics ;
2
2
using Nethereum . ABI . EIP712 ;
3
3
using Nethereum . Hex . HexConvertors . Extensions ;
4
+ using Nethereum . Hex . HexTypes ;
4
5
using Nethereum . Model ;
5
6
using Nethereum . RLP ;
6
7
using Nethereum . Signer ;
@@ -48,14 +49,15 @@ public static async Task<string> GenerateSignature_ZkSyncTransaction(
48
49
IThirdwebWallet signer
49
50
)
50
51
{
51
- var typedData = GetTypedDefinition_ZkSyncTransaction ( domainName , version , chainId , transaction . From ) ;
52
-
53
- var typedDataSigner = new Eip712TypedDataSigner ( ) ;
54
- var encodedTypedData = typedDataSigner . EncodeTypedData ( transaction , typedData ) ;
55
- var hash = new Sha3Keccack ( ) . CalculateHash ( encodedTypedData ) ;
52
+ var typedData = GetTypedDefinition_ZkSyncTransaction ( domainName , version , chainId ) ;
53
+ var typedDataEncoder = new Eip712TypedDataEncoder ( ) ;
54
+ var hash = typedDataEncoder . EncodeAndHashTypedData ( transaction , typedData ) ;
55
+ Console . WriteLine ( $ "Hash: { hash . ToHex ( true ) } ") ;
56
56
var signatureHex = await signer . EthSign ( hash ) ;
57
- var signatureRaw = ECDSASignatureFactory . ExtractECDSASignature ( signatureHex ) ;
57
+ Console . WriteLine ( $ "Signature: { signatureHex } ") ;
58
+ var signatureRaw = EthECDSASignatureFactory . ExtractECDSASignature ( signatureHex ) ;
58
59
var serializedTx = SerializeEip712 ( transaction , signatureRaw , signatureHex , chainId ) ;
60
+ Console . WriteLine ( $ "Serialized: { serializedTx } ") ;
59
61
return serializedTx ;
60
62
}
61
63
@@ -91,23 +93,22 @@ public static TypedData<Domain> GetTypedDefinition_SmartAccount_AccountMessage(s
91
93
} ;
92
94
}
93
95
94
- public static TypedData < Domain > GetTypedDefinition_ZkSyncTransaction ( string domainName , string version , BigInteger chainId , string verifyingContract )
96
+ public static TypedData < DomainWithNameVersionAndChainId > GetTypedDefinition_ZkSyncTransaction ( string domainName , string version , BigInteger chainId )
95
97
{
96
- return new TypedData < Domain >
98
+ return new TypedData < DomainWithNameVersionAndChainId >
97
99
{
98
- Domain = new Domain
100
+ Domain = new DomainWithNameVersionAndChainId
99
101
{
100
102
Name = domainName ,
101
103
Version = version ,
102
104
ChainId = chainId ,
103
- VerifyingContract = verifyingContract
104
105
} ,
105
- Types = MemberDescriptionFactory . GetTypesMemberDescription ( typeof ( Domain ) , typeof ( AccountAbstraction . ZkSyncAATransaction ) ) ,
106
+ Types = MemberDescriptionFactory . GetTypesMemberDescription ( typeof ( DomainWithNameVersionAndChainId ) , typeof ( AccountAbstraction . ZkSyncAATransaction ) ) ,
106
107
PrimaryType = nameof ( AccountAbstraction . ZkSyncAATransaction ) ,
107
108
} ;
108
109
}
109
110
110
- private static string SerializeEip712 ( AccountAbstraction . ZkSyncAATransaction transaction , ECDSASignature signature , string signatureHex , BigInteger chainId )
111
+ private static string SerializeEip712 ( AccountAbstraction . ZkSyncAATransaction transaction , EthECDSASignature signature , string signatureHex , BigInteger chainId )
111
112
{
112
113
if ( chainId == 0 )
113
114
{
@@ -119,27 +120,53 @@ private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction tra
119
120
throw new ArgumentException ( "From address must be provided for EIP712 transactions!" ) ;
120
121
}
121
122
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 ( ) ;
123
+ var fields = new List < byte [ ] >
124
+ {
125
+ transaction . Nonce . ToByteArray ( isUnsigned : true , isBigEndian : true ) ,
126
+ transaction . MaxPriorityFeePerGas . ToByteArray ( isUnsigned : true , isBigEndian : true ) ,
127
+ transaction . MaxFeePerGas . ToByteArray ( isUnsigned : true , isBigEndian : true ) ,
128
+ transaction . GasLimit . ToByteArray ( isUnsigned : true , isBigEndian : true ) ,
129
+ transaction . To . HexToByteArray ( ) ,
130
+ transaction . Value == 0 ? new byte [ 0 ] : transaction . Value . ToByteArray ( isUnsigned : true , isBigEndian : true ) ,
131
+ transaction . Data == null ? new byte [ 0 ] : transaction . Data ,
132
+ } ;
133
+
134
+ if ( signature != null )
135
+ {
136
+ fields . Add ( new BigInteger ( signature . V ) . ToByteArray ( isUnsigned : false , isBigEndian : true ) ) ;
137
+ fields . Add ( new BigInteger ( signature . R ) . ToByteArray ( isUnsigned : false , isBigEndian : true ) ) ;
138
+ fields . Add ( new BigInteger ( signature . S ) . ToByteArray ( isUnsigned : false , isBigEndian : true ) ) ;
139
+ }
140
+ else
141
+ {
142
+ fields . Add ( chainId . ToByteArray ( isUnsigned : true , isBigEndian : true ) ) ;
143
+ fields . Add ( new byte [ 0 ] ) ;
144
+ fields . Add ( new byte [ 0 ] ) ;
145
+ }
146
+
147
+ fields . Add ( chainId . ToByteArray ( isUnsigned : true , isBigEndian : true ) ) ;
148
+ fields . Add ( transaction . From . HexToByteArray ( ) ) ;
149
+
150
+ // Add meta
151
+ fields . Add ( transaction . GasPerPubdataByteLimit . ToByteArray ( isUnsigned : true , isBigEndian : true ) ) ;
152
+ fields . Add ( RLP . EncodeList ( transaction . FactoryDeps ) ) ;
153
+ fields . Add ( signatureHex . HexToByteArray ( ) ) ;
154
+
155
+ if ( ! string . IsNullOrEmpty ( transaction . Paymaster ) && transaction . PaymasterInput != null )
156
+ {
157
+ fields . Add ( transaction . Paymaster . HexToByteArray ( ) ) ;
158
+ fields . Add ( transaction . PaymasterInput ) ;
159
+ }
160
+ else
161
+ {
162
+ fields . Add ( new byte [ 0 ] ) ;
163
+ }
164
+
165
+ // 0x71f901250c84017d784084017d78408401312d009483e13cd6b1179be8b8cb5858accbba84394cf9a780801ca095bdae3d9ee4919b95ccb65008fb834b876cf6daab54f08914a3682b692dac3ba007de707e93d03249ffcaac274caf27e513cbe96d78d24c0136ab8a2aae94a66782012c9483e13cd6b1179be8b8cb5858accbba84394cf9a782c35081c0b8413bac2d692b68a31489f054abdaf66c874b83fb0850b6cc959b91e49e3daebd9567a694ae2a8aab36014cd2786de9cb13e527af4c27accaff4932d0937e70de071c94ba226d47cbb2731cbaa67c916c57d68484aa269fb8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000
166
+
167
+ // 0x71f901260c84017d784084017d78408401312d009483e13cd6b1179be8b8cb5858accbba84394cf9a7808080a02ce7dea3c25ac28c69ef5d425933bf6195c7c5648e4e228e3dca1f62f147449ea06b626df4ccad17b8c472ddba39b113c0e8f49569572fdd4ac2f6e2ddfc29726682012c9483e13cd6b1179be8b8cb5858accbba84394cf9a782c350c0b8412ce7dea3c25ac28c69ef5d425933bf6195c7c5648e4e228e3dca1f62f147449e6b626df4ccad17b8c472ddba39b113c0e8f49569572fdd4ac2f6e2ddfc2972661bf85b94ba226d47cbb2731cbaa67c916c57d68484aa269fb8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000
168
+
169
+ return "0x71" + RLP . EncodeDataItemsAsElementOrListAndCombineAsList ( fields . ToArray ( ) ) . ToHex ( ) ;
143
170
}
144
171
}
145
172
}
0 commit comments