@holoscript/std 6.0.3 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/{chunk-PFX2JM4X.js → chunk-FAMOLKH3.js} +2 -1
- package/dist/{chunk-PFX2JM4X.js.map → chunk-FAMOLKH3.js.map} +1 -1
- package/dist/{chunk-7HVUYGPS.js → chunk-SOKH6FJ7.js} +37 -5
- package/dist/chunk-SOKH6FJ7.js.map +1 -0
- package/dist/{chunk-W2Q3LUCM.js → chunk-XJIFG7G3.js} +3 -3
- package/dist/chunk-XJIFG7G3.js.map +1 -0
- package/dist/collections.cjs +1 -0
- package/dist/collections.cjs.map +1 -1
- package/dist/collections.js +2 -1
- package/dist/fs/fs.d.ts +288 -0
- package/dist/fs/fs.d.ts.map +1 -0
- package/dist/fs/index.cjs +1049 -0
- package/dist/fs/index.cjs.map +1 -0
- package/dist/fs/index.d.ts +51 -0
- package/dist/fs/index.d.ts.map +1 -0
- package/dist/fs/index.js +918 -0
- package/dist/fs/index.js.map +1 -0
- package/dist/fs/path.d.ts +135 -0
- package/dist/fs/path.d.ts.map +1 -0
- package/dist/fs/sandbox.d.ts +49 -0
- package/dist/fs/sandbox.d.ts.map +1 -0
- package/dist/fs/watch.d.ts +133 -0
- package/dist/fs/watch.d.ts.map +1 -0
- package/dist/index.cjs +54 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/dist/math.cjs +21 -2
- package/dist/math.cjs.map +1 -1
- package/dist/math.js +2 -1
- package/dist/string.cjs +2 -2
- package/dist/string.cjs.map +1 -1
- package/dist/string.js +2 -1
- package/dist/time.js +1 -0
- package/dist/traits/EconomicPrimitives.js +1 -0
- package/dist/traits/EconomicTraits.js +1 -0
- package/dist/traits/VRRTraits.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +24 -9
- package/CHANGELOG.md +0 -7
- package/dist/__tests__/EconomicPrimitives.test.d.ts +0 -2
- package/dist/__tests__/EconomicPrimitives.test.d.ts.map +0 -1
- package/dist/__tests__/EconomicTraits.test.d.ts +0 -2
- package/dist/__tests__/EconomicTraits.test.d.ts.map +0 -1
- package/dist/__tests__/SimulationLabPrimitives.test.d.ts +0 -2
- package/dist/__tests__/SimulationLabPrimitives.test.d.ts.map +0 -1
- package/dist/__tests__/collections.test.d.ts +0 -2
- package/dist/__tests__/collections.test.d.ts.map +0 -1
- package/dist/__tests__/events.test.d.ts +0 -2
- package/dist/__tests__/events.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/materials.test.d.ts +0 -2
- package/dist/__tests__/materials.test.d.ts.map +0 -1
- package/dist/__tests__/math.test.d.ts +0 -2
- package/dist/__tests__/math.test.d.ts.map +0 -1
- package/dist/__tests__/physics.test.d.ts +0 -2
- package/dist/__tests__/physics.test.d.ts.map +0 -1
- package/dist/__tests__/spatial.test.d.ts +0 -2
- package/dist/__tests__/spatial.test.d.ts.map +0 -1
- package/dist/__tests__/standard-library-fundamentals.test.d.ts +0 -2
- package/dist/__tests__/standard-library-fundamentals.test.d.ts.map +0 -1
- package/dist/__tests__/string-and-time-utilities.test.d.ts +0 -2
- package/dist/__tests__/string-and-time-utilities.test.d.ts.map +0 -1
- package/dist/__tests__/string-decoupled.test.d.ts +0 -2
- package/dist/__tests__/string-decoupled.test.d.ts.map +0 -1
- package/dist/__tests__/string.test.d.ts +0 -2
- package/dist/__tests__/string.test.d.ts.map +0 -1
- package/dist/__tests__/time.test.d.ts +0 -2
- package/dist/__tests__/time.test.d.ts.map +0 -1
- package/dist/chunk-7HVUYGPS.js.map +0 -1
- package/dist/chunk-W2Q3LUCM.js.map +0 -1
- package/dist/string.basic.test.d.ts +0 -5
- package/dist/string.basic.test.d.ts.map +0 -1
- package/dist/string.test.d.ts +0 -5
- package/dist/string.test.d.ts.map +0 -1
- package/dist/traits/__tests__/ARTraits.test.d.ts +0 -2
- package/dist/traits/__tests__/ARTraits.test.d.ts.map +0 -1
- package/dist/traits/__tests__/EconomicPrimitives.test.d.ts +0 -2
- package/dist/traits/__tests__/EconomicPrimitives.test.d.ts.map +0 -1
- package/dist/traits/__tests__/EconomicTraits.test.d.ts +0 -2
- package/dist/traits/__tests__/EconomicTraits.test.d.ts.map +0 -1
- package/error-utf8.log +0 -6
- package/error.log +0 -0
- package/src/__tests__/EconomicPrimitives.test.ts +0 -690
- package/src/__tests__/EconomicTraits.test.ts +0 -425
- package/src/__tests__/SimulationLabPrimitives.test.ts +0 -415
- package/src/__tests__/collections.test.ts +0 -182
- package/src/__tests__/events.test.ts +0 -135
- package/src/__tests__/index.test.ts +0 -14
- package/src/__tests__/materials.test.ts +0 -84
- package/src/__tests__/math.test.ts +0 -246
- package/src/__tests__/physics.test.ts +0 -83
- package/src/__tests__/spatial.test.ts +0 -333
- package/src/__tests__/standard-library-fundamentals.test.ts +0 -1301
- package/src/__tests__/string-and-time-utilities.test.ts +0 -1070
- package/src/__tests__/string-decoupled.test.ts +0 -14
- package/src/__tests__/string.test.ts +0 -164
- package/src/__tests__/time.test.ts +0 -110
- package/src/collections.ts +0 -850
- package/src/events.ts +0 -88
- package/src/index.ts +0 -474
- package/src/materials.ts +0 -109
- package/src/math.ts +0 -674
- package/src/physics.ts +0 -141
- package/src/spatial.ts +0 -320
- package/src/string.basic.test.ts +0 -14
- package/src/string.test.ts +0 -335
- package/src/string.ts +0 -531
- package/src/time.ts +0 -621
- package/src/traits/ARTraits.ts +0 -103
- package/src/traits/EconomicPrimitives.ts +0 -755
- package/src/traits/EconomicTraits.ts +0 -552
- package/src/traits/IoTTraits.ts +0 -102
- package/src/traits/SimulationLabPrimitives.ts +0 -650
- package/src/traits/SimulationLabTraits.ts +0 -191
- package/src/traits/VRRTraits.ts +0 -326
- package/src/traits/__tests__/ARTraits.test.ts +0 -14
- package/src/traits/__tests__/EconomicPrimitives.test.ts +0 -14
- package/src/traits/__tests__/EconomicTraits.test.ts +0 -14
- package/src/types.ts +0 -411
- package/std_error.log +0 -5
- package/tsconfig.json +0 -18
- package/tsup.config.ts +0 -17
- package/vitest.config.ts +0 -10
|
@@ -1,755 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Economic Primitives - Runtime math and types for virtual economy self-regulation
|
|
3
|
-
* @module @holoscript/std/economic
|
|
4
|
-
*
|
|
5
|
-
* Provides the mathematical building blocks for composable economic behaviors in HoloScript.
|
|
6
|
-
* These primitives implement research-proven mechanisms from control theory, DeFi AMMs,
|
|
7
|
-
* and progressive taxation -- adapted for spatial computing economies.
|
|
8
|
-
*
|
|
9
|
-
* References:
|
|
10
|
-
* - P.030.01: Dual-Loop PID Economy Controller (Alter Aeon model)
|
|
11
|
-
* - P.030.02: Bonding Curve Marketplace (DeFi AMM adaptation)
|
|
12
|
-
* - P.030.03: Progressive Wealth Recycling (logarithmic tax + UBI)
|
|
13
|
-
* - W.031: Faucet-Sink Ratio Is the Master Variable
|
|
14
|
-
* - W.032: Dual-Loop Feedback Control Solves Long-Term Stability
|
|
15
|
-
* - W.034: Wealth Tax > Income Tax for Virtual Gini Reduction
|
|
16
|
-
* - W.035: Bonding Curves Provide Intrinsic Price Discovery
|
|
17
|
-
*
|
|
18
|
-
* @version 1.0.0
|
|
19
|
-
* @category economic
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
// =============================================================================
|
|
23
|
-
// CORE TYPES
|
|
24
|
-
// =============================================================================
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Represents an in-world currency amount. Always positive.
|
|
28
|
-
* Uses number to stay compatible with HoloScript's numeric system.
|
|
29
|
-
*/
|
|
30
|
-
export type Currency = number;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* An agent identifier (player, NPC, or system account).
|
|
34
|
-
*/
|
|
35
|
-
export type AgentID = string;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Result type for economic operations that can fail.
|
|
39
|
-
*/
|
|
40
|
-
export type EconomicResult<T> = { ok: true; value: T } | { ok: false; error: EconomicError };
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Economic error codes.
|
|
44
|
-
*/
|
|
45
|
-
export type EconomicError =
|
|
46
|
-
| 'INSUFFICIENT_FUNDS'
|
|
47
|
-
| 'UNAUTHORIZED'
|
|
48
|
-
| 'INVALID_AMOUNT'
|
|
49
|
-
| 'BELOW_MINIMUM'
|
|
50
|
-
| 'ABOVE_MAXIMUM'
|
|
51
|
-
| 'ITEM_DESTROYED'
|
|
52
|
-
| 'TRANSFER_BLOCKED'
|
|
53
|
-
| 'CURVE_EXHAUSTED'
|
|
54
|
-
| 'PID_DIVERGED'
|
|
55
|
-
| 'TAX_EXEMPT'
|
|
56
|
-
| 'INVALID_PARAMETER';
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* RBAC permission categories needed for economic operations.
|
|
60
|
-
* These map to the existing HoloScript RBAC system (RBACTrait.ts).
|
|
61
|
-
*/
|
|
62
|
-
export type EconomicPermission =
|
|
63
|
-
| 'economy.trade' // Transfer items/currency between agents
|
|
64
|
-
| 'economy.mint' // Create new currency (faucet operation)
|
|
65
|
-
| 'economy.burn' // Destroy currency (sink operation)
|
|
66
|
-
| 'economy.set_price' // Modify prices on bonding curves
|
|
67
|
-
| 'economy.tax' // Levy and collect taxes
|
|
68
|
-
| 'economy.redistribute' // Distribute collected tax proceeds
|
|
69
|
-
| 'economy.tune_pid' // Modify PID controller parameters
|
|
70
|
-
| 'economy.audit' // View economic state and logs
|
|
71
|
-
| 'economy.*'; // Full economic authority
|
|
72
|
-
|
|
73
|
-
// =============================================================================
|
|
74
|
-
// TRADEABLE PRIMITIVES
|
|
75
|
-
// =============================================================================
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Ownership record for a tradeable entity.
|
|
79
|
-
*/
|
|
80
|
-
export interface OwnershipRecord {
|
|
81
|
-
/** Current owner */
|
|
82
|
-
owner: AgentID;
|
|
83
|
-
/** Transfer history (most recent first, capped at last 50) */
|
|
84
|
-
history: TransferRecord[];
|
|
85
|
-
/** Whether transfers are currently locked */
|
|
86
|
-
locked: boolean;
|
|
87
|
-
/** Optional lock reason */
|
|
88
|
-
lockReason?: string;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* A single transfer event in the ownership history.
|
|
93
|
-
*/
|
|
94
|
-
export interface TransferRecord {
|
|
95
|
-
from: AgentID;
|
|
96
|
-
to: AgentID;
|
|
97
|
-
price: Currency;
|
|
98
|
-
timestamp: number;
|
|
99
|
-
/** Transaction hash for integrity verification (P.030.04) */
|
|
100
|
-
txHash: string;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Generate a transaction hash from transfer details.
|
|
105
|
-
* Uses a simple deterministic hash for in-engine verification.
|
|
106
|
-
* NOT cryptographically secure -- server authority provides integrity (W.037).
|
|
107
|
-
*/
|
|
108
|
-
export function generateTxHash(
|
|
109
|
-
from: AgentID,
|
|
110
|
-
to: AgentID,
|
|
111
|
-
price: Currency,
|
|
112
|
-
timestamp: number
|
|
113
|
-
): string {
|
|
114
|
-
// Simple FNV-1a style hash for fast deterministic ID generation
|
|
115
|
-
let hash = 2166136261;
|
|
116
|
-
const input = `${from}:${to}:${price}:${timestamp}`;
|
|
117
|
-
for (let i = 0; i < input.length; i++) {
|
|
118
|
-
hash ^= input.charCodeAt(i);
|
|
119
|
-
hash = Math.imul(hash, 16777619);
|
|
120
|
-
}
|
|
121
|
-
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Execute a trade (transfer ownership for a price).
|
|
126
|
-
* Returns a new OwnershipRecord if successful.
|
|
127
|
-
*/
|
|
128
|
-
export function executeTrade(
|
|
129
|
-
record: OwnershipRecord,
|
|
130
|
-
buyer: AgentID,
|
|
131
|
-
price: Currency,
|
|
132
|
-
timestamp: number
|
|
133
|
-
): EconomicResult<OwnershipRecord> {
|
|
134
|
-
if (record.locked) {
|
|
135
|
-
return { ok: false, error: 'TRANSFER_BLOCKED' };
|
|
136
|
-
}
|
|
137
|
-
if (price < 0) {
|
|
138
|
-
return { ok: false, error: 'INVALID_AMOUNT' };
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const txHash = generateTxHash(record.owner, buyer, price, timestamp);
|
|
142
|
-
|
|
143
|
-
const transfer: TransferRecord = {
|
|
144
|
-
from: record.owner,
|
|
145
|
-
to: buyer,
|
|
146
|
-
price,
|
|
147
|
-
timestamp,
|
|
148
|
-
txHash,
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
// Keep history capped at 50 entries
|
|
152
|
-
const history = [transfer, ...record.history].slice(0, 50);
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
ok: true,
|
|
156
|
-
value: {
|
|
157
|
-
owner: buyer,
|
|
158
|
-
history,
|
|
159
|
-
locked: false,
|
|
160
|
-
},
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// =============================================================================
|
|
165
|
-
// DEPRECIATION PRIMITIVES
|
|
166
|
-
// =============================================================================
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Configuration for asset depreciation (hard sink mechanic).
|
|
170
|
-
*/
|
|
171
|
-
export interface DepreciationConfig {
|
|
172
|
-
/** Per-second decay rate (0.0 - 1.0). E.g., 0.001 = 0.1% per second */
|
|
173
|
-
decayRate: number;
|
|
174
|
-
/** Current condition (0.0 = destroyed, 1.0 = mint condition) */
|
|
175
|
-
condition: number;
|
|
176
|
-
/** Minimum condition before the item is considered destroyed */
|
|
177
|
-
destroyThreshold: number;
|
|
178
|
-
/** Whether repairs are allowed */
|
|
179
|
-
repairable: boolean;
|
|
180
|
-
/** Cost multiplier for repairs (relative to original value) */
|
|
181
|
-
repairCostMultiplier: number;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Default depreciation configuration.
|
|
186
|
-
*/
|
|
187
|
-
export const DEFAULT_DEPRECIATION: DepreciationConfig = {
|
|
188
|
-
decayRate: 0.0001, // 0.01% per second (~36% per hour)
|
|
189
|
-
condition: 1.0,
|
|
190
|
-
destroyThreshold: 0.01,
|
|
191
|
-
repairable: true,
|
|
192
|
-
repairCostMultiplier: 0.5,
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Calculate the current condition of an asset after elapsed time.
|
|
197
|
-
* Uses exponential decay: condition(t) = condition(0) * e^(-rate * elapsed)
|
|
198
|
-
*/
|
|
199
|
-
export function calculateDepreciation(
|
|
200
|
-
initialCondition: number,
|
|
201
|
-
decayRate: number,
|
|
202
|
-
elapsedSeconds: number
|
|
203
|
-
): number {
|
|
204
|
-
if (decayRate <= 0) return initialCondition;
|
|
205
|
-
if (elapsedSeconds <= 0) return initialCondition;
|
|
206
|
-
return initialCondition * Math.exp(-decayRate * elapsedSeconds);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Calculate the effective value of an asset based on condition.
|
|
211
|
-
* Value scales linearly with condition.
|
|
212
|
-
*/
|
|
213
|
-
export function depreciatedValue(baseValue: Currency, condition: number): Currency {
|
|
214
|
-
return baseValue * Math.max(0, Math.min(1, condition));
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Check if an asset has been destroyed by depreciation.
|
|
219
|
-
*/
|
|
220
|
-
export function isDestroyed(condition: number, threshold: number): boolean {
|
|
221
|
-
return condition <= threshold;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Calculate repair cost to restore an asset to full condition.
|
|
226
|
-
*/
|
|
227
|
-
export function calculateRepairCost(
|
|
228
|
-
baseValue: Currency,
|
|
229
|
-
currentCondition: number,
|
|
230
|
-
repairCostMultiplier: number
|
|
231
|
-
): Currency {
|
|
232
|
-
const conditionDeficit = 1.0 - Math.max(0, Math.min(1, currentCondition));
|
|
233
|
-
return baseValue * conditionDeficit * repairCostMultiplier;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// =============================================================================
|
|
237
|
-
// BONDING CURVE PRIMITIVES
|
|
238
|
-
// =============================================================================
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Bonding curve types with different economic properties.
|
|
242
|
-
*
|
|
243
|
-
* - linear: P = R * S (gentle, predictable)
|
|
244
|
-
* - exponential: P = R * S^n (early-adopter reward)
|
|
245
|
-
* - logarithmic: P = R * ln(S + 1) (stability-favoring)
|
|
246
|
-
* - sigmoid: P = R * S^n / (K^n + S^n) (bounded with plateau)
|
|
247
|
-
*/
|
|
248
|
-
export type BondingCurveType = 'linear' | 'exponential' | 'logarithmic' | 'sigmoid';
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Configuration for a bonding curve marketplace.
|
|
252
|
-
*/
|
|
253
|
-
export interface BondingCurveConfig {
|
|
254
|
-
/** Curve type */
|
|
255
|
-
curveType: BondingCurveType;
|
|
256
|
-
/** Reserve ratio (base price multiplier) */
|
|
257
|
-
reserveRatio: number;
|
|
258
|
-
/** Curve steepness (n in P = R * S^(1/n)) */
|
|
259
|
-
curveSteepness: number;
|
|
260
|
-
/** Current supply */
|
|
261
|
-
currentSupply: number;
|
|
262
|
-
/** Reserve pool balance (collateral backing the curve) */
|
|
263
|
-
reserveBalance: Currency;
|
|
264
|
-
/** Transaction fee percentage (hard sink, 0-1) */
|
|
265
|
-
transactionFee: number;
|
|
266
|
-
/** Half-saturation constant for sigmoid curves */
|
|
267
|
-
sigmoidK: number;
|
|
268
|
-
/** Optional spatial distance factor for VR marketplaces */
|
|
269
|
-
spatialDistanceFactor: number;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Default bonding curve configuration.
|
|
274
|
-
*/
|
|
275
|
-
export const DEFAULT_BONDING_CURVE: BondingCurveConfig = {
|
|
276
|
-
curveType: 'exponential',
|
|
277
|
-
reserveRatio: 1.0,
|
|
278
|
-
curveSteepness: 2.0,
|
|
279
|
-
currentSupply: 0,
|
|
280
|
-
reserveBalance: 0,
|
|
281
|
-
transactionFee: 0.02, // 2% hard sink
|
|
282
|
-
sigmoidK: 100,
|
|
283
|
-
spatialDistanceFactor: 0.0,
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Calculate the spot price on a bonding curve given current supply.
|
|
288
|
-
*
|
|
289
|
-
* P = R * S^(1/n) for exponential
|
|
290
|
-
* P = R * S for linear
|
|
291
|
-
* P = R * ln(S+1) for logarithmic
|
|
292
|
-
* P = R * S^n / (K^n + S^n) for sigmoid
|
|
293
|
-
*/
|
|
294
|
-
export function bondingCurvePrice(
|
|
295
|
-
supply: number,
|
|
296
|
-
reserveRatio: number,
|
|
297
|
-
curveSteepness: number,
|
|
298
|
-
curveType: BondingCurveType = 'exponential',
|
|
299
|
-
sigmoidK: number = 100
|
|
300
|
-
): Currency {
|
|
301
|
-
if (supply <= 0) return 0;
|
|
302
|
-
if (reserveRatio <= 0) return 0;
|
|
303
|
-
|
|
304
|
-
switch (curveType) {
|
|
305
|
-
case 'linear':
|
|
306
|
-
return reserveRatio * supply;
|
|
307
|
-
|
|
308
|
-
case 'exponential':
|
|
309
|
-
return reserveRatio * Math.pow(supply, 1.0 / curveSteepness);
|
|
310
|
-
|
|
311
|
-
case 'logarithmic':
|
|
312
|
-
return reserveRatio * Math.log(supply + 1);
|
|
313
|
-
|
|
314
|
-
case 'sigmoid': {
|
|
315
|
-
const sn = Math.pow(supply, curveSteepness);
|
|
316
|
-
const kn = Math.pow(sigmoidK, curveSteepness);
|
|
317
|
-
return reserveRatio * (sn / (kn + sn));
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
default:
|
|
321
|
-
return reserveRatio * Math.pow(supply, 1.0 / curveSteepness);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Calculate the cost to buy `amount` tokens on the bonding curve.
|
|
327
|
-
* Integrates the price function from currentSupply to currentSupply + amount.
|
|
328
|
-
*/
|
|
329
|
-
export function bondingCurveBuyCost(config: BondingCurveConfig, amount: number): Currency {
|
|
330
|
-
if (amount <= 0) return 0;
|
|
331
|
-
|
|
332
|
-
// Numerical integration using Simpson's rule (good enough for game economies)
|
|
333
|
-
const n = Math.max(10, Math.ceil(amount));
|
|
334
|
-
const h = amount / n;
|
|
335
|
-
let sum = 0;
|
|
336
|
-
const s0 = config.currentSupply;
|
|
337
|
-
|
|
338
|
-
for (let i = 0; i <= n; i++) {
|
|
339
|
-
const s = s0 + i * h;
|
|
340
|
-
const p = bondingCurvePrice(
|
|
341
|
-
s,
|
|
342
|
-
config.reserveRatio,
|
|
343
|
-
config.curveSteepness,
|
|
344
|
-
config.curveType,
|
|
345
|
-
config.sigmoidK
|
|
346
|
-
);
|
|
347
|
-
|
|
348
|
-
if (i === 0 || i === n) {
|
|
349
|
-
sum += p;
|
|
350
|
-
} else if (i % 2 === 1) {
|
|
351
|
-
sum += 4 * p;
|
|
352
|
-
} else {
|
|
353
|
-
sum += 2 * p;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const cost = (h / 3) * sum;
|
|
358
|
-
return cost * (1 + config.transactionFee); // Include fee
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Calculate the refund for selling `amount` tokens on the bonding curve.
|
|
363
|
-
*/
|
|
364
|
-
export function bondingCurveSellRefund(config: BondingCurveConfig, amount: number): Currency {
|
|
365
|
-
if (amount <= 0) return 0;
|
|
366
|
-
if (amount > config.currentSupply) return 0;
|
|
367
|
-
|
|
368
|
-
const n = Math.max(10, Math.ceil(amount));
|
|
369
|
-
const h = amount / n;
|
|
370
|
-
let sum = 0;
|
|
371
|
-
const s0 = config.currentSupply - amount;
|
|
372
|
-
|
|
373
|
-
for (let i = 0; i <= n; i++) {
|
|
374
|
-
const s = s0 + i * h;
|
|
375
|
-
const p = bondingCurvePrice(
|
|
376
|
-
s,
|
|
377
|
-
config.reserveRatio,
|
|
378
|
-
config.curveSteepness,
|
|
379
|
-
config.curveType,
|
|
380
|
-
config.sigmoidK
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
if (i === 0 || i === n) {
|
|
384
|
-
sum += p;
|
|
385
|
-
} else if (i % 2 === 1) {
|
|
386
|
-
sum += 4 * p;
|
|
387
|
-
} else {
|
|
388
|
-
sum += 2 * p;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const refund = (h / 3) * sum;
|
|
393
|
-
return refund * (1 - config.transactionFee); // Deduct fee
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Apply spatial distance factor to a bonding curve price.
|
|
398
|
-
* P_spatial = P_bonding * (1 + distance_factor * distance)
|
|
399
|
-
* Creates emergent trade routes in VR economies (P.030.02 ENRICHED).
|
|
400
|
-
*/
|
|
401
|
-
export function spatialPrice(
|
|
402
|
-
basePrice: Currency,
|
|
403
|
-
distanceToHub: number,
|
|
404
|
-
distanceFactor: number
|
|
405
|
-
): Currency {
|
|
406
|
-
if (distanceFactor <= 0 || distanceToHub <= 0) return basePrice;
|
|
407
|
-
return basePrice * (1 + distanceFactor * distanceToHub);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// =============================================================================
|
|
411
|
-
// TAXABLE WEALTH PRIMITIVES
|
|
412
|
-
// =============================================================================
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Configuration for progressive wealth taxation.
|
|
416
|
-
*/
|
|
417
|
-
export interface WealthTaxConfig {
|
|
418
|
-
/** Wealth threshold below which no tax is levied */
|
|
419
|
-
threshold: Currency;
|
|
420
|
-
/** Base tax rate (multiplied by log of excess wealth) */
|
|
421
|
-
baseRate: number;
|
|
422
|
-
/** Maximum effective tax rate cap (prevents punishing engagement) */
|
|
423
|
-
maxEffectiveRate: number;
|
|
424
|
-
/** Tax collection interval description */
|
|
425
|
-
collectionInterval: 'hourly' | 'daily' | 'weekly';
|
|
426
|
-
/** Whether to redistribute to lowest quintile */
|
|
427
|
-
enableRedistribution: boolean;
|
|
428
|
-
/** Fraction of collected tax that goes to redistribution (remainder is burned as hard sink) */
|
|
429
|
-
redistributionFraction: number;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Default wealth tax configuration.
|
|
434
|
-
*/
|
|
435
|
-
export const DEFAULT_WEALTH_TAX: WealthTaxConfig = {
|
|
436
|
-
threshold: 10000,
|
|
437
|
-
baseRate: 0.01, // 1% base
|
|
438
|
-
maxEffectiveRate: 0.05, // 5% cap
|
|
439
|
-
collectionInterval: 'daily',
|
|
440
|
-
enableRedistribution: true,
|
|
441
|
-
redistributionFraction: 0.7, // 70% redistributed, 30% burned as hard sink
|
|
442
|
-
};
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Calculate the effective tax rate for a given wealth level.
|
|
446
|
-
* Uses logarithmic scaling: rate = min(maxRate, log(wealth/threshold) * baseRate)
|
|
447
|
-
* Returns 0 if wealth is below threshold (W.034).
|
|
448
|
-
*/
|
|
449
|
-
export function calculateTaxRate(
|
|
450
|
-
wealth: Currency,
|
|
451
|
-
threshold: Currency,
|
|
452
|
-
baseRate: number,
|
|
453
|
-
maxEffectiveRate: number
|
|
454
|
-
): number {
|
|
455
|
-
if (wealth <= threshold) return 0;
|
|
456
|
-
if (threshold <= 0) return 0;
|
|
457
|
-
|
|
458
|
-
const rate = Math.log(wealth / threshold) * baseRate;
|
|
459
|
-
return Math.min(rate, maxEffectiveRate);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Calculate the tax amount owed for a given wealth level.
|
|
464
|
-
*/
|
|
465
|
-
export function calculateTaxAmount(wealth: Currency, config: WealthTaxConfig): Currency {
|
|
466
|
-
const rate = calculateTaxRate(wealth, config.threshold, config.baseRate, config.maxEffectiveRate);
|
|
467
|
-
return wealth * rate;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/**
|
|
471
|
-
* Calculate redistribution amounts from a tax pool.
|
|
472
|
-
* Returns the per-recipient amount and the amount burned as a hard sink.
|
|
473
|
-
*/
|
|
474
|
-
export function calculateRedistribution(
|
|
475
|
-
totalTaxCollected: Currency,
|
|
476
|
-
recipientCount: number,
|
|
477
|
-
redistributionFraction: number
|
|
478
|
-
): { perRecipient: Currency; burned: Currency } {
|
|
479
|
-
if (recipientCount <= 0 || totalTaxCollected <= 0) {
|
|
480
|
-
return { perRecipient: 0, burned: totalTaxCollected };
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
const redistributed = totalTaxCollected * redistributionFraction;
|
|
484
|
-
const burned = totalTaxCollected - redistributed;
|
|
485
|
-
const perRecipient = redistributed / recipientCount;
|
|
486
|
-
|
|
487
|
-
return { perRecipient, burned };
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// =============================================================================
|
|
491
|
-
// PID CONTROLLER PRIMITIVES
|
|
492
|
-
// =============================================================================
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Configuration for a PID controller (P.030.01).
|
|
496
|
-
*/
|
|
497
|
-
export interface PIDConfig {
|
|
498
|
-
/** Proportional gain */
|
|
499
|
-
kp: number;
|
|
500
|
-
/** Integral gain */
|
|
501
|
-
ki: number;
|
|
502
|
-
/** Derivative gain */
|
|
503
|
-
kd: number;
|
|
504
|
-
/** Target setpoint (e.g., target money supply) */
|
|
505
|
-
setpoint: number;
|
|
506
|
-
/** Output limits [min, max] */
|
|
507
|
-
outputMin: number;
|
|
508
|
-
outputMax: number;
|
|
509
|
-
/** Anti-windup integral limit */
|
|
510
|
-
integralLimit: number;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* Internal state of a PID controller.
|
|
515
|
-
*/
|
|
516
|
-
export interface PIDState {
|
|
517
|
-
/** Previous error (for derivative term) */
|
|
518
|
-
previousError: number;
|
|
519
|
-
/** Accumulated integral */
|
|
520
|
-
integral: number;
|
|
521
|
-
/** Last output value */
|
|
522
|
-
lastOutput: number;
|
|
523
|
-
/** Whether the controller has ever been updated */
|
|
524
|
-
initialized: boolean;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Default PID configuration for economy flow control.
|
|
529
|
-
*/
|
|
530
|
-
export const DEFAULT_PID: PIDConfig = {
|
|
531
|
-
kp: 0.5,
|
|
532
|
-
ki: 0.01,
|
|
533
|
-
kd: 0.1,
|
|
534
|
-
setpoint: 0,
|
|
535
|
-
outputMin: -1.0,
|
|
536
|
-
outputMax: 1.0,
|
|
537
|
-
integralLimit: 10.0,
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* Create initial PID state.
|
|
542
|
-
*/
|
|
543
|
-
export function createPIDState(): PIDState {
|
|
544
|
-
return {
|
|
545
|
-
previousError: 0,
|
|
546
|
-
integral: 0,
|
|
547
|
-
lastOutput: 0,
|
|
548
|
-
initialized: false,
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* Update the PID controller with a new measurement.
|
|
554
|
-
*
|
|
555
|
-
* Returns the control output (e.g., faucet rate multiplier).
|
|
556
|
-
* Positive output means increase faucet rate, negative means decrease.
|
|
557
|
-
*
|
|
558
|
-
* @param config PID configuration
|
|
559
|
-
* @param state Current PID state (mutated in place for performance)
|
|
560
|
-
* @param measurement Current measured value (e.g., total money supply)
|
|
561
|
-
* @param dt Time delta in seconds
|
|
562
|
-
* @returns The control output value
|
|
563
|
-
*/
|
|
564
|
-
export function updatePID(
|
|
565
|
-
config: PIDConfig,
|
|
566
|
-
state: PIDState,
|
|
567
|
-
measurement: number,
|
|
568
|
-
dt: number
|
|
569
|
-
): number {
|
|
570
|
-
if (dt <= 0) return state.lastOutput;
|
|
571
|
-
|
|
572
|
-
const error = config.setpoint - measurement;
|
|
573
|
-
|
|
574
|
-
// Proportional term
|
|
575
|
-
const p = config.kp * error;
|
|
576
|
-
|
|
577
|
-
// Integral term with anti-windup
|
|
578
|
-
state.integral += error * dt;
|
|
579
|
-
state.integral = Math.max(-config.integralLimit, Math.min(config.integralLimit, state.integral));
|
|
580
|
-
const i = config.ki * state.integral;
|
|
581
|
-
|
|
582
|
-
// Derivative term (skip on first update to avoid spike)
|
|
583
|
-
let d = 0;
|
|
584
|
-
if (state.initialized) {
|
|
585
|
-
d = config.kd * ((error - state.previousError) / dt);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Compute output with clamping
|
|
589
|
-
let output = p + i + d;
|
|
590
|
-
output = Math.max(config.outputMin, Math.min(config.outputMax, output));
|
|
591
|
-
|
|
592
|
-
// Update state
|
|
593
|
-
state.previousError = error;
|
|
594
|
-
state.lastOutput = output;
|
|
595
|
-
state.initialized = true;
|
|
596
|
-
|
|
597
|
-
return output;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Dual-loop PID controller configuration (P.030.01).
|
|
602
|
-
*
|
|
603
|
-
* Inner loop: Per-source faucet adjustment (fast response)
|
|
604
|
-
* Outer loop: Global money supply targeting (slow response, adjusts inner setpoint)
|
|
605
|
-
*/
|
|
606
|
-
export interface DualLoopPIDConfig {
|
|
607
|
-
/** Inner loop PID (fast: adjusts faucet rates) */
|
|
608
|
-
innerLoop: PIDConfig;
|
|
609
|
-
/** Outer loop PID (slow: adjusts inner loop setpoint based on total supply) */
|
|
610
|
-
outerLoop: PIDConfig;
|
|
611
|
-
/** Target total money supply */
|
|
612
|
-
targetMoneySupply: number;
|
|
613
|
-
/** Active player count (for per-capita targeting) */
|
|
614
|
-
activePlayerCount: number;
|
|
615
|
-
/** Per-capita money supply target */
|
|
616
|
-
perCapitaTarget: number;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* State for the dual-loop PID controller.
|
|
621
|
-
*/
|
|
622
|
-
export interface DualLoopPIDState {
|
|
623
|
-
innerState: PIDState;
|
|
624
|
-
outerState: PIDState;
|
|
625
|
-
/** Current effective faucet rate multiplier (0.0 - 2.0, where 1.0 = normal) */
|
|
626
|
-
faucetMultiplier: number;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
/**
|
|
630
|
-
* Create initial dual-loop PID state.
|
|
631
|
-
*/
|
|
632
|
-
export function createDualLoopPIDState(): DualLoopPIDState {
|
|
633
|
-
return {
|
|
634
|
-
innerState: createPIDState(),
|
|
635
|
-
outerState: createPIDState(),
|
|
636
|
-
faucetMultiplier: 1.0,
|
|
637
|
-
};
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
/**
|
|
641
|
-
* Update the dual-loop PID controller.
|
|
642
|
-
*
|
|
643
|
-
* @param config Dual-loop configuration
|
|
644
|
-
* @param state Current state (mutated in place)
|
|
645
|
-
* @param totalMoneySupply Current total money supply
|
|
646
|
-
* @param currentFaucetRate Current inflow rate
|
|
647
|
-
* @param dt Time delta in seconds
|
|
648
|
-
* @returns The new faucet rate multiplier
|
|
649
|
-
*/
|
|
650
|
-
export function updateDualLoopPID(
|
|
651
|
-
config: DualLoopPIDConfig,
|
|
652
|
-
state: DualLoopPIDState,
|
|
653
|
-
totalMoneySupply: number,
|
|
654
|
-
currentFaucetRate: number,
|
|
655
|
-
dt: number
|
|
656
|
-
): number {
|
|
657
|
-
// Outer loop: adjust target based on total money supply vs. target
|
|
658
|
-
const targetSupply = config.perCapitaTarget * config.activePlayerCount;
|
|
659
|
-
const outerConfig = { ...config.outerLoop, setpoint: targetSupply };
|
|
660
|
-
const outerOutput = updatePID(outerConfig, state.outerState, totalMoneySupply, dt);
|
|
661
|
-
|
|
662
|
-
// Outer output adjusts inner loop setpoint (desired faucet rate)
|
|
663
|
-
const desiredFaucetRate = currentFaucetRate * (1 + outerOutput * 0.1);
|
|
664
|
-
|
|
665
|
-
// Inner loop: adjust faucet multiplier to achieve desired rate
|
|
666
|
-
const innerConfig = { ...config.innerLoop, setpoint: desiredFaucetRate };
|
|
667
|
-
const innerOutput = updatePID(innerConfig, state.innerState, currentFaucetRate, dt);
|
|
668
|
-
|
|
669
|
-
// Convert inner output to faucet multiplier (0.0 - 2.0 range)
|
|
670
|
-
state.faucetMultiplier = Math.max(0, Math.min(2, 1 + innerOutput));
|
|
671
|
-
|
|
672
|
-
return state.faucetMultiplier;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// =============================================================================
|
|
676
|
-
// FAUCET-SINK TRACKING
|
|
677
|
-
// =============================================================================
|
|
678
|
-
|
|
679
|
-
/**
|
|
680
|
-
* Tracks the faucet/sink ratio -- the master variable for economy health (W.031).
|
|
681
|
-
*/
|
|
682
|
-
export interface FaucetSinkMetrics {
|
|
683
|
-
/** Total currency created in the current period */
|
|
684
|
-
totalFaucet: Currency;
|
|
685
|
-
/** Total currency destroyed in the current period */
|
|
686
|
-
totalSink: Currency;
|
|
687
|
-
/** Current faucet/sink ratio (target: ~1.0) */
|
|
688
|
-
ratio: number;
|
|
689
|
-
/** Velocity of money (transactions per unit per period) */
|
|
690
|
-
velocity: number;
|
|
691
|
-
/** Period start timestamp */
|
|
692
|
-
periodStart: number;
|
|
693
|
-
/** Historical ratio samples */
|
|
694
|
-
ratioHistory: number[];
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
/**
|
|
698
|
-
* Create initial faucet-sink metrics.
|
|
699
|
-
*/
|
|
700
|
-
export function createFaucetSinkMetrics(timestamp: number): FaucetSinkMetrics {
|
|
701
|
-
return {
|
|
702
|
-
totalFaucet: 0,
|
|
703
|
-
totalSink: 0,
|
|
704
|
-
ratio: 1.0,
|
|
705
|
-
velocity: 0,
|
|
706
|
-
periodStart: timestamp,
|
|
707
|
-
ratioHistory: [],
|
|
708
|
-
};
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
/**
|
|
712
|
-
* Record a faucet event (currency creation).
|
|
713
|
-
*/
|
|
714
|
-
export function recordFaucet(metrics: FaucetSinkMetrics, amount: Currency): void {
|
|
715
|
-
metrics.totalFaucet += amount;
|
|
716
|
-
metrics.ratio =
|
|
717
|
-
metrics.totalSink > 0
|
|
718
|
-
? metrics.totalFaucet / metrics.totalSink
|
|
719
|
-
: metrics.totalFaucet > 0
|
|
720
|
-
? Infinity
|
|
721
|
-
: 1.0;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Record a sink event (currency destruction).
|
|
726
|
-
*/
|
|
727
|
-
export function recordSink(metrics: FaucetSinkMetrics, amount: Currency): void {
|
|
728
|
-
metrics.totalSink += amount;
|
|
729
|
-
metrics.ratio =
|
|
730
|
-
metrics.totalSink > 0
|
|
731
|
-
? metrics.totalFaucet / metrics.totalSink
|
|
732
|
-
: metrics.totalFaucet > 0
|
|
733
|
-
? Infinity
|
|
734
|
-
: 1.0;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
/**
|
|
738
|
-
* Reset metrics for a new period, archiving the current ratio.
|
|
739
|
-
*/
|
|
740
|
-
export function resetMetricsPeriod(metrics: FaucetSinkMetrics, timestamp: number): void {
|
|
741
|
-
// Archive current ratio
|
|
742
|
-
if (metrics.totalFaucet > 0 || metrics.totalSink > 0) {
|
|
743
|
-
metrics.ratioHistory.push(metrics.ratio);
|
|
744
|
-
// Keep last 100 periods
|
|
745
|
-
if (metrics.ratioHistory.length > 100) {
|
|
746
|
-
metrics.ratioHistory.shift();
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
metrics.totalFaucet = 0;
|
|
751
|
-
metrics.totalSink = 0;
|
|
752
|
-
metrics.ratio = 1.0;
|
|
753
|
-
metrics.velocity = 0;
|
|
754
|
-
metrics.periodStart = timestamp;
|
|
755
|
-
}
|