版本 1.0.0-rc8:卖货橱窗重构、收款币种、Gas 档位速度、区块自然增长、钱包持仓

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-05 21:32:30 +08:00
1 parent 018ee7d0d2
commit 93e26fc4f5
20 files changed
+582 -498

No files matched your search

+51 -24
View File
@@ -24,8 +24,14 @@ namespace Decentralized.Domain
/// <summary>成交后扣掉抽成的货款(信用点)与其中带的污点。</summary>
public int Proceeds;
public double Taint;
/// <summary>成交那一轮的收款币(空 = CRT,旧存档):货款到期后以这个币付给钱包。</summary>
public string PayAsset;
/// <summary>终态原因:fake(买家看穿假卡退货)/ rug / delist。</summary>
public string Why;
/// <summary>聚合键:同一种商品(标识、型号、真伪、成色取整)算一组,同组倍率相同。</summary>
public static string KeyOf(string item, string model, string fakeOf, double health) => item + "|" + model + "|" + fakeOf + "|" + Math.Round(health);
public string Key => KeyOf(Item, Model, FakeOf, Health);
}
public sealed partial class BlackMarket
@@ -57,7 +63,41 @@ namespace Decentralized.Domain
return Math.Min(Tuning.BmVolumeTaintMax, v / Tuning.BmVolumeRef * Tuning.BmVolumeTaintMax);
}
/// <summary>收款币:愿意接受的币(存档),至少一种;默认只有 CRT。</summary>
public List<string> SellAccepts = new List<string> { Assets.CRT };
public static readonly string[] SellCoins = { Assets.PSC, Assets.CRT, Assets.CRA, Assets.Ponero };
public static double CoinWeight(string asset) =>
asset == Assets.PSC ? Tuning.BmWeightPsc : asset == Assets.CRT ? Tuning.BmWeightCrt : asset == Assets.CRA ? Tuning.BmWeightCra : asset == Assets.Ponero ? Tuning.BmWeightPonero : 0;
public IEnumerable<string> AcceptedCoins => SellAccepts.Count == 0 ? new[] { Assets.CRT } : SellAccepts.Where(a => CoinWeight(a) > 0).Distinct().ToArray();
/// <summary>开关一种收款币;最后一种不能关掉。</summary>
public bool ToggleCoin(string asset)
{
if (SellAccepts.Count == 0) SellAccepts.Add(Assets.CRT);
if (SellAccepts.Contains(asset)) { if (SellAccepts.Count <= 1) return false; SellAccepts.Remove(asset); return true; }
if (CoinWeight(asset) <= 0) return false;
SellAccepts.Add(asset);
return true;
}
/// <summary>在架的件数(全部)、种数、某一组的件数与倍率(没有在架返回 null)。</summary>
public int ActiveListings => Sales.Count(x => x.State == SaleState.Listed);
public int ActiveKinds => Sales.Where(x => x.State == SaleState.Listed).Select(x => x.Key).Distinct().Count();
public int ActiveOf(string key) => Sales.Count(x => x.State == SaleState.Listed && x.Key == key);
public double? MultOf(string key) { var s = Sales.FirstOrDefault(x => x.State == SaleState.Listed && x.Key == key); return s == null ? (double?)null : s.Mult; }
/// <summary>某一组再上架 add 件、倍率 m 时的限制:null = 可以;stack = 超过每种上限;kinds = 超过种数上限;mult = 与已在架的同种货倍率不同。</summary>
public string ListBlock(string key, double m, int add = 1)
{
int have = ActiveOf(key);
if (have + add > Tuning.BmMaxStack) return "stack";
if (have == 0 && ActiveKinds >= Tuning.BmMaxKinds) return "kinds";
var cur = MultOf(key);
if (cur != null && Math.Abs(cur.Value - m) > 1e-9) return "mult";
return null;
}
public static int ListPriceOf(long refValue, double m) => (int)Math.Max(1, Math.Round(refValue * m));
public static int ListFee(int listPrice) => (int)Math.Ceiling(listPrice * Tuning.BmListFee);
@@ -65,7 +105,7 @@ namespace Decentralized.Domain
/// <summary>上架:交付一件货,收上架费(付给 feeAsset 币,污点与成本按比例带走)。倍率超出范围、平台关闭或余额不足返回 null。</summary>
public BmSale List(string item, string model, string fakeOf, double health, long refValue, double m, Wallet w, string feeAsset, int day, Func<string, double> price)
{
if (m < Tuning.BmSellMin - 1e-9 || m > Tuning.BmSellMax + 1e-9 || refValue <= 0 || Closed(day) || feeAsset == Assets.CRC || ActiveListings >= Tuning.BmMaxListings) return null;
if (m < Tuning.BmSellMin - 1e-9 || m > Tuning.BmSellMax + 1e-9 || refValue <= 0 || Closed(day) || feeAsset == Assets.CRC || ListBlock(BmSale.KeyOf(item, model, fakeOf, health), m) != null) return null;
int listPrice = ListPriceOf(refValue, m);
double p = price(feeAsset);
if (p <= 0) return null;
@@ -80,26 +120,6 @@ namespace Decentralized.Domain
return s;
}
public static int RepriceFee(int newPrice) => (int)Math.Ceiling(newPrice * Tuning.BmRepriceFee);
/// <summary>改价:上架中的货换一个倍率,按参考价重算标价,收改价费;不改变上架日。</summary>
public bool Reprice(BmSale s, double m, Wallet w, string feeAsset, int day, Func<string, double> price)
{
if (s == null || s.State != SaleState.Listed || s.Ref <= 0 || Math.Abs(m - s.Mult) < 1e-9 || m < Tuning.BmSellMin - 1e-9 || m > Tuning.BmSellMax + 1e-9 || Closed(day) || feeAsset == Assets.CRC) return false;
int listPrice = ListPriceOf(s.Ref, m);
double p = price(feeAsset);
if (p <= 0) return false;
int fee = RepriceFee(listPrice);
double qty = fee / p;
if (w.Avail(feeAsset) + 1e-9 < qty) return false;
double total = w.Value(price);
double share = total > 0 ? Math.Min(1, fee / total) : 0;
w.Taint -= w.Taint * share; w.Basis -= w.Basis * share;
w.Add(feeAsset, -qty);
s.Mult = m; s.ListPrice = listPrice;
return true;
}
public void Delist(BmSale s) { s.State = SaleState.Delisted; s.Why = "delist"; }
/// <summary>未到账的货款(信用点):跑路时一并归零,也推高跑路概率。</summary>
@@ -111,7 +131,13 @@ namespace Decentralized.Domain
if (crackdown) return;
foreach (var s in Sales.Where(x => x.State == SaleState.Listed && x.ListedDay < day).ToList())
{
if (!rng.Chance(SaleChance(s.Mult))) continue;
// 每接受一种币算一轮成交:轮次顺序随机,任一轮命中即成交,货款用命中的币付
string hit = null;
double chance = SaleChance(s.Mult);
foreach (var c in AcceptedCoins.OrderBy(_ => rng.NextDouble()).ToList())
if (rng.Chance(Math.Min(1, chance * CoinWeight(c)))) { hit = c; break; }
if (hit == null) continue;
s.PayAsset = hit;
if (s.FakeOf != null && rng.Chance(Tuning.BmFakeDetect))
{
s.State = SaleState.Delisted; s.Why = "fake";
@@ -130,10 +156,11 @@ namespace Decentralized.Domain
}
foreach (var s in Sales.Where(x => x.State == SaleState.Sold && day >= x.PayDay).ToList())
{
double p = price(Assets.CRT);
string pa = s.PayAsset ?? Assets.CRT;
double p = price(pa);
if (p <= 0) continue;
var w = wallet(s.Wallet);
w.Add(Assets.CRT, s.Proceeds / p);
w.Add(pa, s.Proceeds / p);
w.Taint += s.Taint;
w.Basis += s.Proceeds;
s.State = SaleState.Paid;
+11 -3
View File
@@ -134,16 +134,22 @@ namespace Decentralized.Domain
public const double BmTrapShare = 0.4, BmTrapWindowCap = 400;
/// <summary>货架上除违禁品外的两类货:高科技物品(需中档声望)和显卡的出现概率、加价(在现货溢价 / 订单价之外再加),显卡里夹假卡的比例、是全新卡(成色 100、封条完好、不会是假卡)的概率。</summary>
public const double BmTechChance = 0.30, BmGpuChance = 0.30, BmTechMarkup = 0.5, BmGpuMarkup = 0.2, BmGpuFake = 0.20, BmGpuNew = 0.15;
/// <summary>玩家上架出售:标价倍率范围(相对参考价)、上架费、改价费、成交抽成、成交后货款托管天数、假卡被买家看穿的概率;
/// <summary>玩家上架出售:标价倍率范围(相对参考价)、上架费、成交抽成、成交后货款托管天数、假卡被买家看穿的概率;
/// 倍率 ≤0.9 / 1.0 / 1.8 时的期望成交天数(之间插值);货款带污点的概率与比例随倍率从下限涨到上限;卖家好评的初始值、看穿一次扣的点数、同时上架的件数上限。</summary>
public const double BmListFee = 0.05, BmRepriceFee = 0.02, BmCommission = 0.08, BmSellMin = 0.6, BmSellMax = 1.8, BmFakeDetect = 0.5;
public const double BmListFee = 0.05, BmCommission = 0.08, BmSellMin = 0.6, BmSellMax = 1.8, BmFakeDetect = 0.5;
/// <summary>出售成交天数的倍率界线:不高于 BmSellFastMult 倍用 BmSellDaysFast 天,BmSellDay1Mult 倍用 BmSellDays1 天,之间线性,再往上指数到 BmSellMax。</summary>
public const double BmSellFastMult = 0.9, BmSellDay1Mult = 1.0;
/// <summary>出售页可选的标价倍率档位。</summary>
public static readonly double[] BmSellMults = { 0.6, 0.8, 0.9, 1.0, 1.2, 1.5, 1.8 };
public const double BmSellDaysFast = 1, BmSellDays1 = 2, BmSellDaysMax = 14;
public const double BmSaleTaintChanceMin = 0.2, BmSaleTaintChanceMax = 0.9, BmSaleTaintRatioMin = 0.2, BmSaleTaintRatioMax = 0.8;
public const int BmSaleHold = 3, BmRatingStart = 90, BmRatingFakeLoss = 10, BmMaxListings = 10;
public const int BmSaleHold = 3, BmRatingStart = 90, BmRatingFakeLoss = 10;
/// <summary>同时上架的货:最多几种(按商品标识),每种最多几件。</summary>
public const int BmMaxKinds = 6, BmMaxStack = 5;
/// <summary>收款币的买家权重:每接受一种币,夜间多一轮成交判定,轮次概率 = 成交概率 × 权重(CRT 为 1 即原有节奏)。</summary>
public const double BmWeightPsc = 0.8, BmWeightCrt = 1, BmWeightCra = 0.6, BmWeightPonero = 0.4;
/// <summary>PLEDGER 区块高度每晚自然增长的范围(区块数,含两端)。</summary>
public const int BlocksPerDayMin = 120, BlocksPerDayMax = 170;
/// <summary>商家货架:每周的商家数(其中 2 家从矿卡 / 矿架 / 模组 4 类里抽,其余从其他类型里抽)、每家的货种数、每种货的库存范围;大宗商家出现概率、库存范围、送货天数;
/// 各类商家的价格系数范围(订单价 = 基础价 × 系数);批量折扣档(件数、折扣)。</summary>
public const int BmMerchantCount = 7, BmCoreMerchants = 2, BmMerchantListings = 3, BmQtyMin = 2, BmQtyMax = 6, BmBulkQtyMin = 10, BmBulkQtyMax = 25, BmBulkDays = 6;
@@ -174,6 +180,8 @@ namespace Decentralized.Domain
/// <summary>转账手续费(信用点等值,按转出的币扣):慢 / 普通 / 快;拥堵时乘以倍数。</summary>
public const double TxFeeSlow = 0.5, TxFeeNormal = 1.5, TxFeeFast = 4, TxCongestedFeeMult = 4;
/// <summary>Gas 档位的确认速度倍数(时间乘它):Gas 越高确认越快、进度条走得越快;Poinbase 出金固定普通档。</summary>
public const double TxSpeedSlow = 1.5, TxSpeedNormal = 1, TxSpeedFast = 0.5;
/// <summary>Gas 价格指数:以 GasPeriod 天为周期正弦涨跌,振幅 GasAmp(0.5×–1.5×),每天再乘 1 ± GasNoise 的随机波动。</summary>
public const int TxGasPeriod = 7;
public const double TxGasAmp = 0.5, TxGasNoise = 0.15;
+11 -2
View File
@@ -38,6 +38,8 @@ namespace Decentralized.Domain
["AsicWeightM2"] = Tuning.AsicWeightM2,
["AsicWeightM3"] = Tuning.AsicWeightM3,
["BlockReward"] = Tuning.BlockReward,
["BlocksPerDayMax"] = Tuning.BlocksPerDayMax,
["BlocksPerDayMin"] = Tuning.BlocksPerDayMin,
["BmAdvanceDiscount"] = Tuning.BmAdvanceDiscount,
["BmAdvanceMinTrades"] = Tuning.BmAdvanceMinTrades,
["BmAutoSwapSlip"] = Tuning.BmAutoSwapSlip,
@@ -90,7 +92,8 @@ namespace Decentralized.Domain
["BmInterceptCrackdown"] = Tuning.BmInterceptCrackdown,
["BmInterceptDoor"] = Tuning.BmInterceptDoor,
["BmListFee"] = Tuning.BmListFee,
["BmMaxListings"] = Tuning.BmMaxListings,
["BmMaxKinds"] = Tuning.BmMaxKinds,
["BmMaxStack"] = Tuning.BmMaxStack,
["BmMaxUnitValue"] = Tuning.BmMaxUnitValue,
["BmMerchantCount"] = Tuning.BmMerchantCount,
["BmMerchantListings"] = Tuning.BmMerchantListings,
@@ -118,7 +121,6 @@ namespace Decentralized.Domain
["BmRatingFakeLoss"] = Tuning.BmRatingFakeLoss,
["BmRatingStart"] = Tuning.BmRatingStart,
["BmRefreshDays"] = Tuning.BmRefreshDays,
["BmRepriceFee"] = Tuning.BmRepriceFee,
["BmRugBase"] = Tuning.BmRugBase,
["BmRugClosedDays"] = Tuning.BmRugClosedDays,
["BmRugMax"] = Tuning.BmRugMax,
@@ -151,6 +153,10 @@ namespace Decentralized.Domain
["BmUnlockPrice"] = Tuning.BmUnlockPrice,
["BmVolumeRef"] = Tuning.BmVolumeRef,
["BmVolumeTaintMax"] = Tuning.BmVolumeTaintMax,
["BmWeightCra"] = Tuning.BmWeightCra,
["BmWeightCrt"] = Tuning.BmWeightCrt,
["BmWeightPonero"] = Tuning.BmWeightPonero,
["BmWeightPsc"] = Tuning.BmWeightPsc,
["CardBracketScratch"] = Tuning.CardBracketScratch,
["CardFanChipped"] = Tuning.CardFanChipped,
["CardFanDust"] = Tuning.CardFanDust,
@@ -397,6 +403,9 @@ namespace Decentralized.Domain
["TxPoisonChance"] = Tuning.TxPoisonChance,
["TxPoisonDelayMax"] = Tuning.TxPoisonDelayMax,
["TxSlowDrop"] = Tuning.TxSlowDrop,
["TxSpeedFast"] = Tuning.TxSpeedFast,
["TxSpeedNormal"] = Tuning.TxSpeedNormal,
["TxSpeedSlow"] = Tuning.TxSpeedSlow,
["UnlockPrice"] = Tuning.UnlockPrice,
["UsedFakeMiddleman"] = Tuning.UsedFakeMiddleman,
["UsedFakeScammer"] = Tuning.UsedFakeScammer,
+8 -2
View File
@@ -31,12 +31,18 @@ namespace Decentralized.Domain
public static int Confirmations(double valueCredits) =>
valueCredits >= Tuning.TxConfirmBigValue ? Tuning.TxConfirmBig : valueCredits >= Tuning.TxConfirmMidValue ? Tuning.TxConfirmMid : Tuning.TxConfirmBase;
/// <summary>每次确认的间隔倍数:拥堵时慢档、普通档变慢。</summary>
public static double Slowdown(FeeTier t, bool congested) => !congested ? 1 : t == FeeTier.Fast ? 1 : t == FeeTier.Normal ? Tuning.TxCongestedNormalSlow : Tuning.TxCongestedSlowSlow;
/// <summary>Gas 档位本身的速度倍数:越高越快。</summary>
public static double TierSpeed(FeeTier t) => t == FeeTier.Fast ? Tuning.TxSpeedFast : t == FeeTier.Normal ? Tuning.TxSpeedNormal : Tuning.TxSpeedSlow;
/// <summary>整条确认时间线的时间倍数:档位速度 × 拥堵时慢档、普通档变慢(快档不受拥堵影响)。</summary>
public static double Slowdown(FeeTier t, bool congested) => TierSpeed(t) * (!congested ? 1 : t == FeeTier.Fast ? 1 : t == FeeTier.Normal ? Tuning.TxCongestedNormalSlow : Tuning.TxCongestedSlowSlow);
/// <summary>拥堵时慢档交易被挤出内存池的概率(交易作废,手续费照扣)。</summary>
public static double DropChance(FeeTier t, bool congested) => congested && t == FeeTier.Slow ? Tuning.TxSlowDrop : 0;
/// <summary>夜间区块高度的自然增长。</summary>
public static int BlocksPerDay(Rng rng) => rng.Range(Tuning.BlocksPerDayMin, Tuning.BlocksPerDayMax);
/// <summary>转账记录最多保留几条。</summary>
public const int HistoryMax = 20;