Skip to content

Commit 3bb48c3

Browse files
authored
Allow raw pm-less zksync serialized txs (#61)
1 parent 371170e commit 3bb48c3

File tree

6 files changed

+93
-33
lines changed

6 files changed

+93
-33
lines changed

Thirdweb.Console/Program.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,67 @@
8686

8787
#endregion
8888

89+
#region Maximum low level zksync tx
90+
91+
// var chainId = 300;
92+
93+
// var zkRawWallet = await PrivateKeyWallet.Generate(client: client);
94+
// var zkRawAddy = await zkRawWallet.GetAddress();
95+
// Console.WriteLine($"ZkSync raw address: {zkRawAddy}");
96+
97+
// // Less raw example
98+
99+
// var zkRawTx = await ThirdwebTransaction.Create(
100+
// wallet: zkRawWallet,
101+
// txInput: new ThirdwebTransactionInput(
102+
// chainId: chainId,
103+
// from: zkRawAddy,
104+
// to: zkRawAddy,
105+
// value: 0,
106+
// data: "0x",
107+
// zkSync: new ZkSyncOptions(paymaster: null, paymasterInput: null, gasPerPubdataByteLimit: 50000)
108+
// )
109+
// );
110+
111+
// zkRawTx = await ThirdwebTransaction.Prepare(zkRawTx);
112+
113+
// Console.WriteLine($"ZkSync raw transaction: {zkRawTx}");
114+
// Console.WriteLine("Make sure you have enough funds!");
115+
// Console.ReadLine();
116+
117+
// var hash = await ThirdwebTransaction.Send(zkRawTx);
118+
// Console.WriteLine($"Transaction hash: {hash}");
119+
120+
// // Extremely raw example
121+
122+
// var zkRawTx = new Thirdweb.AccountAbstraction.ZkSyncAATransaction
123+
// {
124+
// TxType = 0x71,
125+
// From = new HexBigInteger(zkRawAddy).Value,
126+
// To = new HexBigInteger(zkRawAddy).Value,
127+
// GasLimit = 250000,
128+
// GasPerPubdataByteLimit = 50000,
129+
// MaxFeePerGas = 1000000000,
130+
// MaxPriorityFeePerGas = 1000000000,
131+
// Paymaster = 0,
132+
// Nonce = 0,
133+
// Value = 0,
134+
// Data = new byte[] { 0x00 },
135+
// FactoryDeps = new List<byte[]>(),
136+
// PaymasterInput = Array.Empty<byte>(),
137+
// };
138+
// var signedZkRawTx = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", chainId, zkRawTx, zkRawWallet);
139+
140+
// Console.WriteLine($"ZkSync raw transaction: {JsonConvert.SerializeObject(zkRawTx, Formatting.Indented)}");
141+
// Console.WriteLine("Make sure you have enough funds!");
142+
// Console.ReadLine();
143+
144+
// var rpcInstance = ThirdwebRPC.GetRpcInstance(client, chainId);
145+
// var hash = await rpcInstance.SendRequestAsync<string>("eth_sendRawTransaction", signedZkRawTx);
146+
// Console.WriteLine($"Transaction hash: {hash}");
147+
148+
#endregion
149+
89150
#region Account Linking
90151

91152
// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google);

Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,17 +201,17 @@ public async Task SetZkSyncOptions_DefaultsToZeroNull()
201201
transaction = await this.CreateSampleTransaction();
202202
_ = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: null, paymasterInput: "0x"));
203203
Assert.Equal(0, transaction.Input.ZkSync?.Paymaster);
204-
Assert.Null(transaction.Input.ZkSync?.PaymasterInput);
204+
Assert.Equal(transaction.Input.ZkSync?.PaymasterInput, Array.Empty<byte>());
205205
Assert.Null(transaction.Input.ZkSync?.GasPerPubdataByteLimit);
206-
Assert.Null(transaction.Input.ZkSync?.FactoryDeps);
206+
Assert.Equal(transaction.Input.ZkSync?.FactoryDeps, new List<byte[]>());
207207

208208
// PaymasterInput null
209209
transaction = await this.CreateSampleTransaction();
210210
_ = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: "0x", paymasterInput: null));
211211
Assert.Equal(0, transaction.Input.ZkSync?.Paymaster);
212-
Assert.Null(transaction.Input.ZkSync?.PaymasterInput);
212+
Assert.Equal(transaction.Input.ZkSync?.PaymasterInput, Array.Empty<byte>());
213213
Assert.Null(transaction.Input.ZkSync?.GasPerPubdataByteLimit);
214-
Assert.Null(transaction.Input.ZkSync?.FactoryDeps);
214+
Assert.Equal(transaction.Input.ZkSync?.FactoryDeps, new List<byte[]>());
215215
}
216216

217217
[Fact(Timeout = 120000)]

Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public async Task GetAddress_Success()
2727
[Fact(Timeout = 120000)]
2828
public async Task PersonalSign_Success()
2929
{
30-
var account = await this.GetSmartAccount(zkChainId: 302);
30+
var account = await this.GetSmartAccount(zkChainId: 300);
3131
var message = "Hello, World!";
3232
var signature = await account.PersonalSign(message);
3333
Assert.NotNull(signature);
@@ -90,22 +90,22 @@ public async Task SendGaslessZkTx_Success()
9090
Assert.True(hash.Length == 66);
9191
}
9292

