Skip to content

Commit 0196f47

Browse files
committed
add decoder
1 parent 7db813b commit 0196f47

File tree

4 files changed

+126
-58
lines changed

4 files changed

+126
-58
lines changed

Thirdweb.Console/Program.cs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,40 +41,29 @@
4141
var eoaWalletAddress = await eoaWallet.GetAddress();
4242
Console.WriteLine($"EOA address: {eoaWalletAddress}");
4343

44-
// Temporary - fund eoa wallet
45-
var fundingWallet = await PrivateKeyWallet.Create(client, privateKey);
46-
var fundingHash = (
47-
await ThirdwebTransaction.SendAndWaitForTransactionReceipt(
48-
await ThirdwebTransaction.Create(fundingWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, value: BigInteger.Parse("0.1".ToWei())))
49-
)
50-
).TransactionHash;
51-
Console.WriteLine($"Funding hash: {fundingHash}");
44+
// // Temporary - fund eoa wallet
45+
// var fundingWallet = await PrivateKeyWallet.Create(client, privateKey);
46+
// var fundingHash = (
47+
// await ThirdwebTransaction.SendAndWaitForTransactionReceipt(
48+
// await ThirdwebTransaction.Create(fundingWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, value: BigInteger.Parse("0.01".ToWei())))
49+
// )
50+
// ).TransactionHash;
51+
// Console.WriteLine($"Funding hash: {fundingHash}");
5252

5353
// Sign the authorization to make it point to the delegation contract
54-
var authorization = await eoaWallet.SignAuthorization(chainId: chainWith7702, contractAddress: delegationContractAddress, willSelfExecute: true);
54+
var authorization = await eoaWallet.SignAuthorization(chainId: chainWith7702, contractAddress: delegationContractAddress, willSelfExecute: false);
5555
Console.WriteLine($"Authorization: {JsonConvert.SerializeObject(authorization, Formatting.Indented)}");
5656

57-
// Execute the delegation
58-
var tx = await ThirdwebTransaction.Create(eoaWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, authorization: authorization));
59-
var hash = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx)).TransactionHash;
60-
Console.WriteLine($"Transaction hash: {hash}");
61-
6257
// Initialize another wallet, the "executor" that will hit the eoa's execute function
63-
var executorWallet = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google);
64-
if (!await executorWallet.IsConnected())
65-
{
66-
_ = await executorWallet.LoginWithOauth(
67-
isMobile: false,
68-
browserOpenAction: (url) =>
69-
{
70-
var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true };
71-
_ = Process.Start(psi);
72-
}
73-
);
74-
}
58+
var executorWallet = await PrivateKeyWallet.Create(client, privateKey);
7559
var executorWalletAddress = await executorWallet.GetAddress();
7660
Console.WriteLine($"Executor address: {executorWalletAddress}");
7761

62+
// Execute the delegation
63+
var tx = await ThirdwebTransaction.Create(executorWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, authorization: authorization));
64+
var hash = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx)).TransactionHash;
65+
Console.WriteLine($"Transaction hash: {hash}");
66+
7867
// Log erc20 balance of executor before the claim
7968
var executorBalanceBefore = await erc20Contract.ERC20_BalanceOf(executorWalletAddress);
8069
Console.WriteLine($"Executor balance before: {executorBalanceBefore}");

Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -261,33 +261,24 @@ public static async Task<string> Simulate(ThirdwebTransaction transaction)
261261
public static async Task<BigInteger> EstimateGasLimit(ThirdwebTransaction transaction)
262262
{
263263
var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value);
264-
265-
// Remove when https://github.com/ethereum/execution-apis/issues/561 is in
266-
var txInput = new ThirdwebTransactionInput(
267-
chainId: transaction.Input.ChainId,
268-
from: transaction.Input.From,
269-
to: transaction.Input.To,
270-
nonce: transaction.Input.Nonce,
271-
value: transaction.Input.Value,
272-
data: transaction.Input.Data,
273-
zkSync: transaction.Input.ZkSync
274-
);
275-
276-
var extraGas = transaction.Input.AuthorizationList == null ? 0 : 100000;
277-
BigInteger finalGas;
278-
279-
if (await Utils.IsZkSync(transaction._wallet.Client, txInput.ChainId.Value).ConfigureAwait(false))
264+
var isZkSync = await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false);
265+
BigInteger divider = isZkSync
266+
? 7
267+
: transaction.Input.AuthorizationList == null
268+
? 5
269+
: 3;
270+
BigInteger baseGas;
271+
if (isZkSync)
280272
{
281-
var hex = (await rpc.SendRequestAsync<JToken>("zks_estimateFee", txInput).ConfigureAwait(false))["gas_limit"].ToString();
282-
finalGas = hex.HexToBigInt() * 2;
273+
var hex = (await rpc.SendRequestAsync<JToken>("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_limit"].ToString();
274+
baseGas = hex.HexToBigInt();
283275
}
284276
else
285277
{
286-
var hex = await rpc.SendRequestAsync<string>("eth_estimateGas", txInput).ConfigureAwait(false);
287-
finalGas = hex.HexToBigInt() * 2;
278+
var hex = await rpc.SendRequestAsync<string>("eth_estimateGas", transaction.Input).ConfigureAwait(false);
279+
baseGas = hex.HexToBigInt();
288280
}
289-
290-
return finalGas + extraGas;
281+
return baseGas * 10 / divider;
291282
}
292283

