Skip to content

Commit

Permalink
Move zksyncoptions to type, use zk rpc fees
Browse files Browse the repository at this point in the history
  • Loading branch information
0xFirekeeper committed May 23, 2024
1 parent a15eea3 commit 1308554
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 31 deletions.
31 changes: 17 additions & 14 deletions Thirdweb.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,31 @@
// }
}

// Test 113
// Prepare a transaction directly, or with Contract.Prepare
var tx = await ThirdwebTransaction.Create(
client,
privateKeyWallet,
new ThirdwebTransactionInput()
client: client,
wallet: privateKeyWallet,
txInput: new ThirdwebTransactionInput()
{
From = await privateKeyWallet.GetAddress(),
To = await privateKeyWallet.GetAddress(),
Value = new HexBigInteger(BigInteger.Zero),
Data = "0x",
MaxFeePerGas = new HexBigInteger(25000000),
MaxPriorityFeePerGas = new HexBigInteger(25000000),
Gas = new HexBigInteger(20000000),
ChainId = new HexBigInteger(300),
},
300
chainId: 300
);
var txHash = await ThirdwebTransaction.Send(
transaction: tx,
zkSyncPaymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F",
zkSyncPaymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"

// Set zkSync options
tx.SetZkSyncOptions(
new ZkSyncOptions(
// Paymaster contract address
paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F",
// IPaymasterFlow interface encoded data
paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"
)
);

// Send as usual, it's now gasless!
var txHash = await ThirdwebTransaction.Send(transaction: tx);
Console.WriteLine($"Transaction hash: {txHash}");


Expand Down
15 changes: 11 additions & 4 deletions Thirdweb.Tests/Thirdweb.Contracts.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,17 @@ public async Task WriteTest_PrivateKeyAccount()
var pricePerToken = BigInteger.Zero;
var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO };
var data = new byte[] { };
var exception = await Assert.ThrowsAsync<Exception>(
async () => await ThirdwebContract.Write(privateKeyAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data)
);
Assert.Contains("insufficient funds", exception.Message);
try
{
var res = await ThirdwebContract.Write(privateKeyAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data);
Assert.NotNull(res);
Assert.NotNull(res.TransactionHash);
Assert.Equal(66, res.TransactionHash.Length);
}
catch (Exception ex)
{
Assert.Contains("insufficient funds", ex.Message);
}
}

private async Task<SmartWallet> GetAccount()
Expand Down
7 changes: 2 additions & 5 deletions Thirdweb.Tests/Thirdweb.PrivateKeyWallet.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public async Task EthSign_Success()
public async Task EthSign_NullMessage()
{
var account = await GetAccount();
var ex = await Assert.ThrowsAsync<ArgumentNullException>(() => account.EthSign(null));
var ex = await Assert.ThrowsAsync<ArgumentNullException>(() => account.EthSign(null as string));
Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message);
}

Expand Down Expand Up @@ -241,7 +241,7 @@ public async Task SignTransaction_NoGasPrice()
Nonce = new HexBigInteger(99999999999)
};
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => account.SignTransaction(transaction, 421614));
Assert.Equal("Transaction gas price must be set for legacy transactions", ex.Message);
Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message);
}

[Fact]
Expand All @@ -256,7 +256,6 @@ public async Task SignTransaction_1559_Success()
Gas = new HexBigInteger(21000),
Data = "0x",
Nonce = new HexBigInteger(99999999999),
Type = new HexBigInteger(2),
MaxFeePerGas = new HexBigInteger(10000000000),
MaxPriorityFeePerGas = new HexBigInteger(10000000000)
};
Expand All @@ -276,7 +275,6 @@ public async Task SignTransaction_1559_NoMaxFeePerGas()
Gas = new HexBigInteger(21000),
Data = "0x",
Nonce = new HexBigInteger(99999999999),
Type = new HexBigInteger(2),
MaxPriorityFeePerGas = new HexBigInteger(10000000000)
};
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => account.SignTransaction(transaction, 421614));
Expand All @@ -295,7 +293,6 @@ public async Task SignTransaction_1559_NoMaxPriorityFeePerGas()
Gas = new HexBigInteger(21000),
Data = "0x",
Nonce = new HexBigInteger(99999999999),
Type = new HexBigInteger(2),
MaxFeePerGas = new HexBigInteger(10000000000)
};
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => account.SignTransaction(transaction, 421614));
Expand Down
39 changes: 32 additions & 7 deletions Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ public ThirdwebTransaction SetNonce(BigInteger nonce)
return this;
}

public ThirdwebTransaction SetZkSyncOptions(ZkSyncOptions zkSyncOptions)
{
Input.ZkSync = zkSyncOptions;
return this;
}