93-
[Fact(Timeout = 120000)]
94-
public async Task SendGaslessZkTx_ZkCandy_Success()
95-
{
96-
var account = await this.GetSmartAccount(zkChainId: 302);
97-
var hash = await account.SendTransaction(
98-
new ThirdwebTransactionInput(302)
99-
{
100-
From = await account.GetAddress(),
101-
To = await account.GetAddress(),
102-
Value = new Nethereum.Hex.HexTypes.HexBigInteger(0),
103-
Data = "0x"
104-
}
105-
);
106-
Assert.NotNull(hash);
107-
Assert.True(hash.Length == 66);
108-
}
93+
// [Fact(Timeout = 120000)]
94+
// public async Task SendGaslessZkTx_ZkCandy_Success()
95+
// {
96+
// var account = await this.GetSmartAccount(zkChainId: 302);
97+
// var hash = await account.SendTransaction(
98+
// new ThirdwebTransactionInput(302)
99+
// {
100+
// From = await account.GetAddress(),
101+
// To = await account.GetAddress(),
102+
// Value = new Nethereum.Hex.HexTypes.HexBigInteger(0),
103+
// Data = "0x"
104+
// }
105+
// );
106+
// Assert.NotNull(hash);
107+
// Assert.True(hash.Length == 66);
108+
// }
109109

110110
[Fact(Timeout = 120000)]
111111
public async Task SendGaslessZkTx_Abstract_Success()
@@ -129,7 +129,7 @@ public async Task ZkSync_Switch()
129129
{
130130
var account = await this.GetSmartAccount(zkChainId: 300);
131131
_ = await account.SendTransaction(
132-
new ThirdwebTransactionInput(302)
132+
new ThirdwebTransactionInput(11124)
133133
{
134134
From = await account.GetAddress(),
135135
To = await account.GetAddress(),

Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ public static async Task<ThirdwebTransaction> Prepare(ThirdwebTransaction transa
357357
throw new InvalidOperationException("Transaction GasPrice and MaxFeePerGas/MaxPriorityFeePerGas cannot be set at the same time");
358358
}
359359

360+
transaction.Input.Nonce ??= new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false));
360361
transaction.Input.Value ??= new HexBigInteger(0);
361362
transaction.Input.Data ??= "0x";
362363
transaction.Input.Gas ??= new HexBigInteger(await EstimateGasLimit(transaction).ConfigureAwait(false));
@@ -393,12 +394,7 @@ public static async Task<string> Send(ThirdwebTransaction transaction)
393394

394395
var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value);
395396
string hash;
396-
if (
397-
Utils.IsZkSync(transaction.Input.ChainId.Value)
398-
&& transaction.Input.ZkSync.HasValue
399-
&& transaction.Input.ZkSync.Value.Paymaster != 0
400-
&& transaction.Input.ZkSync.Value.PaymasterInput != null
401-
)
397+
if (Utils.IsZkSync(transaction.Input.ChainId.Value) && transaction.Input.ZkSync.HasValue)
402398
{
403399
var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false);
404400
var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet).ConfigureAwait(false);
@@ -409,7 +405,6 @@ public static async Task<string> Send(ThirdwebTransaction transaction)
409405
switch (transaction._wallet.AccountType)
410406
{
411407
case ThirdwebAccountType.PrivateKeyAccount:
412-
transaction.Input.Nonce ??= new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false));
413408
var signedTx = await Sign(transaction);
414409
hash = await rpc.SendRequestAsync<string>("eth_sendRawTransaction", signedTx).ConfigureAwait(false);
415410
break;

Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ public ZkSyncOptions(string paymaster, string paymasterInput, BigInteger? gasPer
166166
if (string.IsNullOrEmpty(paymaster) || string.IsNullOrEmpty(paymasterInput))
167167
{
168168
this.Paymaster = 0;
169-
this.PaymasterInput = null;
169+
this.PaymasterInput = Array.Empty<byte>();
170+
this.GasPerPubdataByteLimit = gasPerPubdataByteLimit;
171+
this.FactoryDeps = factoryDeps ?? new List<byte[]>();
170172
}
171173
else
172174
{

Thirdweb/Thirdweb.Wallets/EIP712.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,8 @@ private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction tra
366366
throw new ArgumentException("Chain ID must be provided for EIP712 transactions!");
367367
}
368368

369-
var fields = new List<byte[]> {
369+
var fields = new List<byte[]>
370+
{
370371
transaction.Nonce == 0 ? Array.Empty<byte>() : transaction.Nonce.ToByteArray(isUnsigned: true, isBigEndian: true),
371372
transaction.MaxPriorityFeePerGas == 0 ? Array.Empty<byte>() : transaction.MaxPriorityFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true),
372373
transaction.MaxFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true),
@@ -379,13 +380,14 @@ private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction tra
379380
signature.S,
380381
chainId.ToByteArray(isUnsigned: true, isBigEndian: true),
381382
transaction.From.ToByteArray(isUnsigned: true, isBigEndian: true),
382-
383383
// Add meta
384384
transaction.GasPerPubdataByteLimit.ToByteArray(isUnsigned: true, isBigEndian: true),
385385
Array.Empty<byte>(), // TODO: FactoryDeps
386386
signature.CreateStringSignature().HexToByteArray(),
387387
// add array of rlp encoded paymaster/paymasterinput
388-
RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray()
388+
transaction.Paymaster != 0
389+
? RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray()
390+
: Array.Empty<byte>()
389391
};
390392

391393
return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), _indexOfListDataItems).ToHex();

0 commit comments

Comments
 (0)