SolanaFM
Search
K

Extract Money Flows from Transactions

Typescript Reference Example

import { ConfirmedSignatureInfo, ParsedInstruction, ParsedTransactionWithMeta, PartiallyDecodedInstruction } from "@solana/web3.js";
import got from 'got';
const solanaWeb3 = require('@solana/web3.js');
const connection = new solanaWeb3.Connection(
solanaWeb3.clusterApiUrl('mainnet-beta'),
'confirmed'
);
interface Transfer {
instructionIndex: number;
innerInstructionIndex: number;
action: string;
status: string;
source: string;
sourceAssociation: string | null;
destination: string | null;
destinationAssociation: string | null;
token: string;
amount: number;
timestamp: number;
}
interface TransferApiResponse {
status: string;
message: string;
result: Transfer[];
}
async function getTransfers(transactionHash: string | string[]): Promise<Transfer[]> {
const url = `https://api.solana.fm/v0/transfers`;
try {
const response = await got.post(url, { json:
{
transactionHashes: (transactionHash instanceof String) ? [transactionHash] : transactionHash
}
}).json<TransferApiResponse>();
if (response.status === 'Success') {
return response.result;
} else {
throw new Error(response.message);
}
} catch (error) {
console.error('Error fetching transfers:', error);
throw error;
}
}
export async function GET(request: Request) {
const accountAddress = new URL(request.url).searchParams.get('accountAddress');
if (!accountAddress)
return
const publicKey = new solanaWeb3.PublicKey(accountAddress);
try {
const confirmedSignatures: string[] = (await connection.getConfirmedSignaturesForAddress2(
publicKey,
{
limit: 10
}
)).map((csi: ConfirmedSignatureInfo) => {
return csi.signature
});
let incomingTransactions: Transfer[] = await getTransfers(confirmedSignatures)
return new Response(JSON.stringify(incomingTransactions));
} catch (error) {
console.error('Error fetching transactions:', error);
return { error: 'Error fetching transactions' };
}
}

C# Reference Example

using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using System.Text;
using System.Text.Json.Serialization;
namespace SFMApiSample.Controllers
{
[ApiController]
[Route("[controller]")]
public class TxController : ControllerBase
{
private const string SignatureName = "signature";
private static readonly string SolanaRpcUrl = "https://api.mainnet-beta.solana.com";
private static readonly HttpClient HttpClient = new HttpClient();
private readonly ILogger<TxController> _logger;
public class TransferData
{
public int InstructionIndex { get; set; }
public int InnerInstructionIndex { get; set; }
public string Action { get; set; }
public string Status { get; set; }
public string Source { get; set; }
public string SourceAssociation { get; set; }
public string Destination { get; set; }
public string DestinationAssociation { get; set; }
public string Token { get; set; }
public decimal Amount { get; set; }
public long Timestamp { get; set; }
}
public class Transfer
{
[JsonPropertyName("transactionHash")]
public string TransactionHash { get; set; }
public List<TransferData> Data { get; set; }
}
public class TransferApiResponse
{
public string Status { get; set; }
public string Message { get; set; }
public List<Transfer> Result { get; set; }
}
public TxController(ILogger<TxController> logger)
{
_logger = logger;
}
public async Task<List<Transfer>> GetTransfersAsync(List<string> transactionHashes)
{
var url = "https://api.solana.fm/v0/transfers";
var content = new StringContent(JsonSerializer.Serialize(new { transactionHashes }), Encoding.UTF8, "application/json");
try
{
var response = await HttpClient.PostAsync(url, content);
var responseContent = await response.Content.ReadAsStringAsync();
var transferApiResponse = JsonSerializer.Deserialize<TransferApiResponse>(responseContent, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
if (transferApiResponse.Status == "Success")
{
return transferApiResponse.Result;
}
else
{
throw new Exception(transferApiResponse.Message);
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error fetching transfers: {ex}");
throw;
}
}
private async Task<List<string>> GetConfirmedSignaturesForAddress2Async(string accountAddress, int limit = 10)
{
var requestBody = new
{
jsonrpc = "2.0",
id = 1,
method = "getConfirmedSignaturesForAddress2",
@params = new object[]
{
accountAddress,
new { limit }
}
};
var content = new StringContent(JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json");
var response = await HttpClient.PostAsync(SolanaRpcUrl, content);
var responseContent = await response.Content.ReadAsStringAsync();
var jsonDocument = JsonDocument.Parse(responseContent);
var signaturesArray = jsonDocument.RootElement.GetProperty("result");
var signatureList = new List<string>();
foreach (var signature in signaturesArray.EnumerateArray())
{
signatureList.Add(signature.GetProperty(SignatureName).GetString());
}
return signatureList;
}
[HttpGet("{accountAddress}")]
public async Task<string> Get(string accountAddress)
{
if (string.IsNullOrEmpty(accountAddress))
return string.Empty;
try
{
var confirmedSignatures = await GetConfirmedSignaturesForAddress2Async(accountAddress);
var incomingTransactions = await GetTransfersAsync(confirmedSignatures);
return JsonSerializer.Serialize(incomingTransactions);
}
catch (Exception ex)
{
_logger.LogError($"Error fetching transactions: {ex}");
return string.Empty;
}
}
}
}