Skip to content

Commit

Permalink
Add GetTransactions ThirdwebInsight API
Browse files Browse the repository at this point in the history
Closes TOOL-3501
  • Loading branch information
0xFirekeeper committed Feb 21, 2025
1 parent 5beb93e commit f6b25d5
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 3 deletions.
15 changes: 13 additions & 2 deletions Thirdweb.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@

#region Indexer

// // Create a ThirdwebInsight instance
// var insight = await ThirdwebInsight.Create(client);
// Create a ThirdwebInsight instance
var insight = await ThirdwebInsight.Create(client);

// // Setup some filters
// var address = await Utils.GetAddressFromENS(client, "vitalik.eth");
Expand Down Expand Up @@ -78,6 +78,17 @@
// );
// Console.WriteLine($"Events: {JsonConvert.SerializeObject(events, Formatting.Indented)}");

// // Fetch transactions (great amount of optional filters available)
// var transactions = await insight.GetTransactions(
// chainIds: new BigInteger[] { 1 }, // ethereum
// contractAddress: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", // bored apes
// fromTimestamp: Utils.GetUnixTimeStampNow() - 3600, // last hour
// sortBy: SortBy.TransactionIndex, // block number, block timestamp or transaction index
// sortOrder: SortOrder.Desc, // latest first
// limit: 5 // last 5 transactions
// );
// Console.WriteLine($"Transactions: {JsonConvert.SerializeObject(transactions, Formatting.Indented)}");

#endregion

#region AI
Expand Down
96 changes: 95 additions & 1 deletion Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ public class Token

public class Token_ERC20 : Token { }

public class Token_ERC721 : Token { }
public class Token_ERC721 : Token
{
[JsonProperty("tokenId", Required = Required.Always)]
public BigInteger TokenId { get; set; }
}

public class Token_ERC1155 : Token
{
Expand Down Expand Up @@ -81,6 +85,96 @@ public class Event
public Decoded Decoded { get; set; } = null!;
}

public class Transaction
{
[JsonProperty("chain_id", Required = Required.Always)]
public BigInteger ChainId { get; set; }

[JsonProperty("block_number", Required = Required.Always)]
public string BlockNumber { get; set; } = null!;

[JsonProperty("block_hash", Required = Required.Always)]
public string BlockHash { get; set; } = null!;

[JsonProperty("block_timestamp", Required = Required.Always)]
public string BlockTimestamp { get; set; } = null!;

[JsonProperty("hash", Required = Required.Always)]
public string Hash { get; set; } = null!;

[JsonProperty("nonce", Required = Required.Always)]
public BigInteger Nonce { get; set; }

[JsonProperty("transaction_index", Required = Required.Always)]
public BigInteger TransactionIndex { get; set; }

[JsonProperty("from_address", Required = Required.Always)]
public string FromAddress { get; set; } = null!;

[JsonProperty("to_address", Required = Required.Always)]
public string ToAddress { get; set; } = null!;

[JsonProperty("value", Required = Required.Always)]
public BigInteger Value { get; set; }

[JsonProperty("gas_price", Required = Required.Always)]
public BigInteger GasPrice { get; set; }

[JsonProperty("gas", Required = Required.Always)]
public BigInteger Gas { get; set; }

[JsonProperty("function_selector", Required = Required.Always)]
public string FunctionSelector { get; set; } = null!;

[JsonProperty("data", Required = Required.Always)]
public string Data { get; set; } = null!;

[JsonProperty("max_fee_per_gas", Required = Required.Always)]
public BigInteger MaxFeePerGas { get; set; }

[JsonProperty("max_priority_fee_per_gas", Required = Required.Always)]
public BigInteger MaxPriorityFeePerGas { get; set; }

[JsonProperty("transaction_type", Required = Required.Always)]
public BigInteger TransactionType { get; set; }

[JsonProperty("r", Required = Required.Always)]
public BigInteger R { get; set; }

[JsonProperty("s", Required = Required.Always)]
public BigInteger S { get; set; }

[JsonProperty("v", Required = Required.Always)]
public BigInteger V { get; set; }

[JsonProperty("access_list_json")]
public string AccessListJson { get; set; }

[JsonProperty("contract_address")]
public string ContractAddress { get; set; }

[JsonProperty("gas_used")]
public BigInteger? GasUsed { get; set; }

[JsonProperty("cumulative_gas_used")]
public BigInteger? CumulativeGasUsed { get; set; }

[JsonProperty("effective_gas_price")]
public BigInteger? EffectiveGasPrice { get; set; }

[JsonProperty("blob_gas_used")]
public BigInteger? BlobGasUsed { get; set; }

[JsonProperty("blob_gas_price")]
public BigInteger? BlobGasPrice { get; set; }

[JsonProperty("logs_bloom")]
public string LogsBloom { get; set; }

[JsonProperty("status")]
public BigInteger? Status { get; set; }
}