public static async Task<TotalCosts> EstimateGasCosts(ThirdwebTransaction transaction)
{
var gasPrice = transaction.Input.GasPrice?.Value ?? await EstimateGasPrice(transaction);
Expand All @@ -113,6 +119,15 @@ public static async Task<BigInteger> EstimateGasPrice(ThirdwebTransaction transa
{
var rpc = ThirdwebRPC.GetRpcInstance(transaction._client, transaction.Input.ChainId.Value);
var chainId = transaction.Input.ChainId.Value;

if (IsZkSyncTransaction(transaction))
{
var fees = await rpc.SendRequestAsync<JToken>("zks_estimateFee", transaction.Input, "latest");
var maxFee = fees["max_fee_per_gas"].ToObject<HexBigInteger>().Value;
var maxPriorityFee = fees["max_priority_fee_per_gas"].ToObject<HexBigInteger>().Value;
return (maxFee, maxPriorityFee == 0 ? maxFee : maxPriorityFee);
}

var gasPrice = await EstimateGasPrice(transaction, withBump);

try
Expand Down Expand Up @@ -164,7 +179,9 @@ public static async Task<BigInteger> EstimateGasLimit(ThirdwebTransaction transa
else
{
var rpc = ThirdwebRPC.GetRpcInstance(transaction._client, transaction.Input.ChainId.Value);
var hex = await rpc.SendRequestAsync<string>("eth_estimateGas", transaction.Input, "latest");
var hex = IsZkSyncTransaction(transaction)
? (await rpc.SendRequestAsync<JToken>("zks_estimateFee", transaction.Input, "latest"))["gas_limit"].ToString()
: await rpc.SendRequestAsync<string>("eth_estimateGas", transaction.Input, "latest");
return new HexBigInteger(hex).Value;
}
}
Expand All @@ -174,7 +191,7 @@ public static async Task<string> Sign(ThirdwebTransaction transaction)
return await transaction._wallet.SignTransaction(transaction.Input, transaction.Input.ChainId.Value);
}

public static async Task<string> Send(ThirdwebTransaction transaction, string zkSyncPaymaster = null, string zkSyncPaymasterInput = null)
public static async Task<string> Send(ThirdwebTransaction transaction)
{
if (transaction.Input.To == null)
{
Expand Down Expand Up @@ -204,8 +221,7 @@ public static async Task<string> Send(ThirdwebTransaction transaction, string zk

var rpc = ThirdwebRPC.GetRpcInstance(transaction._client, transaction.Input.ChainId.Value);
string hash;
var isZkAA = zkSyncPaymaster != null && zkSyncPaymasterInput != null;
if (isZkAA && (transaction.Input.ChainId.Value.Equals(324) || transaction.Input.ChainId.Value.Equals(300)))
if (IsZkSyncTransaction(transaction))
{
var zkTx = new AccountAbstraction.ZkSyncAATransaction
{
Expand All @@ -216,13 +232,14 @@ public static async Task<string> Send(ThirdwebTransaction transaction, string zk
GasPerPubdataByteLimit = 50000,
MaxFeePerGas = transaction.Input.MaxFeePerGas?.Value ?? transaction.Input.GasPrice.Value,
MaxPriorityFeePerGas = transaction.Input.MaxPriorityFeePerGas?.Value ?? transaction.Input.GasPrice.Value,
Paymaster = new HexBigInteger(zkSyncPaymaster).Value,
Paymaster = transaction.Input.ZkSync.Paymaster,
Nonce = transaction.Input.Nonce ?? new HexBigInteger(await rpc.SendRequestAsync<string>("eth_getTransactionCount", transaction.Input.From, "latest")),
Value = transaction.Input.Value.Value,
Data = transaction.Input.Data.HexToByteArray(),
FactoryDeps = new byte[] { },
PaymasterInput = zkSyncPaymasterInput.HexToByteArray()
FactoryDeps = transaction.Input.ZkSync.FactoryDeps,
PaymasterInput = transaction.Input.ZkSync.PaymasterInput
};
Console.WriteLine("zkTx: " + JsonConvert.SerializeObject(zkTx));
var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet);
hash = await rpc.SendRequestAsync<string>("eth_sendRawTransaction", zkTxSigned);
}
Expand Down Expand Up @@ -295,5 +312,13 @@ public static async Task<TransactionReceipt> WaitForTransactionReceipt(ThirdwebC

return receipt;
}

private static bool IsZkSyncTransaction(ThirdwebTransaction transaction)
{
return (transaction.Input.ChainId.Value.Equals(324) || transaction.Input.ChainId.Value.Equals(300))
&& transaction.Input.ZkSync != null
&& transaction.Input.ZkSync.Paymaster != 0
&& transaction.Input.ZkSync.PaymasterInput != null;
}
}
}
27 changes: 27 additions & 0 deletions Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Numerics;
using Nethereum.Hex.HexConvertors.Extensions;
using Nethereum.Hex.HexTypes;
using Newtonsoft.Json;
Expand Down Expand Up @@ -53,5 +54,31 @@ public string Data

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

[JsonProperty(PropertyName = "zkSyncOptions", NullValueHandling = NullValueHandling.Ignore)]
public ZkSyncOptions ZkSync { get; set; }
}

public class ZkSyncOptions
{
[JsonProperty(PropertyName = "gasPerPubdataByteLimit")]
public BigInteger GasPerPubdataByteLimit { get; set; }

[JsonProperty(PropertyName = "factoryDeps")]
public List<byte[]> FactoryDeps { get; set; }

[JsonProperty(PropertyName = "paymaster")]
public BigInteger Paymaster { get; set; }

[JsonProperty(PropertyName = "paymasterInput")]
public byte[] PaymasterInput { get; set; }

public ZkSyncOptions(string paymaster, string paymasterInput, BigInteger? gasPerPubdataByteLimit = null, List<byte[]> factoryDeps = null)
{
Paymaster = new HexBigInteger(paymaster).Value;
PaymasterInput = paymasterInput.HexToByteArray();
GasPerPubdataByteLimit = gasPerPubdataByteLimit ?? new BigInteger(50000);
FactoryDeps = factoryDeps ?? new List<byte[]>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public class ZkSyncAATransaction
public virtual byte[] Data { get; set; }

[Parameter("bytes32[]", "factoryDeps", 12)]
public virtual byte[] FactoryDeps { get; set; }
public virtual List<byte[]> FactoryDeps { get; set; }

[Parameter("bytes", "paymasterInput", 13)]
public virtual byte[] PaymasterInput { get; set; }
Expand Down

0 comments on commit 1308554

Please sign in to comment.