Stellar - Horizon API メモ

クライアントアプリケーション向けに、
Stellarネットワークへの(たぶん)親切なインタフェースを提供するアレ

トランザクション発行、台帳やアカウントの確認、イベント購読とかできる。

発端

インフレーションを設定していると、チョロチョロとLumen/ルーメン(XLM)が増えていきます。
Stellar.ExpertあたりでCSVダウンロードできると楽なのだが、まだ出来なくてめんどくさいな、と思っていた折
SatoshiPayさんがStellar の full validator (Stellar Nodeにはいくつか役割がある) を運用し始めた。とのアナウンスがあり、用意されたAPIエンドポイント使ってもよさそうだったのが発端

SDK

API直接たたいても良いけど、SDKもあるよ。
Go, Java, JavaScript用が公式。それ以外はコミュニティベース。
最近は にわかC#erなのでこれを使う。

APIのレスポンスJSONがなんか親切なフォーマットしているので、ちょっとした処理ならSDKは不要かもしれない。

C#コードからHorizon APIを叩く

準備

このパッケージを使います。

using stellar_dotnet_sdk;
using stellar_dotnet_sdk.requests;
using stellar_dotnet_sdk.responses;
using stellar_dotnet_sdk.responses.effects;

サーバの指定。今回はSatoshiPayのを使う。

Network.UsePublicNetwork();
Server server = new Server(@"https://stellar-horizon.satoshipay.io/");

対象のアカウント

KeyPair keypair = KeyPair.FromAccountId(@"<Stellar アカウント>");

XLMの流れを追う

オペレーションの結果、そのアカウントにどのような変化が生じたかはEffectという形で取得できる。
このうち、XLMの増減に関わるのは以下である。

  1. Account Created
  2. Account Credited
  3. Account Debited
  4. Trade

今回はSDEXしていないので、上三つを抽出する

var effectResponse = server.Effects.ForAccount(keypair)
                         // 一回の要求でいくつの Effectを取得するか. あんまり大きい値にしない
                         .Limit(100)
                         // 最古から昇順で得る. 最新から得る場合は DESC にする
                         .Order(OrderDirection.ASC)
                         // Execute()は Taskを返す. 同期で待つ.
                         .Execute().Result;
// RecordsがEffectのList
foreach (var effect in effectResponse.Records)
{
    // CreatedAtが日時(UTC), TypeがEffect種類
    // 日時は, ISO8601形式の文字列で出力. DateTime(UTC)なので形式のみ真似る
    string output = effect.CreatedAt.ToString(@"yyyy-MM-dd'T'HH:mm:ss'Z'") + "," + effect.Type + ",";
    string balance = "";
    switch (effect)
    {
        case AccountCreatedEffectResponse e:
            // StartingBalance で流入量を得る
            balance = e.StartingBalance;
            break;
        case AccountCreditedEffectResponse e:
            // Amount で流入量を得る
            balance = e.Amount;
            break;
        case AccountDebitedEffectResponse e:
            // Amount で流出量を得る. -(マイナス)付けたほうが良いかもしれない
            balance = e.Amount;
            break;
        default:
            break;
    }

    Console.WriteLine(output + balance);
}

// 必要分足りなければ effectResponse.NextPage() で次の要求Taskが得られる.

上記のEffectは手数料を含まない。
手数料はトランザクションの発行者(SourceAccount)から引かれるので、
発行した覚えがあるなら、その分のXLMが減っているはずだ。

// Effect とほぼ同じ
var transactionResponse = server.Transactions.ForAccount(keypair)
                              .Limit(100)
                              .Order(OrderDirection.ASC)
                              .Execute().Result;
// RecordsがTransactionのList
foreach (var tx in transactionResponse.Records)
{
    // SourceAccount が Fee を負担する
    if (tx.SourceAccount.Address == keypair.Address)
    {
        // 日時が文字列型(ISO8601形式)なのでそのまま
        // FeePaid は stroop単位(1000万stroop = 1 XLM) -> XLM表記(1/1000万)にする
        Console.WriteLine(tx.CreatedAt + "," + $"0.{tx.FeePaid:0000000}");
    }
}

その他

700GBですか


See also