public class Decoded
{
[JsonProperty("name")]
Expand Down
92 changes: 92 additions & 0 deletions Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public class InsightEvents
public Meta Meta { get; set; }
}

public class InsightTransactions
{
public Transaction[] Transactions { get; set; }
public Meta Meta { get; set; }
}

public class ThirdwebInsight
{
private readonly IThirdwebHttpClient _httpClient;
Expand Down Expand Up @@ -234,6 +240,92 @@ public async Task<InsightEvents> GetEvents(
return new InsightEvents { Events = result.Data, Meta = result.Meta, };
}

/// <summary>
/// Get transactions, optionally filtered by contract address, signature, and more.
/// </summary>
/// <param name="chainIds">The chain IDs to get the transactions from.</param>
/// <param name="contractAddress">The contract address to get the transactions from. (Optional)</param>
/// <param name="signature">The signature to filter transactions by. (Optional)</param>
/// <param name="fromBlock">The starting block number to get the transactions from. (Optional, if provided, said block is included in query)</param>
/// <param name="toBlock">The ending block number to get the transactions from. (Optional, if provided, said block is included in query)</param>
/// <param name="fromTimestamp">The starting block timestamp to get the transactions from. (Optional, if provided, said block is included in query)</param>
/// <param name="toTimestamp">The ending block timestamp to get the transactions from. (Optional, if provided, said block is included in query)</param>
/// <param name="sortBy">The field to sort the transactions by. (Default: BlockNumber)</param>
/// <param name="sortOrder">The order to sort the transactions by. (Default: Desc)</param>
/// <param name="limit">The number of transactions to return. (Default: 20)</param>
/// <param name="page">The page number to return. (Default: 0)</param>
/// <param name="decode">Whether to decode the transactions. (Default: true)</param>
/// <returns>The transactions and metadata as an instance of <see cref="InsightTransactions"/>.</returns>
/// <exception cref="ArgumentException">Thrown when a signature is provided without a contract address.</exception>
/// /// <exception cref="ArgumentException">Thrown when no chain IDs are provided.</exception>
public async Task<InsightTransactions> GetTransactions(
BigInteger[] chainIds,
string contractAddress = null,
string signature = null,
BigInteger? fromBlock = null,
BigInteger? toBlock = null,
BigInteger? fromTimestamp = null,
BigInteger? toTimestamp = null,
SortBy sortBy = SortBy.BlockNumber,
SortOrder sortOrder = SortOrder.Desc,
int limit = 20,
int page = 0,
bool decode = true
)
{
if (!string.IsNullOrEmpty(signature) && string.IsNullOrEmpty(contractAddress))
{
throw new ArgumentException("Contract address must be provided when signature is provided.");
}

if (chainIds.Length == 0)
{
throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds));
}

var baseUrl = $"{Constants.INSIGHT_API_URL}/v1/transactions";
var url = AppendChains(
!string.IsNullOrEmpty(contractAddress)
? !string.IsNullOrEmpty(signature)
? $"{baseUrl}/{contractAddress}/{signature}"
: $"{baseUrl}/{contractAddress}"
: baseUrl,
chainIds
);

url += $"&sort_by={SortByToString(sortBy)}";
url += $"&sort_order={SortOrderToString(sortOrder)}";
url += $"&limit={limit}";
url += $"&page={page}";
url += $"&decode={decode}";

if (fromBlock.HasValue)
{
url += $"&filter_block_number_gte={fromBlock}";
}

if (toBlock.HasValue)
{
url += $"&filter_block_number_lte={toBlock}";
}

if (fromTimestamp.HasValue)
{
url += $"&filter_block_timestamp_gte={fromTimestamp}";
}

if (toTimestamp.HasValue)
{
url += $"&filter_block_timestamp_lte={toTimestamp}";
}

var response = await this._httpClient.GetAsync(url).ConfigureAwait(false);
_ = response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var result = JsonConvert.DeserializeObject<ResponseModel<Transaction>>(responseContent);
return new InsightTransactions { Transactions = result.Data, Meta = result.Meta, };
}

private static string AppendChains(string url, BigInteger[] chainIds)
{
return $"{url}?chain={string.Join("&chain=", chainIds)}";
Expand Down

0 comments on commit f6b25d5

Please sign in to comment.