- Fix (Richard): MaxBuyPrice-Skalen-Korrektur analog PreRedeemLimit (Migration FixMaxBuyPriceScale: Werte > 1 wie 98.0/99.0 -> /100 = 0.98/0.99; auf MySQL angewendet). Cap greift bei den betroffenen Accounts jetzt wieder. Beschreibung des Feldes um den Skalen-Hinweis ergaenzt. - Testnetz erweitert: reine Klasse BlockchainSubscription (Logic/) fuer das Alchemy-Abo (PadAddress + Filter-Batching in 3er-Chunks, Buy=Topic3/Sell=Topic2 je Chunk). AlchemyWebsocketService ruft sie jetzt (verhaltensneutral; Konstanten + lokale Methoden entfernt). BlockchainSubscriptionTests: 13 Faelle (Padding, Chunk-Anzahl 0/1/3/4/6/7, Topic-Zuordnung, CTF-Adresse/Topics). Gesamt 137 Tests gruen. Build/Smoke gruen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
98 lines
3.6 KiB
C#
98 lines
3.6 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using PolyTrader.Modules.CopyTrading.Logic;
|
|
using PolyTraderSharp.Models;
|
|
using Xunit;
|
|
|
|
namespace PolyTrader.Tests
|
|
{
|
|
/// <summary>
|
|
/// Sichert den Aufbau des Alchemy-Blockchain-Abos ab: falsche Filter/Padding bedeuten
|
|
/// verpasste (oder falsch zugeordnete) Master-Trades.
|
|
/// </summary>
|
|
public class BlockchainSubscriptionTests
|
|
{
|
|
private static List<TrackedTrader> Traders(int n) =>
|
|
Enumerable.Range(1, n).Select(i => new TrackedTrader { Id = i, WalletAddress = $"0x{i:x40}" }).ToList();
|
|
|
|
// ---------------- PadAddress ----------------
|
|
|
|
[Fact]
|
|
public void PadAddress_strips_prefix_lowercases_and_pads_to_32_bytes()
|
|
{
|
|
var r = BlockchainSubscription.PadAddress("0x628914CF1e96A9D1Ab8F0489A9f64be5633bac41");
|
|
Assert.Equal("0x000000000000000000000000628914cf1e96a9d1ab8f0489a9f64be5633bac41", r);
|
|
Assert.Equal(66, r.Length); // "0x" + 64 Hex-Zeichen
|
|
}
|
|
|
|
[Fact]
|
|
public void PadAddress_pads_short_input_with_leading_zeros()
|
|
{
|
|
Assert.Equal("0x" + new string('0', 61) + "abc", BlockchainSubscription.PadAddress("0xABC"));
|
|
}
|
|
|
|
// ---------------- Build: Chunk-Anzahl ----------------
|
|
|
|
[Theory]
|
|
[InlineData(0, 0)]
|
|
[InlineData(1, 2)] // 1 Chunk -> Buy + Sell
|
|
[InlineData(3, 2)] // 1 Chunk (voll)
|
|
[InlineData(4, 4)] // 2 Chunks (3 + 1)
|
|
[InlineData(6, 4)] // 2 Chunks (3 + 3)
|
|
[InlineData(7, 6)] // 3 Chunks (3 + 3 + 1)
|
|
public void Build_creates_two_filters_per_chunk(int traderCount, int expectedFilters)
|
|
{
|
|
Assert.Equal(expectedFilters, BlockchainSubscription.Build(Traders(traderCount)).Filters.Count);
|
|
}
|
|
|
|
// ---------------- Build: Filter-Inhalt ----------------
|
|
|
|
[Fact]
|
|
public void Build_pairs_buy_topic3_and_sell_topic2()
|
|
{
|
|
var sub = BlockchainSubscription.Build(Traders(1));
|
|
var buy = sub.Filters[0];
|
|
var sell = sub.Filters[1];
|
|
|
|
Assert.NotNull(buy.Topic3);
|
|
Assert.Null(buy.Topic2);
|
|
Assert.NotNull(sell.Topic2);
|
|
Assert.Null(sell.Topic3);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_sets_ctf_address_and_transfer_topics()
|
|
{
|
|
var buy = BlockchainSubscription.Build(Traders(1)).Filters[0];
|
|
Assert.Equal(BlockchainSubscription.CtfContractAddress, buy.Address);
|
|
Assert.Equal(
|
|
new[] { BlockchainSubscription.TransferSingleTopic, BlockchainSubscription.TransferBatchTopic },
|
|
buy.Topic0.ToArray());
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_chunks_addresses_by_three()
|
|
{
|
|
var sub = BlockchainSubscription.Build(Traders(4)); // 3 + 1
|
|
Assert.Equal(3, sub.Filters[0].Topic3!.Count); // Chunk 1 (Buy)
|
|
Assert.Equal(3, sub.Filters[1].Topic2!.Count); // Chunk 1 (Sell)
|
|
Assert.Single(sub.Filters[2].Topic3!); // Chunk 2 (Buy)
|
|
Assert.Single(sub.Filters[3].Topic2!); // Chunk 2 (Sell)
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_uses_padded_addresses()
|
|
{
|
|
var addr = BlockchainSubscription.Build(Traders(1)).Filters[0].Topic3![0];
|
|
Assert.Equal(66, addr.Length);
|
|
Assert.StartsWith("0x", addr);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_empty_returns_no_filters()
|
|
{
|
|
Assert.Empty(BlockchainSubscription.Build(Traders(0)).Filters);
|
|
}
|
|
}
|
|
}
|