293284
/// <summary>

Thirdweb/Thirdweb.Utils/Utils.cs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using Nethereum.Contracts;
1313
using Nethereum.Hex.HexConvertors.Extensions;
1414
using Nethereum.Hex.HexTypes;
15+
using Nethereum.Model;
16+
using Nethereum.RLP;
1517
using Nethereum.Signer;
1618
using Nethereum.Util;
1719
using Newtonsoft.Json;
@@ -1056,4 +1058,92 @@ public static byte[] TrimZeroes(this byte[] bytes)
10561058

10571059
return trimmed.ToArray();
10581060
}
1061+
1062+
/// <summary>
1063+
/// Decodes the given RLP-encoded transaction data.
1064+
/// </summary>
1065+
/// <param name="signedRlpData">The RLP-encoded signed transaction data.</param>
1066+
/// <returns>The decoded transaction input and signature.</returns>
1067+
public static (ThirdwebTransactionInput transactionInput, string signature) DecodeTransaction(string signedRlpData)
1068+
{
1069+
return DecodeTransaction(signedRlpData.HexToBytes());
1070+
}
1071+
1072+
/// <summary>
1073+
/// Decodes the given RLP-encoded transaction data.
1074+
/// </summary>
1075+
/// <param name="signedRlpData">The RLP-encoded signed transaction data.</param>
1076+
/// <returns>The decoded transaction input and signature.</returns>
1077+
public static (ThirdwebTransactionInput transactionInput, string signature) DecodeTransaction(byte[] signedRlpData)
1078+
{
1079+
var maybeType = signedRlpData[0];
1080+
if (maybeType is 0x04 or 0x02)
1081+
{
1082+
signedRlpData = signedRlpData.Skip(1).ToArray();
1083+
}
1084+
1085+
var decodedList = RLP.Decode(signedRlpData);
1086+
var decodedElements = (RLPCollection)decodedList;
1087+
var chainId = decodedElements[0].RLPData.ToBigIntegerFromRLPDecoded();
1088+
var nonce = decodedElements[1].RLPData.ToBigIntegerFromRLPDecoded();
1089+
var maxPriorityFeePerGas = decodedElements[2].RLPData.ToBigIntegerFromRLPDecoded();
1090+
var maxFeePerGas = decodedElements[3].RLPData.ToBigIntegerFromRLPDecoded();
1091+
var gasLimit = decodedElements[4].RLPData.ToBigIntegerFromRLPDecoded();
1092+
var receiverAddress = decodedElements[5].RLPData?.BytesToHex();
1093+
var amount = decodedElements[6].RLPData.ToBigIntegerFromRLPDecoded();
1094+
var data = decodedElements[7].RLPData?.BytesToHex();
1095+
// 8th decoded element is access list
1096+
var authorizations = DecodeAutorizationList(decodedElements[9]?.RLPData);
1097+
1098+
var signature = RLPSignedDataDecoder.DecodeSignature(decodedElements, 10);
1099+
return (
1100+
new ThirdwebTransactionInput(
1101+
chainId: chainId,
1102+
to: receiverAddress,
1103+
nonce: nonce,
1104+
gas: gasLimit,
1105+
value: amount,
1106+
data: data,
1107+
maxFeePerGas: maxFeePerGas,
1108+
maxPriorityFeePerGas: maxPriorityFeePerGas
1109+
)
1110+
{
1111+
AuthorizationList = authorizations
1112+
},
1113+
signature.CreateStringSignature()
1114+
);
1115+
}
1116+
1117+
/// <summary>
1118+
/// Decodes the given RLP-encoded authorization list.
1119+
/// </summary>
1120+
public static List<EIP7702Authorization> DecodeAutorizationList(byte[] authorizationListEncoded)
1121+
{
1122+
if (authorizationListEncoded == null || authorizationListEncoded.Length == 0 || authorizationListEncoded[0] == RLP.OFFSET_SHORT_LIST)
1123+
{
1124+
return null;
1125+
}
1126+
1127+
var decodedList = (RLPCollection)RLP.Decode(authorizationListEncoded);
1128+
1129+
var authorizationLists = new List<EIP7702Authorization>();
1130+
foreach (var rlpElement in decodedList)
1131+
{
1132+
var decodedItem = (RLPCollection)rlpElement;
1133+
var authorizationListItem = new EIP7702Authorization
1134+
{
1135+
ChainId = new HexBigInteger(decodedItem[0].RLPData.ToBigIntegerFromRLPDecoded()).HexValue,
1136+
Address = decodedItem[1].RLPData.BytesToHex(),
1137+
Nonce = new HexBigInteger(decodedItem[2].RLPData.ToBigIntegerFromRLPDecoded()).HexValue
1138+
};
1139+
var signature = RLPSignedDataDecoder.DecodeSignature(decodedItem, 3);
1140+
authorizationListItem.YParity = signature.V.BytesToHex();
1141+
authorizationListItem.R = signature.R.BytesToHex();
1142+
authorizationListItem.S = signature.S.BytesToHex();
1143+
1144+
authorizationLists.Add(authorizationListItem);
1145+
}
1146+
1147+
return authorizationLists;
1148+
}
10591149
}

Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Text;
33
using Nethereum.ABI.EIP712;
44
using Nethereum.Hex.HexConvertors.Extensions;
5-
using Nethereum.Hex.HexTypes;
65
using Nethereum.RLP;
76
using Nethereum.Signer;
87
using Nethereum.Signer.EIP712;
@@ -351,9 +350,9 @@ public virtual Task<string> SignTransaction(ThirdwebTransactionInput transaction
351350
RLP.EncodeElement(authorizationList.ChainId.HexToBigInt().ToBytesForRLPEncoding()),
352351
RLP.EncodeElement(authorizationList.Address.HexToBytes()),
353352
RLP.EncodeElement(authorizationList.Nonce.HexToBigInt().ToBytesForRLPEncoding()),
354-
RLP.EncodeElement(authorizationList.YParity.HexToBytes()),
355-
RLP.EncodeElement(authorizationList.R.HexToBytes()),
356-
RLP.EncodeElement(authorizationList.S.HexToBytes())
353+
RLP.EncodeElement(authorizationList.YParity.HexToBytes()[0] == 0 ? Array.Empty<byte>() : authorizationList.YParity.HexToBytes()),
354+
RLP.EncodeElement(authorizationList.R.HexToBytes().TrimZeroes()),
355+
RLP.EncodeElement(authorizationList.S.HexToBytes().TrimZeroes())
357356
};
358357
encodedAuthorizationList.Add(RLP.EncodeList(encodedItem.ToArray()));
359358
}
@@ -402,7 +401,11 @@ public virtual Task<string> SignTransaction(ThirdwebTransactionInput transaction
402401
Array.Copy(encodedBytes, 0, returnBytes, 1, encodedBytes.Length);
403402
returnBytes[0] = transaction.AuthorizationList != null ? (byte)0x04 : (byte)0x02;
404403

404+
// (var tx, var sig) = Utils.DecodeTransaction(returnBytes);
405+
405406
signedTransaction = returnBytes.ToHex();
407+
408+
// (var tx, var sig) = Utils.DecodeTransaction("0x" + signedTransaction);
406409
}
407410

408411
return Task.FromResult("0x" + signedTransaction);
@@ -461,12 +464,7 @@ public async Task<EIP7702Authorization> SignAuthorization(BigInteger chainId, st
461464
{
462465
nonce++;
463466
}
464-
var encodedData = new List<byte[]>
465-
{
466-
RLP.EncodeElement(new HexBigInteger(chainId).Value.ToBytesForRLPEncoding()),
467-
RLP.EncodeElement(contractAddress.HexToBytes()),
468-
RLP.EncodeElement(new HexBigInteger(nonce).Value.ToBytesForRLPEncoding())
469-
};
467+
var encodedData = new List<byte[]> { RLP.EncodeElement(chainId.ToBytesForRLPEncoding()), RLP.EncodeElement(contractAddress.HexToBytes()), RLP.EncodeElement(nonce.ToBytesForRLPEncoding()) };
470468
var encodedBytes = RLP.EncodeList(encodedData.ToArray());
471469
var returnElements = new byte[encodedBytes.Length + 1];
472470
Array.Copy(encodedBytes.ToArray(), 0, returnElements, 1, encodedBytes.Length);

0 commit comments

Comments
 (0)