dexbot 1.1.10
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/LICENSE +21 -0
- package/README.md +287 -0
- package/claw/README.md +513 -0
- package/claw/scripts/memu_runner.py +385 -0
- package/claw/skills/bitshares-guide/SKILL.md +14 -0
- package/claw/skills/bitshares-guide/references/example-skill-shells.md +18 -0
- package/claw/skills/bitshares-guide/references/presentation-patterns.md +19 -0
- package/claw/skills/bitshares-guide/references/scope-guardrails.md +9 -0
- package/claw/skills/launcher-ops/SKILL.md +18 -0
- package/claw/skills/launcher-ops/references/launcher-workflow.md +23 -0
- package/claw/skills/margin-trading/SKILL.md +23 -0
- package/claw/skills/margin-trading/references/honest-asset-list.md +74 -0
- package/claw/skills/margin-trading/references/honest-assets.md +44 -0
- package/claw/skills/margin-trading/references/position-management.md +203 -0
- package/claw/skills/margin-trading/references/trading-concepts.md +80 -0
- package/claw/skills/memu-memory/SKILL.md +218 -0
- package/claw/skills/shared/references/js-automation-overview.md +24 -0
- package/claw/skills/shared/references/safety-and-staleness.md +11 -0
- package/claw/skills/shared/references/skill-boundaries.md +17 -0
- package/claw/skills/trend-detection/SKILL.md +33 -0
- package/claw/skills/trend-detection/agents/openai.yaml +3 -0
- package/claw/skills/trend-detection/references/service.md +45 -0
- package/dist/analysis/ama_fitting/analyze_ama_price_changes.d.ts +3 -0
- package/dist/analysis/ama_fitting/analyze_ama_price_changes.d.ts.map +1 -0
- package/dist/analysis/ama_fitting/analyze_ama_price_changes.js +149 -0
- package/dist/analysis/ama_fitting/analyze_ama_price_changes.js.map +1 -0
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts +3 -0
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts.map +1 -0
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +387 -0
- package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -0
- package/dist/analysis/ama_fitting/calibrate_convergence_er.d.ts +3 -0
- package/dist/analysis/ama_fitting/calibrate_convergence_er.d.ts.map +1 -0
- package/dist/analysis/ama_fitting/calibrate_convergence_er.js +200 -0
- package/dist/analysis/ama_fitting/calibrate_convergence_er.js.map +1 -0
- package/dist/analysis/ama_fitting/fetch_lp_candles.d.ts +3 -0
- package/dist/analysis/ama_fitting/fetch_lp_candles.d.ts.map +1 -0
- package/dist/analysis/ama_fitting/fetch_lp_candles.js +212 -0
- package/dist/analysis/ama_fitting/fetch_lp_candles.js.map +1 -0
- package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts +31 -0
- package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts.map +1 -0
- package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js +249 -0
- package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js.map +1 -0
- package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts +2 -0
- package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts.map +1 -0
- package/dist/analysis/ama_fitting/optimizer_high_resolution.js +782 -0
- package/dist/analysis/ama_fitting/optimizer_high_resolution.js.map +1 -0
- package/dist/analysis/analyze_derivatives.d.ts +95 -0
- package/dist/analysis/analyze_derivatives.d.ts.map +1 -0
- package/dist/analysis/analyze_derivatives.js +295 -0
- package/dist/analysis/analyze_derivatives.js.map +1 -0
- package/dist/analysis/analyze_dynamic_weight.d.ts +14 -0
- package/dist/analysis/analyze_dynamic_weight.d.ts.map +1 -0
- package/dist/analysis/analyze_dynamic_weight.js +208 -0
- package/dist/analysis/analyze_dynamic_weight.js.map +1 -0
- package/dist/analysis/analyze_kalman.d.ts +13 -0
- package/dist/analysis/analyze_kalman.d.ts.map +1 -0
- package/dist/analysis/analyze_kalman.js +123 -0
- package/dist/analysis/analyze_kalman.js.map +1 -0
- package/dist/analysis/analyze_regime.d.ts +20 -0
- package/dist/analysis/analyze_regime.d.ts.map +1 -0
- package/dist/analysis/analyze_regime.js +139 -0
- package/dist/analysis/analyze_regime.js.map +1 -0
- package/dist/analysis/analyze_regime_windows.d.ts +19 -0
- package/dist/analysis/analyze_regime_windows.d.ts.map +1 -0
- package/dist/analysis/analyze_regime_windows.js +413 -0
- package/dist/analysis/analyze_regime_windows.js.map +1 -0
- package/dist/analysis/analyze_risk_profile.d.ts +3 -0
- package/dist/analysis/analyze_risk_profile.d.ts.map +1 -0
- package/dist/analysis/analyze_risk_profile.js +159 -0
- package/dist/analysis/analyze_risk_profile.js.map +1 -0
- package/dist/analysis/analyze_trade_heatmap.d.ts +3 -0
- package/dist/analysis/analyze_trade_heatmap.d.ts.map +1 -0
- package/dist/analysis/analyze_trade_heatmap.js +367 -0
- package/dist/analysis/analyze_trade_heatmap.js.map +1 -0
- package/dist/analysis/analyze_volatility.d.ts +22 -0
- package/dist/analysis/analyze_volatility.d.ts.map +1 -0
- package/dist/analysis/analyze_volatility.js +172 -0
- package/dist/analysis/analyze_volatility.js.map +1 -0
- package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts +99 -0
- package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts.map +1 -0
- package/dist/analysis/bot_fitting/backtest_ama_sweep.js +804 -0
- package/dist/analysis/bot_fitting/backtest_ama_sweep.js.map +1 -0
- package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts +2 -0
- package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts.map +1 -0
- package/dist/analysis/bot_fitting/backtest_bot_fitting.js +347 -0
- package/dist/analysis/bot_fitting/backtest_bot_fitting.js.map +1 -0
- package/dist/analysis/bot_fitting/shared_utils.d.ts +15 -0
- package/dist/analysis/bot_fitting/shared_utils.d.ts.map +1 -0
- package/dist/analysis/bot_fitting/shared_utils.js +48 -0
- package/dist/analysis/bot_fitting/shared_utils.js.map +1 -0
- package/dist/analysis/bot_key_utils.d.ts +16 -0
- package/dist/analysis/bot_key_utils.d.ts.map +1 -0
- package/dist/analysis/bot_key_utils.js +61 -0
- package/dist/analysis/bot_key_utils.js.map +1 -0
- package/dist/analysis/bot_usage/discover_bot_accounts.d.ts +3 -0
- package/dist/analysis/bot_usage/discover_bot_accounts.d.ts.map +1 -0
- package/dist/analysis/bot_usage/discover_bot_accounts.js +498 -0
- package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -0
- package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +546 -0
- package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -0
- package/dist/analysis/bot_usage/kibana_bot_queries.js +427 -0
- package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -0
- package/dist/analysis/chart_utils.d.ts +13 -0
- package/dist/analysis/chart_utils.d.ts.map +1 -0
- package/dist/analysis/chart_utils.js +142 -0
- package/dist/analysis/chart_utils.js.map +1 -0
- package/dist/analysis/derivative_chart_generator.d.ts +18 -0
- package/dist/analysis/derivative_chart_generator.d.ts.map +1 -0
- package/dist/analysis/derivative_chart_generator.js +896 -0
- package/dist/analysis/derivative_chart_generator.js.map +1 -0
- package/dist/analysis/math_utils.d.ts +35 -0
- package/dist/analysis/math_utils.d.ts.map +1 -0
- package/dist/analysis/math_utils.js +121 -0
- package/dist/analysis/math_utils.js.map +1 -0
- package/dist/analysis/price_sources.d.ts +34 -0
- package/dist/analysis/price_sources.d.ts.map +1 -0
- package/dist/analysis/price_sources.js +103 -0
- package/dist/analysis/price_sources.js.map +1 -0
- package/dist/analysis/trade_profitability.d.ts +115 -0
- package/dist/analysis/trade_profitability.d.ts.map +1 -0
- package/dist/analysis/trade_profitability.js +1247 -0
- package/dist/analysis/trade_profitability.js.map +1 -0
- package/dist/analysis/tradingview/analyze_tradingview.d.ts +38 -0
- package/dist/analysis/tradingview/analyze_tradingview.d.ts.map +1 -0
- package/dist/analysis/tradingview/analyze_tradingview.js +212 -0
- package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -0
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts +9 -0
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -0
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +1717 -0
- package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js.map +1 -0
- package/dist/analysis/trend_detection/derivative_analyzer.d.ts +250 -0
- package/dist/analysis/trend_detection/derivative_analyzer.d.ts.map +1 -0
- package/dist/analysis/trend_detection/derivative_analyzer.js +903 -0
- package/dist/analysis/trend_detection/derivative_analyzer.js.map +1 -0
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts +6 -0
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -0
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +1449 -0
- package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -0
- package/dist/analysis/trend_detection/hurst_analyzer.d.ts +42 -0
- package/dist/analysis/trend_detection/hurst_analyzer.d.ts.map +1 -0
- package/dist/analysis/trend_detection/hurst_analyzer.js +159 -0
- package/dist/analysis/trend_detection/hurst_analyzer.js.map +1 -0
- package/dist/analysis/trend_detection/kalman_chart_generator.d.ts +6 -0
- package/dist/analysis/trend_detection/kalman_chart_generator.d.ts.map +1 -0
- package/dist/analysis/trend_detection/kalman_chart_generator.js +408 -0
- package/dist/analysis/trend_detection/kalman_chart_generator.js.map +1 -0
- package/dist/analysis/trend_detection/kalman_trend_analyzer.d.ts +103 -0
- package/dist/analysis/trend_detection/kalman_trend_analyzer.d.ts.map +1 -0
- package/dist/analysis/trend_detection/kalman_trend_analyzer.js +229 -0
- package/dist/analysis/trend_detection/kalman_trend_analyzer.js.map +1 -0
- package/dist/analysis/trend_detection/kalman_velocity_smoothing.d.ts +34 -0
- package/dist/analysis/trend_detection/kalman_velocity_smoothing.d.ts.map +1 -0
- package/dist/analysis/trend_detection/kalman_velocity_smoothing.js +89 -0
- package/dist/analysis/trend_detection/kalman_velocity_smoothing.js.map +1 -0
- package/dist/analysis/trend_detection/permutation_entropy_analyzer.d.ts +39 -0
- package/dist/analysis/trend_detection/permutation_entropy_analyzer.d.ts.map +1 -0
- package/dist/analysis/trend_detection/permutation_entropy_analyzer.js +132 -0
- package/dist/analysis/trend_detection/permutation_entropy_analyzer.js.map +1 -0
- package/dist/analysis/trend_detection/regime_chart_generator.d.ts +6 -0
- package/dist/analysis/trend_detection/regime_chart_generator.d.ts.map +1 -0
- package/dist/analysis/trend_detection/regime_chart_generator.js +345 -0
- package/dist/analysis/trend_detection/regime_chart_generator.js.map +1 -0
- package/dist/analysis/trend_detection/tests/test_kalman_trend.d.ts +2 -0
- package/dist/analysis/trend_detection/tests/test_kalman_trend.d.ts.map +1 -0
- package/dist/analysis/trend_detection/tests/test_kalman_trend.js +130 -0
- package/dist/analysis/trend_detection/tests/test_kalman_trend.js.map +1 -0
- package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.d.ts +2 -0
- package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.d.ts.map +1 -0
- package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js +38 -0
- package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js.map +1 -0
- package/dist/analysis/trend_detection/volatility_chart_generator.d.ts +6 -0
- package/dist/analysis/trend_detection/volatility_chart_generator.d.ts.map +1 -0
- package/dist/analysis/trend_detection/volatility_chart_generator.js +732 -0
- package/dist/analysis/trend_detection/volatility_chart_generator.js.map +1 -0
- package/dist/bot.d.ts +49 -0
- package/dist/bot.d.ts.map +1 -0
- package/dist/bot.js +221 -0
- package/dist/bot.js.map +1 -0
- package/dist/credential-daemon.d.ts +64 -0
- package/dist/credential-daemon.d.ts.map +1 -0
- package/dist/credential-daemon.js +987 -0
- package/dist/credential-daemon.js.map +1 -0
- package/dist/dexbot.d.ts +87 -0
- package/dist/dexbot.d.ts.map +1 -0
- package/dist/dexbot.js +1222 -0
- package/dist/dexbot.js.map +1 -0
- package/dist/market_adapter/ama_signal_runner.d.ts +3 -0
- package/dist/market_adapter/ama_signal_runner.d.ts.map +1 -0
- package/dist/market_adapter/ama_signal_runner.js +175 -0
- package/dist/market_adapter/ama_signal_runner.js.map +1 -0
- package/dist/market_adapter/candle_utils.d.ts +57 -0
- package/dist/market_adapter/candle_utils.d.ts.map +1 -0
- package/dist/market_adapter/candle_utils.js +252 -0
- package/dist/market_adapter/candle_utils.js.map +1 -0
- package/dist/market_adapter/core/asymmetric_bounds.d.ts +20 -0
- package/dist/market_adapter/core/asymmetric_bounds.d.ts.map +1 -0
- package/dist/market_adapter/core/asymmetric_bounds.js +88 -0
- package/dist/market_adapter/core/asymmetric_bounds.js.map +1 -0
- package/dist/market_adapter/core/config_normalizers.d.ts +10 -0
- package/dist/market_adapter/core/config_normalizers.d.ts.map +1 -0
- package/dist/market_adapter/core/config_normalizers.js +24 -0
- package/dist/market_adapter/core/config_normalizers.js.map +1 -0
- package/dist/market_adapter/core/kibana_candles.d.ts +74 -0
- package/dist/market_adapter/core/kibana_candles.d.ts.map +1 -0
- package/dist/market_adapter/core/kibana_candles.js +249 -0
- package/dist/market_adapter/core/kibana_candles.js.map +1 -0
- package/dist/market_adapter/core/kibana_client.d.ts +27 -0
- package/dist/market_adapter/core/kibana_client.d.ts.map +1 -0
- package/dist/market_adapter/core/kibana_client.js +120 -0
- package/dist/market_adapter/core/kibana_client.js.map +1 -0
- package/dist/market_adapter/core/kibana_market_candles.d.ts +143 -0
- package/dist/market_adapter/core/kibana_market_candles.d.ts.map +1 -0
- package/dist/market_adapter/core/kibana_market_candles.js +170 -0
- package/dist/market_adapter/core/kibana_market_candles.js.map +1 -0
- package/dist/market_adapter/core/market_adapter_service.d.ts +210 -0
- package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -0
- package/dist/market_adapter/core/market_adapter_service.js +2328 -0
- package/dist/market_adapter/core/market_adapter_service.js.map +1 -0
- package/dist/market_adapter/core/strategies/ama.d.ts +2 -0
- package/dist/market_adapter/core/strategies/ama.d.ts.map +1 -0
- package/dist/market_adapter/core/strategies/ama.js +138 -0
- package/dist/market_adapter/core/strategies/ama.js.map +1 -0
- package/dist/market_adapter/core/strategies/ama_slope_model.d.ts +50 -0
- package/dist/market_adapter/core/strategies/ama_slope_model.d.ts.map +1 -0
- package/dist/market_adapter/core/strategies/ama_slope_model.js +143 -0
- package/dist/market_adapter/core/strategies/ama_slope_model.js.map +1 -0
- package/dist/market_adapter/core/strategies/atr/calculator.d.ts +12 -0
- package/dist/market_adapter/core/strategies/atr/calculator.d.ts.map +1 -0
- package/dist/market_adapter/core/strategies/atr/calculator.js +47 -0
- package/dist/market_adapter/core/strategies/atr/calculator.js.map +1 -0
- package/dist/market_adapter/core/strategies/collateral_manager.d.ts +32 -0
- package/dist/market_adapter/core/strategies/collateral_manager.d.ts.map +1 -0
- package/dist/market_adapter/core/strategies/collateral_manager.js +68 -0
- package/dist/market_adapter/core/strategies/collateral_manager.js.map +1 -0
- package/dist/market_adapter/core/strategies/regime_gate.d.ts +66 -0
- package/dist/market_adapter/core/strategies/regime_gate.d.ts.map +1 -0
- package/dist/market_adapter/core/strategies/regime_gate.js +189 -0
- package/dist/market_adapter/core/strategies/regime_gate.js.map +1 -0
- package/dist/market_adapter/index.d.ts +10 -0
- package/dist/market_adapter/index.d.ts.map +1 -0
- package/dist/market_adapter/index.js +71 -0
- package/dist/market_adapter/index.js.map +1 -0
- package/dist/market_adapter/inputs/fetch_cex_synthetic_data.d.ts +3 -0
- package/dist/market_adapter/inputs/fetch_cex_synthetic_data.d.ts.map +1 -0
- package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +1165 -0
- package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -0
- package/dist/market_adapter/inputs/fetch_lp_data.d.ts +54 -0
- package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -0
- package/dist/market_adapter/inputs/fetch_lp_data.js +743 -0
- package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -0
- package/dist/market_adapter/inputs/kibana_source.d.ts +68 -0
- package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -0
- package/dist/market_adapter/inputs/kibana_source.js +143 -0
- package/dist/market_adapter/inputs/kibana_source.js.map +1 -0
- package/dist/market_adapter/interval_utils.d.ts +6 -0
- package/dist/market_adapter/interval_utils.d.ts.map +1 -0
- package/dist/market_adapter/interval_utils.js +14 -0
- package/dist/market_adapter/interval_utils.js.map +1 -0
- package/dist/market_adapter/log_format.d.ts +16 -0
- package/dist/market_adapter/log_format.d.ts.map +1 -0
- package/dist/market_adapter/log_format.js +72 -0
- package/dist/market_adapter/log_format.js.map +1 -0
- package/dist/market_adapter/lp_chart_core.d.ts +6 -0
- package/dist/market_adapter/lp_chart_core.d.ts.map +1 -0
- package/dist/market_adapter/lp_chart_core.js +874 -0
- package/dist/market_adapter/lp_chart_core.js.map +1 -0
- package/dist/market_adapter/lp_chart_runner.d.ts +135 -0
- package/dist/market_adapter/lp_chart_runner.d.ts.map +1 -0
- package/dist/market_adapter/lp_chart_runner.js +337 -0
- package/dist/market_adapter/lp_chart_runner.js.map +1 -0
- package/dist/market_adapter/lp_chart_strategy_loader.d.ts +23 -0
- package/dist/market_adapter/lp_chart_strategy_loader.d.ts.map +1 -0
- package/dist/market_adapter/lp_chart_strategy_loader.js +169 -0
- package/dist/market_adapter/lp_chart_strategy_loader.js.map +1 -0
- package/dist/market_adapter/market_adapter.d.ts +133 -0
- package/dist/market_adapter/market_adapter.d.ts.map +1 -0
- package/dist/market_adapter/market_adapter.js +1331 -0
- package/dist/market_adapter/market_adapter.js.map +1 -0
- package/dist/market_adapter/merge_lp_data.d.ts +3 -0
- package/dist/market_adapter/merge_lp_data.d.ts.map +1 -0
- package/dist/market_adapter/merge_lp_data.js +125 -0
- package/dist/market_adapter/merge_lp_data.js.map +1 -0
- package/dist/market_adapter/test_helpers.d.ts +14 -0
- package/dist/market_adapter/test_helpers.d.ts.map +1 -0
- package/dist/market_adapter/test_helpers.js +22 -0
- package/dist/market_adapter/test_helpers.js.map +1 -0
- package/dist/market_adapter/utils/adapter_client.d.ts +20 -0
- package/dist/market_adapter/utils/adapter_client.d.ts.map +1 -0
- package/dist/market_adapter/utils/adapter_client.js +88 -0
- package/dist/market_adapter/utils/adapter_client.js.map +1 -0
- package/dist/market_adapter/utils/atomic_write.d.ts +9 -0
- package/dist/market_adapter/utils/atomic_write.d.ts.map +1 -0
- package/dist/market_adapter/utils/atomic_write.js +13 -0
- package/dist/market_adapter/utils/atomic_write.js.map +1 -0
- package/dist/market_adapter/utils/chain.d.ts +50 -0
- package/dist/market_adapter/utils/chain.d.ts.map +1 -0
- package/dist/market_adapter/utils/chain.js +196 -0
- package/dist/market_adapter/utils/chain.js.map +1 -0
- package/dist/market_adapter/utils/data_discovery.d.ts +6 -0
- package/dist/market_adapter/utils/data_discovery.d.ts.map +1 -0
- package/dist/market_adapter/utils/data_discovery.js +35 -0
- package/dist/market_adapter/utils/data_discovery.js.map +1 -0
- package/dist/market_adapter/utils/dynamic_grid_snapshot.d.ts +15 -0
- package/dist/market_adapter/utils/dynamic_grid_snapshot.d.ts.map +1 -0
- package/dist/market_adapter/utils/dynamic_grid_snapshot.js +60 -0
- package/dist/market_adapter/utils/dynamic_grid_snapshot.js.map +1 -0
- package/dist/market_adapter/utils/file_lock.d.ts +19 -0
- package/dist/market_adapter/utils/file_lock.d.ts.map +1 -0
- package/dist/market_adapter/utils/file_lock.js +191 -0
- package/dist/market_adapter/utils/file_lock.js.map +1 -0
- package/dist/market_adapter/utils/native_history.d.ts +19 -0
- package/dist/market_adapter/utils/native_history.d.ts.map +1 -0
- package/dist/market_adapter/utils/native_history.js +172 -0
- package/dist/market_adapter/utils/native_history.js.map +1 -0
- package/dist/market_adapter/utils/paths.d.ts +5 -0
- package/dist/market_adapter/utils/paths.d.ts.map +1 -0
- package/dist/market_adapter/utils/paths.js +7 -0
- package/dist/market_adapter/utils/paths.js.map +1 -0
- package/dist/modules/account_bots.d.ts +112 -0
- package/dist/modules/account_bots.d.ts.map +1 -0
- package/dist/modules/account_bots.js +1259 -0
- package/dist/modules/account_bots.js.map +1 -0
- package/dist/modules/account_orders.d.ts +273 -0
- package/dist/modules/account_orders.d.ts.map +1 -0
- package/dist/modules/account_orders.js +662 -0
- package/dist/modules/account_orders.js.map +1 -0
- package/dist/modules/authority_resolver.d.ts +2 -0
- package/dist/modules/authority_resolver.d.ts.map +1 -0
- package/dist/modules/authority_resolver.js +231 -0
- package/dist/modules/authority_resolver.js.map +1 -0
- package/dist/modules/bitshares-native/chain_client.d.ts +38 -0
- package/dist/modules/bitshares-native/chain_client.d.ts.map +1 -0
- package/dist/modules/bitshares-native/chain_client.js +322 -0
- package/dist/modules/bitshares-native/chain_client.js.map +1 -0
- package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts +59 -0
- package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts.map +1 -0
- package/dist/modules/bitshares-native/crypto/ecc.browser.js +456 -0
- package/dist/modules/bitshares-native/crypto/ecc.browser.js.map +1 -0
- package/dist/modules/bitshares-native/crypto/ecc.d.ts +66 -0
- package/dist/modules/bitshares-native/crypto/ecc.d.ts.map +1 -0
- package/dist/modules/bitshares-native/crypto/ecc.js +557 -0
- package/dist/modules/bitshares-native/crypto/ecc.js.map +1 -0
- package/dist/modules/bitshares-native/crypto/ecc_selector.d.ts +2 -0
- package/dist/modules/bitshares-native/crypto/ecc_selector.d.ts.map +1 -0
- package/dist/modules/bitshares-native/crypto/ecc_selector.js +20 -0
- package/dist/modules/bitshares-native/crypto/ecc_selector.js.map +1 -0
- package/dist/modules/bitshares-native/index.d.ts +3 -0
- package/dist/modules/bitshares-native/index.d.ts.map +1 -0
- package/dist/modules/bitshares-native/index.js +32 -0
- package/dist/modules/bitshares-native/index.js.map +1 -0
- package/dist/modules/bitshares-native/resolvers.d.ts +40 -0
- package/dist/modules/bitshares-native/resolvers.d.ts.map +1 -0
- package/dist/modules/bitshares-native/resolvers.js +161 -0
- package/dist/modules/bitshares-native/resolvers.js.map +1 -0
- package/dist/modules/bitshares-native/serial/chain_constants.d.ts +56 -0
- package/dist/modules/bitshares-native/serial/chain_constants.d.ts.map +1 -0
- package/dist/modules/bitshares-native/serial/chain_constants.js +92 -0
- package/dist/modules/bitshares-native/serial/chain_constants.js.map +1 -0
- package/dist/modules/bitshares-native/serial/index.d.ts +10 -0
- package/dist/modules/bitshares-native/serial/index.d.ts.map +1 -0
- package/dist/modules/bitshares-native/serial/index.js +14 -0
- package/dist/modules/bitshares-native/serial/index.js.map +1 -0
- package/dist/modules/bitshares-native/serial/operations.d.ts +102 -0
- package/dist/modules/bitshares-native/serial/operations.d.ts.map +1 -0
- package/dist/modules/bitshares-native/serial/operations.js +615 -0
- package/dist/modules/bitshares-native/serial/operations.js.map +1 -0
- package/dist/modules/bitshares-native/serial/serializer.d.ts +64 -0
- package/dist/modules/bitshares-native/serial/serializer.d.ts.map +1 -0
- package/dist/modules/bitshares-native/serial/serializer.js +252 -0
- package/dist/modules/bitshares-native/serial/serializer.js.map +1 -0
- package/dist/modules/bitshares-native/serial/types.d.ts +120 -0
- package/dist/modules/bitshares-native/serial/types.d.ts.map +1 -0
- package/dist/modules/bitshares-native/serial/types.js +837 -0
- package/dist/modules/bitshares-native/serial/types.js.map +1 -0
- package/dist/modules/bitshares-native/signing_client.d.ts +6 -0
- package/dist/modules/bitshares-native/signing_client.d.ts.map +1 -0
- package/dist/modules/bitshares-native/signing_client.js +141 -0
- package/dist/modules/bitshares-native/signing_client.js.map +1 -0
- package/dist/modules/bitshares-native/subscriptions.d.ts +6 -0
- package/dist/modules/bitshares-native/subscriptions.d.ts.map +1 -0
- package/dist/modules/bitshares-native/subscriptions.js +865 -0
- package/dist/modules/bitshares-native/subscriptions.js.map +1 -0
- package/dist/modules/bitshares-native/transport.d.ts +51 -0
- package/dist/modules/bitshares-native/transport.d.ts.map +1 -0
- package/dist/modules/bitshares-native/transport.js +447 -0
- package/dist/modules/bitshares-native/transport.js.map +1 -0
- package/dist/modules/bitshares-native/tx/builder.d.ts +30 -0
- package/dist/modules/bitshares-native/tx/builder.d.ts.map +1 -0
- package/dist/modules/bitshares-native/tx/builder.js +262 -0
- package/dist/modules/bitshares-native/tx/builder.js.map +1 -0
- package/dist/modules/bitshares_client.d.ts +129 -0
- package/dist/modules/bitshares_client.d.ts.map +1 -0
- package/dist/modules/bitshares_client.js +627 -0
- package/dist/modules/bitshares_client.js.map +1 -0
- package/dist/modules/bot_settings.d.ts +33 -0
- package/dist/modules/bot_settings.d.ts.map +1 -0
- package/dist/modules/bot_settings.js +328 -0
- package/dist/modules/bot_settings.js.map +1 -0
- package/dist/modules/bots_file_lock.d.ts +88 -0
- package/dist/modules/bots_file_lock.d.ts.map +1 -0
- package/dist/modules/bots_file_lock.js +161 -0
- package/dist/modules/bots_file_lock.js.map +1 -0
- package/dist/modules/chain_keys.d.ts +302 -0
- package/dist/modules/chain_keys.d.ts.map +1 -0
- package/dist/modules/chain_keys.js +1095 -0
- package/dist/modules/chain_keys.js.map +1 -0
- package/dist/modules/chain_orders.d.ts +423 -0
- package/dist/modules/chain_orders.d.ts.map +1 -0
- package/dist/modules/chain_orders.js +1201 -0
- package/dist/modules/chain_orders.js.map +1 -0
- package/dist/modules/cli_whitelist_args.d.ts +6 -0
- package/dist/modules/cli_whitelist_args.d.ts.map +1 -0
- package/dist/modules/cli_whitelist_args.js +13 -0
- package/dist/modules/cli_whitelist_args.js.map +1 -0
- package/dist/modules/config.d.ts +57 -0
- package/dist/modules/config.d.ts.map +1 -0
- package/dist/modules/config.js +107 -0
- package/dist/modules/config.js.map +1 -0
- package/dist/modules/constants.d.ts +635 -0
- package/dist/modules/constants.d.ts.map +1 -0
- package/dist/modules/constants.js +1464 -0
- package/dist/modules/constants.js.map +1 -0
- package/dist/modules/cr_planner.d.ts +51 -0
- package/dist/modules/cr_planner.d.ts.map +1 -0
- package/dist/modules/cr_planner.js +299 -0
- package/dist/modules/cr_planner.js.map +1 -0
- package/dist/modules/credential_policy.d.ts +188 -0
- package/dist/modules/credential_policy.d.ts.map +1 -0
- package/dist/modules/credential_policy.js +1452 -0
- package/dist/modules/credential_policy.js.map +1 -0
- package/dist/modules/credential_runtime.d.ts +42 -0
- package/dist/modules/credential_runtime.d.ts.map +1 -0
- package/dist/modules/credential_runtime.js +148 -0
- package/dist/modules/credential_runtime.js.map +1 -0
- package/dist/modules/credential_session_cache.d.ts +36 -0
- package/dist/modules/credential_session_cache.d.ts.map +1 -0
- package/dist/modules/credential_session_cache.js +106 -0
- package/dist/modules/credential_session_cache.js.map +1 -0
- package/dist/modules/credit_runtime.d.ts +412 -0
- package/dist/modules/credit_runtime.d.ts.map +1 -0
- package/dist/modules/credit_runtime.js +2866 -0
- package/dist/modules/credit_runtime.js.map +1 -0
- package/dist/modules/crypto/browser_provider.d.ts +15 -0
- package/dist/modules/crypto/browser_provider.d.ts.map +1 -0
- package/dist/modules/crypto/browser_provider.js +113 -0
- package/dist/modules/crypto/browser_provider.js.map +1 -0
- package/dist/modules/crypto/index.d.ts +9 -0
- package/dist/modules/crypto/index.d.ts.map +1 -0
- package/dist/modules/crypto/index.js +44 -0
- package/dist/modules/crypto/index.js.map +1 -0
- package/dist/modules/crypto/node_provider.d.ts +15 -0
- package/dist/modules/crypto/node_provider.d.ts.map +1 -0
- package/dist/modules/crypto/node_provider.js +74 -0
- package/dist/modules/crypto/node_provider.js.map +1 -0
- package/dist/modules/crypto/provider.d.ts +34 -0
- package/dist/modules/crypto/provider.d.ts.map +1 -0
- package/dist/modules/crypto/provider.js +3 -0
- package/dist/modules/crypto/provider.js.map +1 -0
- package/dist/modules/crypto/pure_ripemd160.d.ts +8 -0
- package/dist/modules/crypto/pure_ripemd160.d.ts.map +1 -0
- package/dist/modules/crypto/pure_ripemd160.js +142 -0
- package/dist/modules/crypto/pure_ripemd160.js.map +1 -0
- package/dist/modules/crypto/pure_scrypt.d.ts +23 -0
- package/dist/modules/crypto/pure_scrypt.d.ts.map +1 -0
- package/dist/modules/crypto/pure_scrypt.js +161 -0
- package/dist/modules/crypto/pure_scrypt.js.map +1 -0
- package/dist/modules/crypto/pure_secp256k1.d.ts +29 -0
- package/dist/modules/crypto/pure_secp256k1.d.ts.map +1 -0
- package/dist/modules/crypto/pure_secp256k1.js +195 -0
- package/dist/modules/crypto/pure_secp256k1.js.map +1 -0
- package/dist/modules/crypto/sync.d.ts +13 -0
- package/dist/modules/crypto/sync.d.ts.map +1 -0
- package/dist/modules/crypto/sync.js +37 -0
- package/dist/modules/crypto/sync.js.map +1 -0
- package/dist/modules/dexbot_class.d.ts +1074 -0
- package/dist/modules/dexbot_class.d.ts.map +1 -0
- package/dist/modules/dexbot_class.js +4613 -0
- package/dist/modules/dexbot_class.js.map +1 -0
- package/dist/modules/dexbot_credential_client.d.ts +71 -0
- package/dist/modules/dexbot_credential_client.d.ts.map +1 -0
- package/dist/modules/dexbot_credential_client.js +224 -0
- package/dist/modules/dexbot_credential_client.js.map +1 -0
- package/dist/modules/dexbot_fill_runtime.d.ts +173 -0
- package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -0
- package/dist/modules/dexbot_fill_runtime.js +217 -0
- package/dist/modules/dexbot_fill_runtime.js.map +1 -0
- package/dist/modules/dexbot_maintenance_runtime.d.ts +279 -0
- package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -0
- package/dist/modules/dexbot_maintenance_runtime.js +1613 -0
- package/dist/modules/dexbot_maintenance_runtime.js.map +1 -0
- package/dist/modules/env.d.ts +12 -0
- package/dist/modules/env.d.ts.map +1 -0
- package/dist/modules/env.js +57 -0
- package/dist/modules/env.js.map +1 -0
- package/dist/modules/fund_registry.d.ts +96 -0
- package/dist/modules/fund_registry.d.ts.map +1 -0
- package/dist/modules/fund_registry.js +261 -0
- package/dist/modules/fund_registry.js.map +1 -0
- package/dist/modules/general_settings.d.ts +36 -0
- package/dist/modules/general_settings.d.ts.map +1 -0
- package/dist/modules/general_settings.js +63 -0
- package/dist/modules/general_settings.js.map +1 -0
- package/dist/modules/graceful_shutdown.d.ts +86 -0
- package/dist/modules/graceful_shutdown.d.ts.map +1 -0
- package/dist/modules/graceful_shutdown.js +164 -0
- package/dist/modules/graceful_shutdown.js.map +1 -0
- package/dist/modules/key_store.d.ts +60 -0
- package/dist/modules/key_store.d.ts.map +1 -0
- package/dist/modules/key_store.js +215 -0
- package/dist/modules/key_store.js.map +1 -0
- package/dist/modules/launcher/bot_supervisor.d.ts +84 -0
- package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -0
- package/dist/modules/launcher/bot_supervisor.js +1067 -0
- package/dist/modules/launcher/bot_supervisor.js.map +1 -0
- package/dist/modules/launcher/child_env.d.ts +9 -0
- package/dist/modules/launcher/child_env.d.ts.map +1 -0
- package/dist/modules/launcher/child_env.js +78 -0
- package/dist/modules/launcher/child_env.js.map +1 -0
- package/dist/modules/launcher/credential_bootstrap.d.ts +22 -0
- package/dist/modules/launcher/credential_bootstrap.d.ts.map +1 -0
- package/dist/modules/launcher/credential_bootstrap.js +303 -0
- package/dist/modules/launcher/credential_bootstrap.js.map +1 -0
- package/dist/modules/launcher/credential_daemon.d.ts +32 -0
- package/dist/modules/launcher/credential_daemon.d.ts.map +1 -0
- package/dist/modules/launcher/credential_daemon.js +173 -0
- package/dist/modules/launcher/credential_daemon.js.map +1 -0
- package/dist/modules/launcher/credential_secret.d.ts +6 -0
- package/dist/modules/launcher/credential_secret.d.ts.map +1 -0
- package/dist/modules/launcher/credential_secret.js +15 -0
- package/dist/modules/launcher/credential_secret.js.map +1 -0
- package/dist/modules/launcher/foreign_cred_daemon.d.ts +2 -0
- package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -0
- package/dist/modules/launcher/foreign_cred_daemon.js +166 -0
- package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -0
- package/dist/modules/launcher/headless_password.d.ts +8 -0
- package/dist/modules/launcher/headless_password.d.ts.map +1 -0
- package/dist/modules/launcher/headless_password.js +33 -0
- package/dist/modules/launcher/headless_password.js.map +1 -0
- package/dist/modules/launcher/launch_modes.d.ts +36 -0
- package/dist/modules/launcher/launch_modes.d.ts.map +1 -0
- package/dist/modules/launcher/launch_modes.js +129 -0
- package/dist/modules/launcher/launch_modes.js.map +1 -0
- package/dist/modules/launcher/market_adapter_runtime.d.ts +43 -0
- package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -0
- package/dist/modules/launcher/market_adapter_runtime.js +217 -0
- package/dist/modules/launcher/market_adapter_runtime.js.map +1 -0
- package/dist/modules/launcher/market_adapter_watchdog.d.ts +26 -0
- package/dist/modules/launcher/market_adapter_watchdog.d.ts.map +1 -0
- package/dist/modules/launcher/market_adapter_watchdog.js +214 -0
- package/dist/modules/launcher/market_adapter_watchdog.js.map +1 -0
- package/dist/modules/launcher/monolithic_runtime.d.ts +89 -0
- package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -0
- package/dist/modules/launcher/monolithic_runtime.js +425 -0
- package/dist/modules/launcher/monolithic_runtime.js.map +1 -0
- package/dist/modules/launcher/runtime_entry.d.ts +26 -0
- package/dist/modules/launcher/runtime_entry.d.ts.map +1 -0
- package/dist/modules/launcher/runtime_entry.js +49 -0
- package/dist/modules/launcher/runtime_entry.js.map +1 -0
- package/dist/modules/launcher/status_reporting.d.ts +48 -0
- package/dist/modules/launcher/status_reporting.d.ts.map +1 -0
- package/dist/modules/launcher/status_reporting.js +113 -0
- package/dist/modules/launcher/status_reporting.js.map +1 -0
- package/dist/modules/launcher/supervisor_control.d.ts +6 -0
- package/dist/modules/launcher/supervisor_control.d.ts.map +1 -0
- package/dist/modules/launcher/supervisor_control.js +59 -0
- package/dist/modules/launcher/supervisor_control.js.map +1 -0
- package/dist/modules/logger.d.ts +2 -0
- package/dist/modules/logger.d.ts.map +1 -0
- package/dist/modules/logger.js +71 -0
- package/dist/modules/logger.js.map +1 -0
- package/dist/modules/market_adapter_whitelist.d.ts +22 -0
- package/dist/modules/market_adapter_whitelist.d.ts.map +1 -0
- package/dist/modules/market_adapter_whitelist.js +82 -0
- package/dist/modules/market_adapter_whitelist.js.map +1 -0
- package/dist/modules/node_health_cache.d.ts +55 -0
- package/dist/modules/node_health_cache.d.ts.map +1 -0
- package/dist/modules/node_health_cache.js +134 -0
- package/dist/modules/node_health_cache.js.map +1 -0
- package/dist/modules/node_manager.d.ts +215 -0
- package/dist/modules/node_manager.d.ts.map +1 -0
- package/dist/modules/node_manager.js +628 -0
- package/dist/modules/node_manager.js.map +1 -0
- package/dist/modules/order/accounting.d.ts +349 -0
- package/dist/modules/order/accounting.d.ts.map +1 -0
- package/dist/modules/order/accounting.js +1191 -0
- package/dist/modules/order/accounting.js.map +1 -0
- package/dist/modules/order/async_lock.d.ts +126 -0
- package/dist/modules/order/async_lock.d.ts.map +1 -0
- package/dist/modules/order/async_lock.js +195 -0
- package/dist/modules/order/async_lock.js.map +1 -0
- package/dist/modules/order/export.d.ts +129 -0
- package/dist/modules/order/export.d.ts.map +1 -0
- package/dist/modules/order/export.js +316 -0
- package/dist/modules/order/export.js.map +1 -0
- package/dist/modules/order/format.d.ts +158 -0
- package/dist/modules/order/format.d.ts.map +1 -0
- package/dist/modules/order/format.js +232 -0
- package/dist/modules/order/format.js.map +1 -0
- package/dist/modules/order/grid.d.ts +549 -0
- package/dist/modules/order/grid.d.ts.map +1 -0
- package/dist/modules/order/grid.js +1746 -0
- package/dist/modules/order/grid.js.map +1 -0
- package/dist/modules/order/grid_reconcile.d.ts +154 -0
- package/dist/modules/order/grid_reconcile.d.ts.map +1 -0
- package/dist/modules/order/grid_reconcile.js +1192 -0
- package/dist/modules/order/grid_reconcile.js.map +1 -0
- package/dist/modules/order/index.d.ts +55 -0
- package/dist/modules/order/index.d.ts.map +1 -0
- package/dist/modules/order/index.js +79 -0
- package/dist/modules/order/index.js.map +1 -0
- package/dist/modules/order/logger.d.ts +136 -0
- package/dist/modules/order/logger.d.ts.map +1 -0
- package/dist/modules/order/logger.js +614 -0
- package/dist/modules/order/logger.js.map +1 -0
- package/dist/modules/order/logger_state.d.ts +133 -0
- package/dist/modules/order/logger_state.d.ts.map +1 -0
- package/dist/modules/order/logger_state.js +170 -0
- package/dist/modules/order/logger_state.js.map +1 -0
- package/dist/modules/order/manager.d.ts +413 -0
- package/dist/modules/order/manager.d.ts.map +1 -0
- package/dist/modules/order/manager.js +1605 -0
- package/dist/modules/order/manager.js.map +1 -0
- package/dist/modules/order/processed_fill_store.d.ts +135 -0
- package/dist/modules/order/processed_fill_store.d.ts.map +1 -0
- package/dist/modules/order/processed_fill_store.js +288 -0
- package/dist/modules/order/processed_fill_store.js.map +1 -0
- package/dist/modules/order/runner.d.ts +70 -0
- package/dist/modules/order/runner.d.ts.map +1 -0
- package/dist/modules/order/runner.js +140 -0
- package/dist/modules/order/runner.js.map +1 -0
- package/dist/modules/order/strategy.d.ts +196 -0
- package/dist/modules/order/strategy.d.ts.map +1 -0
- package/dist/modules/order/strategy.js +398 -0
- package/dist/modules/order/strategy.js.map +1 -0
- package/dist/modules/order/sync_engine.d.ts +386 -0
- package/dist/modules/order/sync_engine.d.ts.map +1 -0
- package/dist/modules/order/sync_engine.js +1459 -0
- package/dist/modules/order/sync_engine.js.map +1 -0
- package/dist/modules/order/utils/math.d.ts +677 -0
- package/dist/modules/order/utils/math.d.ts.map +1 -0
- package/dist/modules/order/utils/math.js +1172 -0
- package/dist/modules/order/utils/math.js.map +1 -0
- package/dist/modules/order/utils/order.d.ts +572 -0
- package/dist/modules/order/utils/order.d.ts.map +1 -0
- package/dist/modules/order/utils/order.js +1145 -0
- package/dist/modules/order/utils/order.js.map +1 -0
- package/dist/modules/order/utils/system.d.ts +268 -0
- package/dist/modules/order/utils/system.d.ts.map +1 -0
- package/dist/modules/order/utils/system.js +1261 -0
- package/dist/modules/order/utils/system.js.map +1 -0
- package/dist/modules/order/utils/validate.d.ts +280 -0
- package/dist/modules/order/utils/validate.d.ts.map +1 -0
- package/dist/modules/order/utils/validate.js +918 -0
- package/dist/modules/order/utils/validate.js.map +1 -0
- package/dist/modules/order/working_grid.d.ts +212 -0
- package/dist/modules/order/working_grid.d.ts.map +1 -0
- package/dist/modules/order/working_grid.js +279 -0
- package/dist/modules/order/working_grid.js.map +1 -0
- package/dist/modules/path_api.d.ts +32 -0
- package/dist/modules/path_api.d.ts.map +1 -0
- package/dist/modules/path_api.js +148 -0
- package/dist/modules/path_api.js.map +1 -0
- package/dist/modules/paths.d.ts +58 -0
- package/dist/modules/paths.d.ts.map +1 -0
- package/dist/modules/paths.js +82 -0
- package/dist/modules/paths.js.map +1 -0
- package/dist/modules/process_discovery.d.ts +58 -0
- package/dist/modules/process_discovery.d.ts.map +1 -0
- package/dist/modules/process_discovery.js +265 -0
- package/dist/modules/process_discovery.js.map +1 -0
- package/dist/modules/runtime.d.ts +34 -0
- package/dist/modules/runtime.d.ts.map +1 -0
- package/dist/modules/runtime.js +98 -0
- package/dist/modules/runtime.js.map +1 -0
- package/dist/modules/runtime_settings.d.ts +12 -0
- package/dist/modules/runtime_settings.d.ts.map +1 -0
- package/dist/modules/runtime_settings.js +122 -0
- package/dist/modules/runtime_settings.js.map +1 -0
- package/dist/modules/settings_merge.d.ts +38 -0
- package/dist/modules/settings_merge.d.ts.map +1 -0
- package/dist/modules/settings_merge.js +246 -0
- package/dist/modules/settings_merge.js.map +1 -0
- package/dist/modules/storage/browser_adapter.d.ts +56 -0
- package/dist/modules/storage/browser_adapter.d.ts.map +1 -0
- package/dist/modules/storage/browser_adapter.js +231 -0
- package/dist/modules/storage/browser_adapter.js.map +1 -0
- package/dist/modules/storage/index.d.ts +28 -0
- package/dist/modules/storage/index.d.ts.map +1 -0
- package/dist/modules/storage/index.js +52 -0
- package/dist/modules/storage/index.js.map +1 -0
- package/dist/modules/storage/node_adapter.d.ts +49 -0
- package/dist/modules/storage/node_adapter.d.ts.map +1 -0
- package/dist/modules/storage/node_adapter.js +167 -0
- package/dist/modules/storage/node_adapter.js.map +1 -0
- package/dist/modules/storage/types.d.ts +92 -0
- package/dist/modules/storage/types.d.ts.map +1 -0
- package/dist/modules/storage/types.js +3 -0
- package/dist/modules/storage/types.js.map +1 -0
- package/dist/modules/types.d.ts +1382 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +11 -0
- package/dist/modules/types.js.map +1 -0
- package/dist/modules/utils/base58check.d.ts +12 -0
- package/dist/modules/utils/base58check.d.ts.map +1 -0
- package/dist/modules/utils/base58check.js +112 -0
- package/dist/modules/utils/base58check.js.map +1 -0
- package/dist/modules/utils/build_dir.d.ts +7 -0
- package/dist/modules/utils/build_dir.d.ts.map +1 -0
- package/dist/modules/utils/build_dir.js +8 -0
- package/dist/modules/utils/build_dir.js.map +1 -0
- package/dist/modules/utils/fs_utils.d.ts +25 -0
- package/dist/modules/utils/fs_utils.d.ts.map +1 -0
- package/dist/modules/utils/fs_utils.js +27 -0
- package/dist/modules/utils/fs_utils.js.map +1 -0
- package/dist/modules/utils/math_utils.d.ts +10 -0
- package/dist/modules/utils/math_utils.d.ts.map +1 -0
- package/dist/modules/utils/math_utils.js +17 -0
- package/dist/modules/utils/math_utils.js.map +1 -0
- package/dist/modules/validate_profiles.d.ts +37 -0
- package/dist/modules/validate_profiles.d.ts.map +1 -0
- package/dist/modules/validate_profiles.js +369 -0
- package/dist/modules/validate_profiles.js.map +1 -0
- package/dist/pm2.d.ts +167 -0
- package/dist/pm2.d.ts.map +1 -0
- package/dist/pm2.js +998 -0
- package/dist/pm2.js.map +1 -0
- package/dist/scripts/analyze-git.d.ts +11 -0
- package/dist/scripts/analyze-git.d.ts.map +1 -0
- package/dist/scripts/analyze-git.js +851 -0
- package/dist/scripts/analyze-git.js.map +1 -0
- package/dist/scripts/analyze-orders.d.ts +17 -0
- package/dist/scripts/analyze-orders.d.ts.map +1 -0
- package/dist/scripts/analyze-orders.js +1568 -0
- package/dist/scripts/analyze-orders.js.map +1 -0
- package/dist/scripts/diagnose-kibana-candles.d.ts +3 -0
- package/dist/scripts/diagnose-kibana-candles.d.ts.map +1 -0
- package/dist/scripts/diagnose-kibana-candles.js +82 -0
- package/dist/scripts/diagnose-kibana-candles.js.map +1 -0
- package/dist/scripts/diagnose-pool-history.d.ts +3 -0
- package/dist/scripts/diagnose-pool-history.d.ts.map +1 -0
- package/dist/scripts/diagnose-pool-history.js +296 -0
- package/dist/scripts/diagnose-pool-history.js.map +1 -0
- package/dist/scripts/divergence-calc.d.ts +26 -0
- package/dist/scripts/divergence-calc.d.ts.map +1 -0
- package/dist/scripts/divergence-calc.js +119 -0
- package/dist/scripts/divergence-calc.js.map +1 -0
- package/dist/scripts/generate_lp_chart.d.ts +31 -0
- package/dist/scripts/generate_lp_chart.d.ts.map +1 -0
- package/dist/scripts/generate_lp_chart.js +92 -0
- package/dist/scripts/generate_lp_chart.js.map +1 -0
- package/dist/scripts/generate_mainnet_corpus_report.d.ts +24 -0
- package/dist/scripts/generate_mainnet_corpus_report.d.ts.map +1 -0
- package/dist/scripts/generate_mainnet_corpus_report.js +237 -0
- package/dist/scripts/generate_mainnet_corpus_report.js.map +1 -0
- package/dist/scripts/generate_market_adapter_whitelist.d.ts +2 -0
- package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +1 -0
- package/dist/scripts/generate_market_adapter_whitelist.js +111 -0
- package/dist/scripts/generate_market_adapter_whitelist.js.map +1 -0
- package/dist/scripts/migrate_bot_keys.d.ts +6 -0
- package/dist/scripts/migrate_bot_keys.d.ts.map +1 -0
- package/dist/scripts/migrate_bot_keys.js +301 -0
- package/dist/scripts/migrate_bot_keys.js.map +1 -0
- package/dist/scripts/native_release_gates.d.ts +3 -0
- package/dist/scripts/native_release_gates.d.ts.map +1 -0
- package/dist/scripts/native_release_gates.js +52 -0
- package/dist/scripts/native_release_gates.js.map +1 -0
- package/dist/scripts/print_grid.d.ts +16 -0
- package/dist/scripts/print_grid.d.ts.map +1 -0
- package/dist/scripts/print_grid.js +80 -0
- package/dist/scripts/print_grid.js.map +1 -0
- package/dist/scripts/run-tests.d.ts +2 -0
- package/dist/scripts/run-tests.d.ts.map +1 -0
- package/dist/scripts/run-tests.js +49 -0
- package/dist/scripts/run-tests.js.map +1 -0
- package/dist/scripts/sync-version.d.ts +14 -0
- package/dist/scripts/sync-version.d.ts.map +1 -0
- package/dist/scripts/sync-version.js +158 -0
- package/dist/scripts/sync-version.js.map +1 -0
- package/dist/scripts/test-credit-renewal.d.ts +2 -0
- package/dist/scripts/test-credit-renewal.d.ts.map +1 -0
- package/dist/scripts/test-credit-renewal.js +329 -0
- package/dist/scripts/test-credit-renewal.js.map +1 -0
- package/dist/scripts/update.d.ts +24 -0
- package/dist/scripts/update.d.ts.map +1 -0
- package/dist/scripts/update.js +650 -0
- package/dist/scripts/update.js.map +1 -0
- package/dist/scripts/validate_bots.d.ts +16 -0
- package/dist/scripts/validate_bots.d.ts.map +1 -0
- package/dist/scripts/validate_bots.js +106 -0
- package/dist/scripts/validate_bots.js.map +1 -0
- package/dist/scripts/verify-browser-bundle.d.ts +22 -0
- package/dist/scripts/verify-browser-bundle.d.ts.map +1 -0
- package/dist/scripts/verify-browser-bundle.js +339 -0
- package/dist/scripts/verify-browser-bundle.js.map +1 -0
- package/dist/unlock.d.ts +48 -0
- package/dist/unlock.d.ts.map +1 -0
- package/dist/unlock.js +925 -0
- package/dist/unlock.js.map +1 -0
- package/package.json +112 -0
- package/scripts/README.md +356 -0
- package/scripts/clear-all.sh +195 -0
- package/scripts/clear-logs.sh +95 -0
- package/scripts/clear-market-adapter.sh +196 -0
- package/scripts/clear-orders.sh +113 -0
- package/scripts/create-bot-symlinks.sh +51 -0
- package/scripts/postinstall.js +9 -0
- package/scripts/reset-settings.sh +118 -0
|
@@ -0,0 +1,1452 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DEXBot2 Credential Daemon Policy Engine
|
|
4
|
+
*
|
|
5
|
+
* Evaluates policies before key material is decrypted. Inspired by OWS pattern.
|
|
6
|
+
* Supports declarative rules (fast, in-process) + executable hooks (subprocess).
|
|
7
|
+
* AND semantics: all policies must allow, or signing is denied.
|
|
8
|
+
* Default-deny on errors: validation failures, executable timeouts, etc.
|
|
9
|
+
*/
|
|
10
|
+
const { path } = require('./path_api');
|
|
11
|
+
const { randomBytes, createHmac, timingSafeEqual } = require('./crypto/sync');
|
|
12
|
+
const { BitShares } = require('./bitshares_client');
|
|
13
|
+
const { isPositiveInt } = require('./order/utils/math');
|
|
14
|
+
const { parseJsonWithComments } = require('./order/utils/system');
|
|
15
|
+
const { FEE_PARAMETERS } = require('./constants');
|
|
16
|
+
const { getCredentialReadyFilePath, assertPrivatePathSecurity } = require('./credential_runtime');
|
|
17
|
+
const { PATHS } = require('./paths');
|
|
18
|
+
const Logger = require('./logger');
|
|
19
|
+
const { getStorage } = require('./storage');
|
|
20
|
+
const storage = getStorage();
|
|
21
|
+
const { runtime } = require('./runtime');
|
|
22
|
+
const { ensureDir, readJSON, safeUnlink, writeJSON } = require('./utils/fs_utils');
|
|
23
|
+
// Module-scope logger for library-style helpers that don't own a process
|
|
24
|
+
// logger. The class honours PM2 auto-quiet and routes to a log file when one
|
|
25
|
+
// is configured, matching the rest of the codebase.
|
|
26
|
+
const policyLogger = new Logger('credential-policy');
|
|
27
|
+
const BOTS_JSON_PATH = PATHS.PROFILES.BOTS_JSON;
|
|
28
|
+
const ASSET_OBJECT_ID_PATTERN = /^1\.3\.\d+$/;
|
|
29
|
+
const POLICY_DENIED_PREFIX = 'POLICY_DENIED: ';
|
|
30
|
+
const EXECUTABLE_TIMEOUT_MS = 5000;
|
|
31
|
+
// BitShares operation types that DEXBot2 uses
|
|
32
|
+
const ALLOWED_OP_TYPES = [
|
|
33
|
+
'transfer',
|
|
34
|
+
'limit_order_create',
|
|
35
|
+
'limit_order_cancel',
|
|
36
|
+
'call_order_update',
|
|
37
|
+
'liquidity_pool_exchange',
|
|
38
|
+
'limit_order_update',
|
|
39
|
+
'credit_offer_accept',
|
|
40
|
+
'credit_deal_repay',
|
|
41
|
+
'credit_deal_update',
|
|
42
|
+
];
|
|
43
|
+
// Hardcoded baseline policy used when resolving policy layers in-process.
|
|
44
|
+
// The credential daemon now requires an explicit on-disk policy file and
|
|
45
|
+
// fails closed on startup/reload mismatches.
|
|
46
|
+
const BUILTIN_DEFAULT_POLICY = Object.freeze({
|
|
47
|
+
allowedOps: Object.freeze({
|
|
48
|
+
limit_order_create: null,
|
|
49
|
+
limit_order_cancel: null,
|
|
50
|
+
limit_order_update: null,
|
|
51
|
+
call_order_update: null,
|
|
52
|
+
liquidity_pool_exchange: null,
|
|
53
|
+
transfer: null,
|
|
54
|
+
credit_offer_accept: null,
|
|
55
|
+
credit_deal_repay: null,
|
|
56
|
+
credit_deal_update: null,
|
|
57
|
+
}),
|
|
58
|
+
maxOpsPerBatch: 200,
|
|
59
|
+
allowedAssetIds: null,
|
|
60
|
+
executable: null,
|
|
61
|
+
});
|
|
62
|
+
const policyCache = new Map();
|
|
63
|
+
const assetRefResolutionCache = new Map();
|
|
64
|
+
let _externalAssetResolver = null;
|
|
65
|
+
/**
|
|
66
|
+
* Register an external asset-ref resolver used by the credential daemon.
|
|
67
|
+
* The daemon's native chain client is connected and can resolve symbol names,
|
|
68
|
+
* whereas the global BitShares object may not be initialised in daemon context.
|
|
69
|
+
*/
|
|
70
|
+
function setExternalAssetResolver(resolver) {
|
|
71
|
+
_externalAssetResolver = resolver;
|
|
72
|
+
}
|
|
73
|
+
async function resolveAssetRefToId(assetRef) {
|
|
74
|
+
if (!assetRef || typeof assetRef !== 'string')
|
|
75
|
+
return null;
|
|
76
|
+
const cacheKey = String(assetRef);
|
|
77
|
+
if (assetRefResolutionCache.has(cacheKey)) {
|
|
78
|
+
return assetRefResolutionCache.get(cacheKey);
|
|
79
|
+
}
|
|
80
|
+
let resolvedId = null;
|
|
81
|
+
// Try external resolver first (credential daemon with native chain client).
|
|
82
|
+
// Only registered by the daemon; the legacy bot process path never sets one.
|
|
83
|
+
// If it fails (e.g. native client not yet connected), fall through to the
|
|
84
|
+
// legacy BitShares path below.
|
|
85
|
+
if (_externalAssetResolver) {
|
|
86
|
+
try {
|
|
87
|
+
const result = await _externalAssetResolver(cacheKey);
|
|
88
|
+
if (result) {
|
|
89
|
+
assetRefResolutionCache.set(cacheKey, result);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (_) {
|
|
94
|
+
// fall through — native client may not be connected yet
|
|
95
|
+
}
|
|
96
|
+
// Don't cache null from external resolver; the native client may not
|
|
97
|
+
// be connected yet and would have returned a transient failure.
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
if (ASSET_OBJECT_ID_PATTERN.test(cacheKey)) {
|
|
101
|
+
resolvedId = cacheKey;
|
|
102
|
+
}
|
|
103
|
+
else if (BitShares?.db?.lookup_asset_symbols) {
|
|
104
|
+
const result = await BitShares.db.lookup_asset_symbols([cacheKey]);
|
|
105
|
+
const asset = Array.isArray(result) ? result[0] : null;
|
|
106
|
+
resolvedId = asset?.id ? String(asset.id) : null;
|
|
107
|
+
}
|
|
108
|
+
else if (BitShares?.db?.get_assets) {
|
|
109
|
+
const result = await BitShares.db.get_assets([cacheKey]);
|
|
110
|
+
const asset = Array.isArray(result) ? result[0] : null;
|
|
111
|
+
resolvedId = asset?.id ? String(asset.id) : null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (_) {
|
|
115
|
+
resolvedId = null;
|
|
116
|
+
}
|
|
117
|
+
if (resolvedId)
|
|
118
|
+
assetRefResolutionCache.set(cacheKey, resolvedId);
|
|
119
|
+
return resolvedId;
|
|
120
|
+
}
|
|
121
|
+
async function resolveConfiguredAssetRefs(refs, label) {
|
|
122
|
+
const resolved = [];
|
|
123
|
+
for (const ref of refs) {
|
|
124
|
+
if (!ref)
|
|
125
|
+
continue;
|
|
126
|
+
const normalizedRef = String(ref);
|
|
127
|
+
if (ASSET_OBJECT_ID_PATTERN.test(normalizedRef)) {
|
|
128
|
+
resolved.push(normalizedRef);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const resolvedId = await resolveAssetRefToId(normalizedRef);
|
|
132
|
+
if (!resolvedId) {
|
|
133
|
+
return {
|
|
134
|
+
ok: false,
|
|
135
|
+
reason: `unable to resolve asset ref "${normalizedRef}" from ${label}`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
resolved.push(String(resolvedId));
|
|
139
|
+
}
|
|
140
|
+
return { ok: true, values: resolved };
|
|
141
|
+
}
|
|
142
|
+
function normalizeGrapheneCollateralRatio(value) {
|
|
143
|
+
const numeric = Number(value);
|
|
144
|
+
if (!Number.isFinite(numeric) || numeric <= 0)
|
|
145
|
+
return null;
|
|
146
|
+
const denom = FEE_PARAMETERS.GRAPHENE_COLLATERAL_RATIO_DENOM;
|
|
147
|
+
return numeric >= denom ? numeric / denom : numeric;
|
|
148
|
+
}
|
|
149
|
+
function createMinimalPolicyConfig() {
|
|
150
|
+
return {
|
|
151
|
+
accounts: {},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function readPolicyConfigDetailed(filePath) {
|
|
155
|
+
if (!storage.exists(filePath)) {
|
|
156
|
+
return {
|
|
157
|
+
status: 'missing',
|
|
158
|
+
config: null,
|
|
159
|
+
error: `config file not found: ${filePath}`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
let raw;
|
|
163
|
+
try {
|
|
164
|
+
raw = readJSON(filePath);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
return {
|
|
168
|
+
status: 'invalid',
|
|
169
|
+
config: null,
|
|
170
|
+
error: `failed to load config: ${error.message}`,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const { valid, errors } = validatePolicyConfig(raw);
|
|
174
|
+
if (!valid) {
|
|
175
|
+
return {
|
|
176
|
+
status: 'invalid',
|
|
177
|
+
config: null,
|
|
178
|
+
error: `config validation failed: ${errors.join('; ')}`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
status: 'ok',
|
|
183
|
+
config: raw,
|
|
184
|
+
error: null,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Check that a policy config file has restrictive permissions (0o600).
|
|
189
|
+
* MIGRATION: Auto-remediates legacy 0o644 mode with a warning, matching
|
|
190
|
+
* the behavior of checkKeysFileSecurity in chain_keys.ts.
|
|
191
|
+
*
|
|
192
|
+
* @param {string} filePath - Path to daemon-policies.json
|
|
193
|
+
*/
|
|
194
|
+
function checkPolicyFileSecurity(filePath) {
|
|
195
|
+
if (!storage.exists(filePath))
|
|
196
|
+
return;
|
|
197
|
+
try {
|
|
198
|
+
assertPrivatePathSecurity(filePath, { expectedType: 'file', requiredMode: 0o600 });
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
const stat = storage.lstat(filePath);
|
|
202
|
+
const mode = stat.mode & 0o777;
|
|
203
|
+
if (mode === 0o644 && !stat.isSymbolicLink()) {
|
|
204
|
+
storage.chmod(filePath, 0o600);
|
|
205
|
+
policyLogger.warn(`[security] Auto-fixed ${filePath} permissions from 0o644 to 0o600. Run: chmod 600 profiles/daemon-policies.json`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
throw err;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Ensure daemon-policies.json exists before the credential daemon starts.
|
|
213
|
+
* Missing files are initialized to a minimal strict-compatible policy; invalid
|
|
214
|
+
* existing files still fail closed and are not overwritten.
|
|
215
|
+
*
|
|
216
|
+
* @param {string} filePath - Path to daemon-policies.json
|
|
217
|
+
* @returns {object} Valid parsed config
|
|
218
|
+
* @throws {Error} When the existing file is invalid or creation fails
|
|
219
|
+
*/
|
|
220
|
+
function ensurePolicyConfig(filePath) {
|
|
221
|
+
if (!storage.exists(filePath)) {
|
|
222
|
+
try {
|
|
223
|
+
storage.ensureDir(path.dirname(filePath));
|
|
224
|
+
storage.writeJSON(filePath, createMinimalPolicyConfig(), { mode: 0o600, flag: 'wx' });
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
if (err.code !== 'EEXIST') {
|
|
228
|
+
const wrapped = new Error(`Failed to create required policy config: ${err.message}`);
|
|
229
|
+
wrapped.code = 'POLICY_CONFIG_CREATE_FAILED';
|
|
230
|
+
throw wrapped;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return loadRequiredPolicyConfig(filePath);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Load and parse daemon-policies.json. Returns normalized config or throws on
|
|
238
|
+
* error/absence (daemon uses loadRequiredPolicyConfig which throws).
|
|
239
|
+
*
|
|
240
|
+
* @param {string} filePath - Path to daemon-policies.json
|
|
241
|
+
* @param {object} [options={}] - Options
|
|
242
|
+
* @param {boolean} [options.forceReload=false] - If true, bypass cache and reload from disk
|
|
243
|
+
*/
|
|
244
|
+
function loadPolicyConfig(filePath, options = {}) {
|
|
245
|
+
const forceReload = options.forceReload || false;
|
|
246
|
+
if (!forceReload && policyCache.has(filePath)) {
|
|
247
|
+
return policyCache.get(filePath);
|
|
248
|
+
}
|
|
249
|
+
const detailed = readPolicyConfigDetailed(filePath);
|
|
250
|
+
if (detailed.status !== 'ok') {
|
|
251
|
+
policyLogger.warn(`[policy] ${detailed.error} — using builtin defaults`);
|
|
252
|
+
policyCache.set(filePath, null);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
policyCache.set(filePath, detailed.config);
|
|
256
|
+
return detailed.config;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Reload daemon-policies.json from disk with caller-controlled failure
|
|
260
|
+
* semantics. Single source of truth for both the SIGHUP handler
|
|
261
|
+
* (operator-initiated, fail closed) and the fs.watch debounce
|
|
262
|
+
* (auto-provision, keep last-good in-memory config).
|
|
263
|
+
*
|
|
264
|
+
* @param {string} filePath - Path to daemon-policies.json
|
|
265
|
+
* @param {object} [options={}] - Options
|
|
266
|
+
* @param {boolean} [options.strict=false] - When true, rethrows the load
|
|
267
|
+
* error so the caller can decide the response (e.g. shutdown). When
|
|
268
|
+
* false (default), returns null on failure so the caller can keep the
|
|
269
|
+
* existing in-memory config and log a warning.
|
|
270
|
+
* @returns {object|null} Parsed config on success, null on non-strict failure
|
|
271
|
+
*/
|
|
272
|
+
function reloadPolicyFromDisk(filePath, options = {}) {
|
|
273
|
+
const strict = options.strict === true;
|
|
274
|
+
try {
|
|
275
|
+
return loadRequiredPolicyConfig(filePath);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
if (strict)
|
|
279
|
+
throw err;
|
|
280
|
+
policyLogger.warn(`[policy] Reload from ${filePath} failed: ${err.message} — keeping in-memory config`);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Load daemon-policies.json as a required runtime dependency.
|
|
286
|
+
* Used by the credential daemon, which fails closed on missing/invalid policy.
|
|
287
|
+
*
|
|
288
|
+
* @param {string} filePath - Path to daemon-policies.json
|
|
289
|
+
* @returns {object} Valid parsed config
|
|
290
|
+
* @throws {Error} When the file is missing or invalid
|
|
291
|
+
*/
|
|
292
|
+
function loadRequiredPolicyConfig(filePath) {
|
|
293
|
+
const detailed = readPolicyConfigDetailed(filePath);
|
|
294
|
+
if (detailed.status !== 'ok') {
|
|
295
|
+
policyCache.set(filePath, null);
|
|
296
|
+
const err = new Error(`Required policy config ${detailed.status}: ${detailed.error}`);
|
|
297
|
+
err.code = detailed.status === 'missing'
|
|
298
|
+
? 'POLICY_CONFIG_MISSING'
|
|
299
|
+
: 'POLICY_CONFIG_INVALID';
|
|
300
|
+
throw err;
|
|
301
|
+
}
|
|
302
|
+
policyCache.set(filePath, detailed.config);
|
|
303
|
+
return detailed.config;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Helper: check if value is an array of strings
|
|
307
|
+
*/
|
|
308
|
+
function isStringArray(v) {
|
|
309
|
+
return Array.isArray(v) && v.every((x) => typeof x === 'string');
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Validate per-operation constraints. Returns { errors: string[] }.
|
|
313
|
+
* Constraint fields are validated based on operation type.
|
|
314
|
+
*/
|
|
315
|
+
function validateOpConstraints(opName, constraints) {
|
|
316
|
+
const errors = [];
|
|
317
|
+
// transfer
|
|
318
|
+
if (opName === 'transfer') {
|
|
319
|
+
if (constraints.allowedToAccounts !== undefined && !isStringArray(constraints.allowedToAccounts))
|
|
320
|
+
errors.push('allowedToAccounts must be an array of strings');
|
|
321
|
+
if (constraints.allowedAssets !== undefined && !isStringArray(constraints.allowedAssets))
|
|
322
|
+
errors.push('allowedAssets must be an array of strings');
|
|
323
|
+
if (constraints.maxAmount !== undefined && !isPositiveInt(constraints.maxAmount))
|
|
324
|
+
errors.push('maxAmount must be a positive integer');
|
|
325
|
+
}
|
|
326
|
+
// Fields valid for limit_order_create and limit_order_update
|
|
327
|
+
if (['limit_order_create', 'limit_order_update'].includes(opName)) {
|
|
328
|
+
if (constraints.allowedSellAssets !== undefined) {
|
|
329
|
+
if (!isStringArray(constraints.allowedSellAssets))
|
|
330
|
+
errors.push('allowedSellAssets must be an array of strings');
|
|
331
|
+
}
|
|
332
|
+
if (constraints.allowedReceiveAssets !== undefined) {
|
|
333
|
+
if (!isStringArray(constraints.allowedReceiveAssets))
|
|
334
|
+
errors.push('allowedReceiveAssets must be an array of strings');
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// maxSellAmount, maxReceiveAmount, allowFillOrKill — only for limit_order_create
|
|
338
|
+
if (opName === 'limit_order_create') {
|
|
339
|
+
if (constraints.maxSellAmount !== undefined && !isPositiveInt(constraints.maxSellAmount))
|
|
340
|
+
errors.push('maxSellAmount must be a positive integer');
|
|
341
|
+
if (constraints.maxReceiveAmount !== undefined && !isPositiveInt(constraints.maxReceiveAmount))
|
|
342
|
+
errors.push('maxReceiveAmount must be a positive integer');
|
|
343
|
+
if (constraints.allowFillOrKill !== undefined && typeof constraints.allowFillOrKill !== 'boolean')
|
|
344
|
+
errors.push('allowFillOrKill must be a boolean');
|
|
345
|
+
}
|
|
346
|
+
// maxDeltaSellAmount — only for limit_order_update
|
|
347
|
+
if (opName === 'limit_order_update') {
|
|
348
|
+
if (constraints.maxDeltaSellAmount !== undefined && !isPositiveInt(constraints.maxDeltaSellAmount))
|
|
349
|
+
errors.push('maxDeltaSellAmount must be a positive integer');
|
|
350
|
+
}
|
|
351
|
+
// call_order_update
|
|
352
|
+
if (opName === 'call_order_update') {
|
|
353
|
+
if (constraints.allowedAssets !== undefined && !isStringArray(constraints.allowedAssets))
|
|
354
|
+
errors.push('allowedAssets must be an array of strings');
|
|
355
|
+
if (constraints.collateralAsset !== undefined && typeof constraints.collateralAsset !== 'string')
|
|
356
|
+
errors.push('collateralAsset must be a string');
|
|
357
|
+
if (constraints.allowedCollateralAssets !== undefined && !isStringArray(constraints.allowedCollateralAssets))
|
|
358
|
+
errors.push('allowedCollateralAssets must be an array of strings');
|
|
359
|
+
if (constraints.maxDeltaCollateral !== undefined && !isPositiveInt(constraints.maxDeltaCollateral))
|
|
360
|
+
errors.push('maxDeltaCollateral must be a positive integer');
|
|
361
|
+
if (constraints.maxDeltaDebt !== undefined && !isPositiveInt(constraints.maxDeltaDebt))
|
|
362
|
+
errors.push('maxDeltaDebt must be a positive integer');
|
|
363
|
+
if (constraints.minCollateralRatio !== undefined && typeof constraints.minCollateralRatio !== 'number')
|
|
364
|
+
errors.push('minCollateralRatio must be a number');
|
|
365
|
+
if (constraints.maxCollateralRatio !== undefined && typeof constraints.maxCollateralRatio !== 'number')
|
|
366
|
+
errors.push('maxCollateralRatio must be a number');
|
|
367
|
+
if (constraints.targetCollateralRatio !== undefined && typeof constraints.targetCollateralRatio !== 'number')
|
|
368
|
+
errors.push('targetCollateralRatio must be a number');
|
|
369
|
+
}
|
|
370
|
+
// credit_offer_accept
|
|
371
|
+
if (opName === 'credit_offer_accept') {
|
|
372
|
+
if (constraints.allowedOfferIds !== undefined && !isStringArray(constraints.allowedOfferIds))
|
|
373
|
+
errors.push('allowedOfferIds must be an array of strings');
|
|
374
|
+
if (constraints.collateralAsset !== undefined && typeof constraints.collateralAsset !== 'string')
|
|
375
|
+
errors.push('collateralAsset must be a string');
|
|
376
|
+
if (constraints.allowedCollateralAssets !== undefined && !isStringArray(constraints.allowedCollateralAssets))
|
|
377
|
+
errors.push('allowedCollateralAssets must be an array of strings');
|
|
378
|
+
if (constraints.allowedDebtAssets !== undefined && !isStringArray(constraints.allowedDebtAssets))
|
|
379
|
+
errors.push('allowedDebtAssets must be an array of strings');
|
|
380
|
+
if (constraints.maxFeeRate !== undefined && !isPositiveInt(constraints.maxFeeRate))
|
|
381
|
+
errors.push('maxFeeRate must be a positive integer');
|
|
382
|
+
if (constraints.minDurationSeconds !== undefined && !isPositiveInt(constraints.minDurationSeconds))
|
|
383
|
+
errors.push('minDurationSeconds must be a positive integer');
|
|
384
|
+
}
|
|
385
|
+
// credit_deal_repay
|
|
386
|
+
if (opName === 'credit_deal_repay') {
|
|
387
|
+
if (constraints.disallowedDealIds !== undefined && !isStringArray(constraints.disallowedDealIds))
|
|
388
|
+
errors.push('disallowedDealIds must be an array of strings');
|
|
389
|
+
if (constraints.maxRepayAmount !== undefined && !isPositiveInt(constraints.maxRepayAmount))
|
|
390
|
+
errors.push('maxRepayAmount must be a positive integer');
|
|
391
|
+
if (constraints.maxCreditFee !== undefined && !isPositiveInt(constraints.maxCreditFee))
|
|
392
|
+
errors.push('maxCreditFee must be a positive integer');
|
|
393
|
+
}
|
|
394
|
+
// credit_deal_update
|
|
395
|
+
if (opName === 'credit_deal_update') {
|
|
396
|
+
if (constraints.disallowedDealIds !== undefined && !isStringArray(constraints.disallowedDealIds))
|
|
397
|
+
errors.push('disallowedDealIds must be an array of strings');
|
|
398
|
+
if (constraints.allowAutoRepay !== undefined && typeof constraints.allowAutoRepay !== 'boolean')
|
|
399
|
+
errors.push('allowAutoRepay must be a boolean');
|
|
400
|
+
}
|
|
401
|
+
// liquidity_pool_exchange
|
|
402
|
+
if (opName === 'liquidity_pool_exchange') {
|
|
403
|
+
if (constraints.allowedPools !== undefined && !isStringArray(constraints.allowedPools))
|
|
404
|
+
errors.push('allowedPools must be an array of strings');
|
|
405
|
+
if (constraints.allowedSellAssets !== undefined && !isStringArray(constraints.allowedSellAssets))
|
|
406
|
+
errors.push('allowedSellAssets must be an array of strings');
|
|
407
|
+
if (constraints.allowedReceiveAssets !== undefined && !isStringArray(constraints.allowedReceiveAssets))
|
|
408
|
+
errors.push('allowedReceiveAssets must be an array of strings');
|
|
409
|
+
if (constraints.maxSellAmount !== undefined && !isPositiveInt(constraints.maxSellAmount))
|
|
410
|
+
errors.push('maxSellAmount must be a positive integer');
|
|
411
|
+
}
|
|
412
|
+
// limit_order_cancel has no constraints
|
|
413
|
+
return { errors };
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Validate raw policy config. Returns { valid: boolean, errors: string[] }.
|
|
417
|
+
*/
|
|
418
|
+
function validatePolicyConfig(raw) {
|
|
419
|
+
const errors = [];
|
|
420
|
+
if (typeof raw !== 'object' || raw === null) {
|
|
421
|
+
errors.push('root must be an object');
|
|
422
|
+
return { valid: false, errors };
|
|
423
|
+
}
|
|
424
|
+
// sessionTtlMs: optional positive integer
|
|
425
|
+
if (raw.sessionTtlMs !== undefined) {
|
|
426
|
+
if (typeof raw.sessionTtlMs !== 'number' || raw.sessionTtlMs <= 0) {
|
|
427
|
+
errors.push('sessionTtlMs must be a positive integer');
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
// default: optional policy object
|
|
431
|
+
if (raw.default !== undefined) {
|
|
432
|
+
if (typeof raw.default !== 'object' || raw.default === null) {
|
|
433
|
+
errors.push('default must be an object');
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
const { valid: validDefault, errors: defaultErrors } = validatePolicyObject(raw.default);
|
|
437
|
+
if (!validDefault) {
|
|
438
|
+
errors.push(`default: ${defaultErrors.join('; ')}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
// accounts: optional object of policies
|
|
443
|
+
if (raw.accounts !== undefined) {
|
|
444
|
+
if (typeof raw.accounts !== 'object' || Array.isArray(raw.accounts)) {
|
|
445
|
+
errors.push('accounts must be an object');
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
for (const [accountName, policy] of Object.entries(raw.accounts)) {
|
|
449
|
+
if (typeof policy !== 'object' || policy === null) {
|
|
450
|
+
errors.push(`accounts.${accountName} must be an object`);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
const { valid: validPolicy, errors: policyErrors } = validatePolicyObject(policy);
|
|
454
|
+
if (!validPolicy) {
|
|
455
|
+
errors.push(`accounts.${accountName}: ${policyErrors.join('; ')}`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return { valid: errors.length === 0, errors };
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Validate a single policy object (used by both default and per-account policies).
|
|
465
|
+
*/
|
|
466
|
+
function validatePolicyObject(policy) {
|
|
467
|
+
const errors = [];
|
|
468
|
+
// allowedOpTypes: must be array of strings
|
|
469
|
+
if (policy.allowedOpTypes !== undefined) {
|
|
470
|
+
if (!Array.isArray(policy.allowedOpTypes)) {
|
|
471
|
+
errors.push('allowedOpTypes must be an array');
|
|
472
|
+
}
|
|
473
|
+
else if (!policy.allowedOpTypes.every((x) => typeof x === 'string')) {
|
|
474
|
+
errors.push('allowedOpTypes must be an array of strings');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// maxOpsPerBatch: must be positive integer
|
|
478
|
+
if (policy.maxOpsPerBatch !== undefined) {
|
|
479
|
+
if (typeof policy.maxOpsPerBatch !== 'number' || policy.maxOpsPerBatch <= 0) {
|
|
480
|
+
errors.push('maxOpsPerBatch must be a positive integer');
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
// allowedAssetIds: optional array of strings
|
|
484
|
+
if (policy.allowedAssetIds !== undefined) {
|
|
485
|
+
if (policy.allowedAssetIds !== null) {
|
|
486
|
+
if (!Array.isArray(policy.allowedAssetIds)) {
|
|
487
|
+
errors.push('allowedAssetIds must be an array or null');
|
|
488
|
+
}
|
|
489
|
+
else if (!policy.allowedAssetIds.every((x) => typeof x === 'string')) {
|
|
490
|
+
errors.push('allowedAssetIds must be an array of strings');
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
// executable: optional string path or null
|
|
495
|
+
if (policy.executable !== undefined) {
|
|
496
|
+
if (policy.executable !== null && typeof policy.executable !== 'string') {
|
|
497
|
+
errors.push('executable must be a string path or null');
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
// botHmacSecret: optional 64-char hex string (32 bytes)
|
|
501
|
+
if (policy.botHmacSecret !== undefined) {
|
|
502
|
+
if (typeof policy.botHmacSecret !== 'string' || !/^[0-9a-f]{64}$/i.test(policy.botHmacSecret)) {
|
|
503
|
+
errors.push('botHmacSecret must be a 64-char hex string (32 bytes)');
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
// allowedOps: optional object keyed by op_name → constraints (object or null)
|
|
507
|
+
if (policy.allowedOps !== undefined) {
|
|
508
|
+
if (policy.allowedOps !== null) {
|
|
509
|
+
if (typeof policy.allowedOps !== 'object' || Array.isArray(policy.allowedOps)) {
|
|
510
|
+
errors.push('allowedOps must be an object or null');
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
for (const [opName, constraints] of Object.entries(policy.allowedOps)) {
|
|
514
|
+
if (constraints !== null) {
|
|
515
|
+
if (typeof constraints !== 'object' || Array.isArray(constraints)) {
|
|
516
|
+
errors.push(`allowedOps.${opName} must be an object or null`);
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
const { errors: cErrors } = validateOpConstraints(opName, constraints);
|
|
520
|
+
for (const e of cErrors)
|
|
521
|
+
errors.push(`allowedOps.${opName}: ${e}`);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return { valid: errors.length === 0, errors };
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Derive debt-policy constraints from profiles/bots.json for an account.
|
|
532
|
+
* Scans all bots using `accountName` as preferredAccount and extracts
|
|
533
|
+
* collateralAsset / asset mappings from debtPolicy.lending[].
|
|
534
|
+
*
|
|
535
|
+
* Returns { call_order_update?, credit_offer_accept?, credit_deal_repay? }
|
|
536
|
+
* where each op constraint may contain:
|
|
537
|
+
* - collateralAsset (string) — if all lending items for that op type share one collateral
|
|
538
|
+
* - allowedCollateralAssets (string[]) — if multiple collaterals are used
|
|
539
|
+
* - allowedDebtAssets (string[]) — debt assets used in credit lending items
|
|
540
|
+
*/
|
|
541
|
+
function deriveDebtPolicyConstraints(accountName) {
|
|
542
|
+
if (!accountName)
|
|
543
|
+
return {};
|
|
544
|
+
try {
|
|
545
|
+
if (!storage.exists(BOTS_JSON_PATH))
|
|
546
|
+
return {};
|
|
547
|
+
const raw = storage.readFile(BOTS_JSON_PATH);
|
|
548
|
+
const parsed = parseJsonWithComments(raw);
|
|
549
|
+
const bots = Array.isArray(parsed)
|
|
550
|
+
? parsed.filter(Boolean)
|
|
551
|
+
: (Array.isArray(parsed?.bots) ? parsed.bots.filter(Boolean) : []);
|
|
552
|
+
if (!Array.isArray(bots))
|
|
553
|
+
return {};
|
|
554
|
+
const mpaCollaterals = new Set();
|
|
555
|
+
const creditCollaterals = new Set();
|
|
556
|
+
const creditDebtAssets = new Set();
|
|
557
|
+
for (const bot of bots) {
|
|
558
|
+
if (!bot || bot.active === false)
|
|
559
|
+
continue;
|
|
560
|
+
const pref = bot.preferredAccount || bot.account;
|
|
561
|
+
if (pref !== accountName)
|
|
562
|
+
continue;
|
|
563
|
+
const dp = bot.debtPolicy;
|
|
564
|
+
if (!dp || !Array.isArray(dp.lending))
|
|
565
|
+
continue;
|
|
566
|
+
for (const item of dp.lending) {
|
|
567
|
+
if (!item || !item.asset || !item.collateralAsset)
|
|
568
|
+
continue;
|
|
569
|
+
if (item.type === 'mpa') {
|
|
570
|
+
mpaCollaterals.add(item.collateralAsset);
|
|
571
|
+
}
|
|
572
|
+
else if (item.type === 'creditOffer') {
|
|
573
|
+
creditCollaterals.add(item.collateralAsset);
|
|
574
|
+
creditDebtAssets.add(item.asset);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const constraints = {};
|
|
579
|
+
if (mpaCollaterals.size > 0) {
|
|
580
|
+
constraints.call_order_update = {};
|
|
581
|
+
if (mpaCollaterals.size === 1) {
|
|
582
|
+
constraints.call_order_update.collateralAsset = Array.from(mpaCollaterals)[0];
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
constraints.call_order_update.allowedCollateralAssets = Array.from(mpaCollaterals);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (creditCollaterals.size > 0 || creditDebtAssets.size > 0) {
|
|
589
|
+
constraints.credit_offer_accept = {};
|
|
590
|
+
if (creditCollaterals.size === 1) {
|
|
591
|
+
constraints.credit_offer_accept.collateralAsset = Array.from(creditCollaterals)[0];
|
|
592
|
+
}
|
|
593
|
+
else if (creditCollaterals.size > 1) {
|
|
594
|
+
constraints.credit_offer_accept.allowedCollateralAssets = Array.from(creditCollaterals);
|
|
595
|
+
}
|
|
596
|
+
if (creditDebtAssets.size > 0) {
|
|
597
|
+
constraints.credit_offer_accept.allowedDebtAssets = Array.from(creditDebtAssets);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (creditDebtAssets.size > 0) {
|
|
601
|
+
constraints.credit_deal_repay = {
|
|
602
|
+
allowedDebtAssets: Array.from(creditDebtAssets),
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
return constraints;
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
return {};
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Resolve the effective policy for an account by merging layers:
|
|
613
|
+
* builtin default → auto-derived debt constraints → config.default → config.accounts[accountName]
|
|
614
|
+
*/
|
|
615
|
+
function resolveAccountPolicy(config, accountName) {
|
|
616
|
+
// Start with builtin
|
|
617
|
+
let policy = JSON.parse(JSON.stringify(BUILTIN_DEFAULT_POLICY));
|
|
618
|
+
// Layer auto-derived debt constraints from bots.json
|
|
619
|
+
const debtConstraints = deriveDebtPolicyConstraints(accountName);
|
|
620
|
+
if (Object.keys(debtConstraints).length > 0) {
|
|
621
|
+
policy.allowedOps = { ...policy.allowedOps };
|
|
622
|
+
for (const [opName, constraints] of Object.entries(debtConstraints)) {
|
|
623
|
+
policy.allowedOps[opName] = { ...(policy.allowedOps[opName] || {}), ...constraints };
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
// Layer on config.default
|
|
627
|
+
if (config && config.default) {
|
|
628
|
+
policy = { ...policy, ...config.default };
|
|
629
|
+
}
|
|
630
|
+
// Layer on config.accounts[accountName]
|
|
631
|
+
if (config && config.accounts && config.accounts[accountName]) {
|
|
632
|
+
policy = { ...policy, ...config.accounts[accountName] };
|
|
633
|
+
}
|
|
634
|
+
return policy;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Build the PolicyContext passed to evaluatePolicy and to executable hooks.
|
|
638
|
+
*/
|
|
639
|
+
function buildPolicyContext(request) {
|
|
640
|
+
return {
|
|
641
|
+
accountName: request.accountName,
|
|
642
|
+
requestType: request.type,
|
|
643
|
+
sessionId: request.sessionId || null,
|
|
644
|
+
timestamp: new Date().toISOString(),
|
|
645
|
+
operations: request.operations || [],
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Evaluate per-operation parameter constraints.
|
|
650
|
+
* Returns { allow: boolean, reason: string|null, policyId: string }
|
|
651
|
+
*/
|
|
652
|
+
async function evaluateOpConstraints(opName, opData, constraints) {
|
|
653
|
+
if (!constraints)
|
|
654
|
+
return { allow: true, reason: null, policyId: null };
|
|
655
|
+
const d = opData || {};
|
|
656
|
+
if (opName === 'transfer') {
|
|
657
|
+
// allowedToAccounts
|
|
658
|
+
if (Array.isArray(constraints.allowedToAccounts) && constraints.allowedToAccounts.length > 0) {
|
|
659
|
+
if (!constraints.allowedToAccounts.includes(d.to)) {
|
|
660
|
+
return {
|
|
661
|
+
allow: false,
|
|
662
|
+
reason: `transfer: recipient "${d.to}" not in allowedToAccounts`,
|
|
663
|
+
policyId: 'opParams',
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
// allowedAssets
|
|
668
|
+
if (Array.isArray(constraints.allowedAssets) && constraints.allowedAssets.length > 0) {
|
|
669
|
+
const id = d.amount && d.amount.asset_id;
|
|
670
|
+
if (id && !constraints.allowedAssets.includes(id)) {
|
|
671
|
+
return {
|
|
672
|
+
allow: false,
|
|
673
|
+
reason: `transfer: asset "${id}" not in allowedAssets`,
|
|
674
|
+
policyId: 'opParams',
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
// maxAmount
|
|
679
|
+
if (constraints.maxAmount != null) {
|
|
680
|
+
const amt = d.amount && d.amount.amount;
|
|
681
|
+
if (typeof amt === 'number' && amt > constraints.maxAmount) {
|
|
682
|
+
return {
|
|
683
|
+
allow: false,
|
|
684
|
+
reason: `transfer: amount ${amt} exceeds maxAmount ${constraints.maxAmount}`,
|
|
685
|
+
policyId: 'opParams',
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (opName === 'limit_order_create') {
|
|
691
|
+
// allowedSellAssets
|
|
692
|
+
if (Array.isArray(constraints.allowedSellAssets) && constraints.allowedSellAssets.length > 0) {
|
|
693
|
+
const id = d.amount_to_sell && d.amount_to_sell.asset_id;
|
|
694
|
+
if (id && !constraints.allowedSellAssets.includes(id)) {
|
|
695
|
+
return {
|
|
696
|
+
allow: false,
|
|
697
|
+
reason: `limit_order_create: sell asset "${id}" not in allowedSellAssets`,
|
|
698
|
+
policyId: 'opParams',
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
// allowedReceiveAssets
|
|
703
|
+
if (Array.isArray(constraints.allowedReceiveAssets) && constraints.allowedReceiveAssets.length > 0) {
|
|
704
|
+
const id = d.min_to_receive && d.min_to_receive.asset_id;
|
|
705
|
+
if (id && !constraints.allowedReceiveAssets.includes(id)) {
|
|
706
|
+
return {
|
|
707
|
+
allow: false,
|
|
708
|
+
reason: `limit_order_create: receive asset "${id}" not in allowedReceiveAssets`,
|
|
709
|
+
policyId: 'opParams',
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
// maxSellAmount
|
|
714
|
+
if (constraints.maxSellAmount != null) {
|
|
715
|
+
const amt = d.amount_to_sell && d.amount_to_sell.amount;
|
|
716
|
+
if (typeof amt === 'number' && amt > constraints.maxSellAmount) {
|
|
717
|
+
return {
|
|
718
|
+
allow: false,
|
|
719
|
+
reason: `limit_order_create: sell amount ${amt} exceeds maxSellAmount ${constraints.maxSellAmount}`,
|
|
720
|
+
policyId: 'opParams',
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
// maxReceiveAmount
|
|
725
|
+
if (constraints.maxReceiveAmount != null) {
|
|
726
|
+
const amt = d.min_to_receive && d.min_to_receive.amount;
|
|
727
|
+
if (typeof amt === 'number' && amt > constraints.maxReceiveAmount) {
|
|
728
|
+
return {
|
|
729
|
+
allow: false,
|
|
730
|
+
reason: `limit_order_create: receive amount ${amt} exceeds maxReceiveAmount ${constraints.maxReceiveAmount}`,
|
|
731
|
+
policyId: 'opParams',
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
// allowFillOrKill
|
|
736
|
+
if (constraints.allowFillOrKill === false && d.fill_or_kill === true) {
|
|
737
|
+
return {
|
|
738
|
+
allow: false,
|
|
739
|
+
reason: 'limit_order_create: fill_or_kill=true not permitted',
|
|
740
|
+
policyId: 'opParams',
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (opName === 'limit_order_update') {
|
|
745
|
+
// allowedSellAssets via new_price.base
|
|
746
|
+
if (Array.isArray(constraints.allowedSellAssets) && constraints.allowedSellAssets.length > 0) {
|
|
747
|
+
const id = d.new_price && d.new_price.base && d.new_price.base.asset_id;
|
|
748
|
+
if (id && !constraints.allowedSellAssets.includes(id)) {
|
|
749
|
+
return {
|
|
750
|
+
allow: false,
|
|
751
|
+
reason: `limit_order_update: base asset "${id}" not in allowedSellAssets`,
|
|
752
|
+
policyId: 'opParams',
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
// allowedReceiveAssets via new_price.quote
|
|
757
|
+
if (Array.isArray(constraints.allowedReceiveAssets) && constraints.allowedReceiveAssets.length > 0) {
|
|
758
|
+
const id = d.new_price && d.new_price.quote && d.new_price.quote.asset_id;
|
|
759
|
+
if (id && !constraints.allowedReceiveAssets.includes(id)) {
|
|
760
|
+
return {
|
|
761
|
+
allow: false,
|
|
762
|
+
reason: `limit_order_update: quote asset "${id}" not in allowedReceiveAssets`,
|
|
763
|
+
policyId: 'opParams',
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
// maxDeltaSellAmount (abs value)
|
|
768
|
+
if (constraints.maxDeltaSellAmount != null) {
|
|
769
|
+
const delta = d.delta_amount_to_sell && d.delta_amount_to_sell.amount;
|
|
770
|
+
if (typeof delta === 'number' && Math.abs(delta) > constraints.maxDeltaSellAmount) {
|
|
771
|
+
return {
|
|
772
|
+
allow: false,
|
|
773
|
+
reason: `limit_order_update: |delta| ${Math.abs(delta)} exceeds maxDeltaSellAmount ${constraints.maxDeltaSellAmount}`,
|
|
774
|
+
policyId: 'opParams',
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (opName === 'call_order_update') {
|
|
780
|
+
// allowedAssets
|
|
781
|
+
if (Array.isArray(constraints.allowedAssets) && constraints.allowedAssets.length > 0) {
|
|
782
|
+
const collId = d.delta_collateral && d.delta_collateral.asset_id;
|
|
783
|
+
const debtId = d.delta_debt && d.delta_debt.asset_id;
|
|
784
|
+
if (collId && !constraints.allowedAssets.includes(collId)) {
|
|
785
|
+
return {
|
|
786
|
+
allow: false,
|
|
787
|
+
reason: `call_order_update: collateral asset "${collId}" not in allowedAssets`,
|
|
788
|
+
policyId: 'opParams',
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
if (debtId && !constraints.allowedAssets.includes(debtId)) {
|
|
792
|
+
return {
|
|
793
|
+
allow: false,
|
|
794
|
+
reason: `call_order_update: debt asset "${debtId}" not in allowedAssets`,
|
|
795
|
+
policyId: 'opParams',
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (constraints.collateralAsset) {
|
|
800
|
+
const collId = d.delta_collateral && d.delta_collateral.asset_id;
|
|
801
|
+
const resolved = await resolveConfiguredAssetRefs([constraints.collateralAsset], 'collateralAsset');
|
|
802
|
+
if (!resolved.ok) {
|
|
803
|
+
return {
|
|
804
|
+
allow: false,
|
|
805
|
+
reason: `call_order_update: ${resolved.reason}`,
|
|
806
|
+
policyId: 'opParams',
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
if (collId && !resolved.values.includes(String(collId))) {
|
|
810
|
+
return {
|
|
811
|
+
allow: false,
|
|
812
|
+
reason: `call_order_update: collateral asset "${collId}" does not match collateralAsset`,
|
|
813
|
+
policyId: 'opParams',
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
if (Array.isArray(constraints.allowedCollateralAssets) && constraints.allowedCollateralAssets.length > 0) {
|
|
818
|
+
const collId = d.delta_collateral && d.delta_collateral.asset_id;
|
|
819
|
+
const resolved = await resolveConfiguredAssetRefs(constraints.allowedCollateralAssets, 'allowedCollateralAssets');
|
|
820
|
+
if (!resolved.ok) {
|
|
821
|
+
return {
|
|
822
|
+
allow: false,
|
|
823
|
+
reason: `call_order_update: ${resolved.reason}`,
|
|
824
|
+
policyId: 'opParams',
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
if (collId && !resolved.values.includes(String(collId))) {
|
|
828
|
+
return {
|
|
829
|
+
allow: false,
|
|
830
|
+
reason: `call_order_update: collateral asset "${collId}" not in allowedCollateralAssets`,
|
|
831
|
+
policyId: 'opParams',
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
// maxDeltaCollateral
|
|
836
|
+
if (constraints.maxDeltaCollateral != null) {
|
|
837
|
+
const amt = d.delta_collateral && d.delta_collateral.amount;
|
|
838
|
+
if (typeof amt === 'number' && Math.abs(amt) > constraints.maxDeltaCollateral) {
|
|
839
|
+
return {
|
|
840
|
+
allow: false,
|
|
841
|
+
reason: `call_order_update: |delta_collateral| ${Math.abs(amt)} exceeds maxDeltaCollateral ${constraints.maxDeltaCollateral}`,
|
|
842
|
+
policyId: 'opParams',
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
// maxDeltaDebt
|
|
847
|
+
if (constraints.maxDeltaDebt != null) {
|
|
848
|
+
const amt = d.delta_debt && d.delta_debt.amount;
|
|
849
|
+
if (typeof amt === 'number' && Math.abs(amt) > constraints.maxDeltaDebt) {
|
|
850
|
+
return {
|
|
851
|
+
allow: false,
|
|
852
|
+
reason: `call_order_update: |delta_debt| ${Math.abs(amt)} exceeds maxDeltaDebt ${constraints.maxDeltaDebt}`,
|
|
853
|
+
policyId: 'opParams',
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
if (constraints.minCollateralRatio != null && d.extensions && d.extensions.target_collateral_ratio != null) {
|
|
858
|
+
const target = normalizeGrapheneCollateralRatio(d.extensions.target_collateral_ratio);
|
|
859
|
+
if (Number.isFinite(target) && target < constraints.minCollateralRatio) {
|
|
860
|
+
return {
|
|
861
|
+
allow: false,
|
|
862
|
+
reason: `call_order_update: target_collateral_ratio ${target} below minCollateralRatio ${constraints.minCollateralRatio}`,
|
|
863
|
+
policyId: 'opParams',
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (constraints.maxCollateralRatio != null && d.extensions && d.extensions.target_collateral_ratio != null) {
|
|
868
|
+
const target = normalizeGrapheneCollateralRatio(d.extensions.target_collateral_ratio);
|
|
869
|
+
if (Number.isFinite(target) && target > constraints.maxCollateralRatio) {
|
|
870
|
+
return {
|
|
871
|
+
allow: false,
|
|
872
|
+
reason: `call_order_update: target_collateral_ratio ${target} above maxCollateralRatio ${constraints.maxCollateralRatio}`,
|
|
873
|
+
policyId: 'opParams',
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if (opName === 'credit_offer_accept') {
|
|
879
|
+
if (Array.isArray(constraints.allowedOfferIds) && constraints.allowedOfferIds.length > 0) {
|
|
880
|
+
const offerId = d.offer_id;
|
|
881
|
+
if (offerId && !constraints.allowedOfferIds.includes(String(offerId))) {
|
|
882
|
+
return {
|
|
883
|
+
allow: false,
|
|
884
|
+
reason: `credit_offer_accept: offer "${offerId}" not in allowedOfferIds`,
|
|
885
|
+
policyId: 'opParams',
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
if (constraints.collateralAsset) {
|
|
890
|
+
const assetId = d.collateral && d.collateral.asset_id;
|
|
891
|
+
const resolved = await resolveConfiguredAssetRefs([constraints.collateralAsset], 'collateralAsset');
|
|
892
|
+
if (!resolved.ok) {
|
|
893
|
+
return {
|
|
894
|
+
allow: false,
|
|
895
|
+
reason: `credit_offer_accept: ${resolved.reason}`,
|
|
896
|
+
policyId: 'opParams',
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
if (assetId && !resolved.values.includes(String(assetId))) {
|
|
900
|
+
return {
|
|
901
|
+
allow: false,
|
|
902
|
+
reason: `credit_offer_accept: collateral asset "${assetId}" does not match collateralAsset`,
|
|
903
|
+
policyId: 'opParams',
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
if (Array.isArray(constraints.allowedCollateralAssets) && constraints.allowedCollateralAssets.length > 0) {
|
|
908
|
+
const assetId = d.collateral && d.collateral.asset_id;
|
|
909
|
+
const resolved = await resolveConfiguredAssetRefs(constraints.allowedCollateralAssets, 'allowedCollateralAssets');
|
|
910
|
+
if (!resolved.ok) {
|
|
911
|
+
return {
|
|
912
|
+
allow: false,
|
|
913
|
+
reason: `credit_offer_accept: ${resolved.reason}`,
|
|
914
|
+
policyId: 'opParams',
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
if (assetId && !resolved.values.includes(String(assetId))) {
|
|
918
|
+
return {
|
|
919
|
+
allow: false,
|
|
920
|
+
reason: `credit_offer_accept: collateral asset "${assetId}" not in allowedCollateralAssets`,
|
|
921
|
+
policyId: 'opParams',
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
if (Array.isArray(constraints.allowedDebtAssets) && constraints.allowedDebtAssets.length > 0) {
|
|
926
|
+
const assetId = d.borrow_amount && d.borrow_amount.asset_id;
|
|
927
|
+
const resolved = await resolveConfiguredAssetRefs(constraints.allowedDebtAssets, 'allowedDebtAssets');
|
|
928
|
+
if (!resolved.ok) {
|
|
929
|
+
return {
|
|
930
|
+
allow: false,
|
|
931
|
+
reason: `credit_offer_accept: ${resolved.reason}`,
|
|
932
|
+
policyId: 'opParams',
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
if (assetId && !resolved.values.includes(String(assetId))) {
|
|
936
|
+
return {
|
|
937
|
+
allow: false,
|
|
938
|
+
reason: `credit_offer_accept: debt asset "${assetId}" not in allowedDebtAssets`,
|
|
939
|
+
policyId: 'opParams',
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (constraints.maxFeeRate != null) {
|
|
944
|
+
const maxFeeRate = Number(d.max_fee_rate);
|
|
945
|
+
if (Number.isFinite(maxFeeRate) && maxFeeRate > constraints.maxFeeRate) {
|
|
946
|
+
return {
|
|
947
|
+
allow: false,
|
|
948
|
+
reason: `credit_offer_accept: max_fee_rate ${maxFeeRate} exceeds maxFeeRate ${constraints.maxFeeRate}`,
|
|
949
|
+
policyId: 'opParams',
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
if (constraints.minDurationSeconds != null) {
|
|
954
|
+
const minDurationSeconds = Number(d.min_duration_seconds);
|
|
955
|
+
if (Number.isFinite(minDurationSeconds) && minDurationSeconds < constraints.minDurationSeconds) {
|
|
956
|
+
return {
|
|
957
|
+
allow: false,
|
|
958
|
+
reason: `credit_offer_accept: min_duration_seconds ${minDurationSeconds} below minDurationSeconds ${constraints.minDurationSeconds}`,
|
|
959
|
+
policyId: 'opParams',
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
if (opName === 'credit_deal_repay') {
|
|
965
|
+
if (Array.isArray(constraints.allowedDebtAssets) && constraints.allowedDebtAssets.length > 0) {
|
|
966
|
+
const assetId = d.repay_amount && d.repay_amount.asset_id;
|
|
967
|
+
const resolved = await resolveConfiguredAssetRefs(constraints.allowedDebtAssets, 'allowedDebtAssets');
|
|
968
|
+
if (!resolved.ok) {
|
|
969
|
+
return {
|
|
970
|
+
allow: false,
|
|
971
|
+
reason: `credit_deal_repay: ${resolved.reason}`,
|
|
972
|
+
policyId: 'opParams',
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
if (assetId && !resolved.values.includes(String(assetId))) {
|
|
976
|
+
return {
|
|
977
|
+
allow: false,
|
|
978
|
+
reason: `credit_deal_repay: debt asset "${assetId}" not in allowedDebtAssets`,
|
|
979
|
+
policyId: 'opParams',
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
if (constraints.maxRepayAmount != null) {
|
|
984
|
+
const amt = d.repay_amount && d.repay_amount.amount;
|
|
985
|
+
if (typeof amt === 'number' && amt > constraints.maxRepayAmount) {
|
|
986
|
+
return {
|
|
987
|
+
allow: false,
|
|
988
|
+
reason: `credit_deal_repay: repay amount ${amt} exceeds maxRepayAmount ${constraints.maxRepayAmount}`,
|
|
989
|
+
policyId: 'opParams',
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
if (constraints.maxCreditFee != null) {
|
|
994
|
+
const fee = d.credit_fee && d.credit_fee.amount;
|
|
995
|
+
if (typeof fee === 'number' && fee > constraints.maxCreditFee) {
|
|
996
|
+
return {
|
|
997
|
+
allow: false,
|
|
998
|
+
reason: `credit_deal_repay: credit fee ${fee} exceeds maxCreditFee ${constraints.maxCreditFee}`,
|
|
999
|
+
policyId: 'opParams',
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
if (opName === 'credit_deal_update') {
|
|
1005
|
+
if (constraints.allowAutoRepay === false && d.auto_repay) {
|
|
1006
|
+
return {
|
|
1007
|
+
allow: false,
|
|
1008
|
+
reason: 'credit_deal_update: auto_repay change not permitted',
|
|
1009
|
+
policyId: 'opParams',
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
if (opName === 'liquidity_pool_exchange') {
|
|
1014
|
+
// allowedPools
|
|
1015
|
+
if (Array.isArray(constraints.allowedPools) && constraints.allowedPools.length > 0) {
|
|
1016
|
+
if (!constraints.allowedPools.includes(d.pool)) {
|
|
1017
|
+
return {
|
|
1018
|
+
allow: false,
|
|
1019
|
+
reason: `liquidity_pool_exchange: pool "${d.pool}" not in allowedPools`,
|
|
1020
|
+
policyId: 'opParams',
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
// allowedSellAssets
|
|
1025
|
+
if (Array.isArray(constraints.allowedSellAssets) && constraints.allowedSellAssets.length > 0) {
|
|
1026
|
+
const id = d.amount_to_sell && d.amount_to_sell.asset_id;
|
|
1027
|
+
if (id && !constraints.allowedSellAssets.includes(id)) {
|
|
1028
|
+
return {
|
|
1029
|
+
allow: false,
|
|
1030
|
+
reason: `liquidity_pool_exchange: sell asset "${id}" not in allowedSellAssets`,
|
|
1031
|
+
policyId: 'opParams',
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
// allowedReceiveAssets
|
|
1036
|
+
if (Array.isArray(constraints.allowedReceiveAssets) && constraints.allowedReceiveAssets.length > 0) {
|
|
1037
|
+
const id = d.min_to_receive && d.min_to_receive.asset_id;
|
|
1038
|
+
if (id && !constraints.allowedReceiveAssets.includes(id)) {
|
|
1039
|
+
return {
|
|
1040
|
+
allow: false,
|
|
1041
|
+
reason: `liquidity_pool_exchange: receive asset "${id}" not in allowedReceiveAssets`,
|
|
1042
|
+
policyId: 'opParams',
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
// maxSellAmount
|
|
1047
|
+
if (constraints.maxSellAmount != null) {
|
|
1048
|
+
const amt = d.amount_to_sell && d.amount_to_sell.amount;
|
|
1049
|
+
if (typeof amt === 'number' && amt > constraints.maxSellAmount) {
|
|
1050
|
+
return {
|
|
1051
|
+
allow: false,
|
|
1052
|
+
reason: `liquidity_pool_exchange: sell amount ${amt} exceeds maxSellAmount ${constraints.maxSellAmount}`,
|
|
1053
|
+
policyId: 'opParams',
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
// limit_order_cancel — no constraints
|
|
1059
|
+
return { allow: true, reason: null, policyId: null };
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Evaluate a policy against a context. AND semantics: short-circuit on first denial.
|
|
1063
|
+
* Returns Promise<{ allow: boolean, reason: string|null, policyId: string|null }>
|
|
1064
|
+
*/
|
|
1065
|
+
async function evaluatePolicy(policy, context) {
|
|
1066
|
+
try {
|
|
1067
|
+
// Step 1: allowedOps check (if present) or allowedOpTypes fallback
|
|
1068
|
+
if (policy.allowedOps && typeof policy.allowedOps === 'object') {
|
|
1069
|
+
for (const op of context.operations) {
|
|
1070
|
+
if (!op || typeof op !== 'object')
|
|
1071
|
+
continue;
|
|
1072
|
+
const opName = op.op_name;
|
|
1073
|
+
// Check if op type is allowed
|
|
1074
|
+
if (!(opName in policy.allowedOps)) {
|
|
1075
|
+
return {
|
|
1076
|
+
allow: false,
|
|
1077
|
+
reason: `op type "${opName}" not permitted`,
|
|
1078
|
+
policyId: 'allowedOps',
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
// Get per-op constraints and evaluate
|
|
1082
|
+
const constraints = policy.allowedOps[opName];
|
|
1083
|
+
const result = await evaluateOpConstraints(opName, op.op_data, constraints);
|
|
1084
|
+
if (!result.allow) {
|
|
1085
|
+
return result;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
else {
|
|
1090
|
+
// Fallback: allowedOpTypes check (backward compat)
|
|
1091
|
+
const allowed = policy.allowedOpTypes || [];
|
|
1092
|
+
if (Array.isArray(allowed) && allowed.length > 0) {
|
|
1093
|
+
for (const op of context.operations) {
|
|
1094
|
+
if (!op || typeof op !== 'object')
|
|
1095
|
+
continue;
|
|
1096
|
+
if (!allowed.includes(op.op_name)) {
|
|
1097
|
+
return {
|
|
1098
|
+
allow: false,
|
|
1099
|
+
reason: `op type "${op.op_name}" not permitted`,
|
|
1100
|
+
policyId: 'allowedOpTypes',
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
// Step 2: maxOpsPerBatch check
|
|
1107
|
+
{
|
|
1108
|
+
const max = policy.maxOpsPerBatch || 200;
|
|
1109
|
+
if (context.operations.length > max) {
|
|
1110
|
+
return {
|
|
1111
|
+
allow: false,
|
|
1112
|
+
reason: `batch size ${context.operations.length} exceeds maxOpsPerBatch ${max}`,
|
|
1113
|
+
policyId: 'maxOpsPerBatch',
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
// Step 3: allowedAssetIds check (optional)
|
|
1118
|
+
if (policy.allowedAssetIds && Array.isArray(policy.allowedAssetIds) && policy.allowedAssetIds.length > 0) {
|
|
1119
|
+
const allowed = policy.allowedAssetIds;
|
|
1120
|
+
for (const op of context.operations) {
|
|
1121
|
+
if (!op || typeof op !== 'object')
|
|
1122
|
+
continue;
|
|
1123
|
+
const opData = op.op_data || {};
|
|
1124
|
+
// Check amount_to_sell asset (for create/update)
|
|
1125
|
+
if (opData.amount_to_sell && opData.amount_to_sell.asset_id) {
|
|
1126
|
+
if (!allowed.includes(opData.amount_to_sell.asset_id)) {
|
|
1127
|
+
return {
|
|
1128
|
+
allow: false,
|
|
1129
|
+
reason: `asset_id "${opData.amount_to_sell.asset_id}" not in allowlist`,
|
|
1130
|
+
policyId: 'allowedAssetIds',
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
// Check min_to_receive asset (for create/update)
|
|
1135
|
+
if (opData.min_to_receive && opData.min_to_receive.asset_id) {
|
|
1136
|
+
if (!allowed.includes(opData.min_to_receive.asset_id)) {
|
|
1137
|
+
return {
|
|
1138
|
+
allow: false,
|
|
1139
|
+
reason: `asset_id "${opData.min_to_receive.asset_id}" not in allowlist`,
|
|
1140
|
+
policyId: 'allowedAssetIds',
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (op.op_name === 'call_order_update') {
|
|
1145
|
+
if (opData.delta_collateral && opData.delta_collateral.asset_id && !allowed.includes(opData.delta_collateral.asset_id)) {
|
|
1146
|
+
return {
|
|
1147
|
+
allow: false,
|
|
1148
|
+
reason: `asset_id "${opData.delta_collateral.asset_id}" not in allowlist`,
|
|
1149
|
+
policyId: 'allowedAssetIds',
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
if (opData.delta_debt && opData.delta_debt.asset_id && !allowed.includes(opData.delta_debt.asset_id)) {
|
|
1153
|
+
return {
|
|
1154
|
+
allow: false,
|
|
1155
|
+
reason: `asset_id "${opData.delta_debt.asset_id}" not in allowlist`,
|
|
1156
|
+
policyId: 'allowedAssetIds',
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
if (op.op_name === 'credit_offer_accept') {
|
|
1161
|
+
if (opData.borrow_amount && opData.borrow_amount.asset_id && !allowed.includes(opData.borrow_amount.asset_id)) {
|
|
1162
|
+
return {
|
|
1163
|
+
allow: false,
|
|
1164
|
+
reason: `asset_id "${opData.borrow_amount.asset_id}" not in allowlist`,
|
|
1165
|
+
policyId: 'allowedAssetIds',
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
if (opData.collateral && opData.collateral.asset_id && !allowed.includes(opData.collateral.asset_id)) {
|
|
1169
|
+
return {
|
|
1170
|
+
allow: false,
|
|
1171
|
+
reason: `asset_id "${opData.collateral.asset_id}" not in allowlist`,
|
|
1172
|
+
policyId: 'allowedAssetIds',
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
if (op.op_name === 'credit_deal_repay') {
|
|
1177
|
+
if (opData.repay_amount && opData.repay_amount.asset_id && !allowed.includes(opData.repay_amount.asset_id)) {
|
|
1178
|
+
return {
|
|
1179
|
+
allow: false,
|
|
1180
|
+
reason: `asset_id "${opData.repay_amount.asset_id}" not in allowlist`,
|
|
1181
|
+
policyId: 'allowedAssetIds',
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
if (opData.credit_fee && opData.credit_fee.asset_id && !allowed.includes(opData.credit_fee.asset_id)) {
|
|
1185
|
+
return {
|
|
1186
|
+
allow: false,
|
|
1187
|
+
reason: `asset_id "${opData.credit_fee.asset_id}" not in allowlist`,
|
|
1188
|
+
policyId: 'allowedAssetIds',
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
// Step 4: executable check (optional)
|
|
1195
|
+
if (policy.executable && typeof policy.executable === 'string') {
|
|
1196
|
+
const result = await evaluateExecutable(policy.executable, context);
|
|
1197
|
+
if (!result.allow) {
|
|
1198
|
+
return {
|
|
1199
|
+
allow: false,
|
|
1200
|
+
reason: result.reason || 'denied by executable',
|
|
1201
|
+
policyId: 'executable',
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
// All checks passed
|
|
1206
|
+
return { allow: true, reason: null, policyId: null };
|
|
1207
|
+
}
|
|
1208
|
+
catch (error) {
|
|
1209
|
+
// Any evaluation error → deny
|
|
1210
|
+
return {
|
|
1211
|
+
allow: false,
|
|
1212
|
+
reason: `policy evaluation error: ${error.message}`,
|
|
1213
|
+
policyId: 'policy_eval_error',
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Spawn and evaluate a custom policy executable.
|
|
1219
|
+
* Executable receives PolicyContext JSON on stdin.
|
|
1220
|
+
* Must output { "allow": true/false, "reason": "..." } to stdout within 5 seconds.
|
|
1221
|
+
* Returns Promise<{ allow: boolean, reason: string|null }>
|
|
1222
|
+
*/
|
|
1223
|
+
// File mode check: execute permission (X_OK = 1 on POSIX)
|
|
1224
|
+
const X_OK = 1;
|
|
1225
|
+
function evaluateExecutable(exePath, context) {
|
|
1226
|
+
return new Promise((resolve) => {
|
|
1227
|
+
let spawn;
|
|
1228
|
+
try {
|
|
1229
|
+
spawn = require('child_process').spawn;
|
|
1230
|
+
}
|
|
1231
|
+
catch {
|
|
1232
|
+
return resolve({ allow: false, reason: `executable not supported in this environment: ${exePath}` });
|
|
1233
|
+
}
|
|
1234
|
+
// Check file exists and is executable
|
|
1235
|
+
try {
|
|
1236
|
+
storage.access(exePath, X_OK);
|
|
1237
|
+
}
|
|
1238
|
+
catch {
|
|
1239
|
+
return resolve({ allow: false, reason: `executable not found or not executable: ${exePath}` });
|
|
1240
|
+
}
|
|
1241
|
+
let stdout = '';
|
|
1242
|
+
let stderr = '';
|
|
1243
|
+
const child = spawn(exePath, [], {
|
|
1244
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1245
|
+
timeout: EXECUTABLE_TIMEOUT_MS,
|
|
1246
|
+
});
|
|
1247
|
+
child.stdout.on('data', (data) => {
|
|
1248
|
+
stdout += data.toString();
|
|
1249
|
+
});
|
|
1250
|
+
child.stderr.on('data', (data) => {
|
|
1251
|
+
stderr += data.toString();
|
|
1252
|
+
});
|
|
1253
|
+
child.on('error', (error) => {
|
|
1254
|
+
if (error.code === 'ETIMEDOUT') {
|
|
1255
|
+
resolve({ allow: false, reason: `executable timed out after ${EXECUTABLE_TIMEOUT_MS}ms` });
|
|
1256
|
+
}
|
|
1257
|
+
else {
|
|
1258
|
+
resolve({ allow: false, reason: `executable spawn failed: ${error.message}` });
|
|
1259
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
child.on('close', (code, signal) => {
|
|
1262
|
+
if (signal === 'SIGTERM') {
|
|
1263
|
+
return resolve({ allow: false, reason: `executable timed out after ${EXECUTABLE_TIMEOUT_MS}ms` });
|
|
1264
|
+
}
|
|
1265
|
+
if (code !== 0) {
|
|
1266
|
+
const stderrMsg = stderr.trim() ? `: ${stderr.trim()}` : '';
|
|
1267
|
+
return resolve({ allow: false, reason: `executable exited with code ${code}${stderrMsg}` });
|
|
1268
|
+
}
|
|
1269
|
+
// Parse JSON output
|
|
1270
|
+
try {
|
|
1271
|
+
const result = JSON.parse(stdout.trim());
|
|
1272
|
+
if (typeof result.allow !== 'boolean') {
|
|
1273
|
+
return resolve({ allow: false, reason: 'executable output missing "allow" field' });
|
|
1274
|
+
}
|
|
1275
|
+
resolve({
|
|
1276
|
+
allow: result.allow,
|
|
1277
|
+
reason: result.allow ? null : (result.reason || 'denied by executable'),
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
catch (error) {
|
|
1281
|
+
resolve({ allow: false, reason: `executable output invalid JSON: ${error.message}` });
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1284
|
+
// Send context to stdin
|
|
1285
|
+
try {
|
|
1286
|
+
child.stdin.write(JSON.stringify(context));
|
|
1287
|
+
child.stdin.end();
|
|
1288
|
+
}
|
|
1289
|
+
catch (error) {
|
|
1290
|
+
child.kill();
|
|
1291
|
+
resolve({ allow: false, reason: `failed to pipe context to executable: ${error.message}` });
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Load the botHmacSecret for an account from the policy config file.
|
|
1297
|
+
*
|
|
1298
|
+
* CONCURRENCY NOTE (M1): If two bot processes call this simultaneously for
|
|
1299
|
+
* the same account before either has written, both will generate independent
|
|
1300
|
+
* secrets. The second atomic rename clobbers the first, leaving both bots
|
|
1301
|
+
* holding the second bot's secret. The first bot's HMAC will then mismatch
|
|
1302
|
+
* until it retries (triggering another reload). This is a brief disruption
|
|
1303
|
+
* window, not a security breach — both bots are legitimate. If strict
|
|
1304
|
+
* per-bot isolation is required, use flock(2) on the policy file or switch
|
|
1305
|
+
* to a per-bot key-derivation from a shared master secret.
|
|
1306
|
+
*
|
|
1307
|
+
* @param {string} accountName - The account name
|
|
1308
|
+
* @param {string} policyConfigPath - Path to daemon-policies.json
|
|
1309
|
+
* @param {Object} [options] - Optional configuration
|
|
1310
|
+
* @returns {string|null} The botHmacSecret, or null if not configured
|
|
1311
|
+
*/
|
|
1312
|
+
function loadBotHmacSecret(accountName, policyConfigPath, options = {}) {
|
|
1313
|
+
const quiet = options.quiet === true || options.silent === true;
|
|
1314
|
+
// Route through the module-scope policyLogger so output honours the
|
|
1315
|
+
// process-wide log level, file rotation, and PM2 auto-quiet rules.
|
|
1316
|
+
// `quiet` (per-call) suppresses routine info; security-relevant warns
|
|
1317
|
+
// and the auto-provision event still surface regardless.
|
|
1318
|
+
const info = (msg) => {
|
|
1319
|
+
if (!quiet)
|
|
1320
|
+
policyLogger.info(msg);
|
|
1321
|
+
};
|
|
1322
|
+
const debug = (msg) => {
|
|
1323
|
+
if (!quiet)
|
|
1324
|
+
policyLogger.debug?.(msg);
|
|
1325
|
+
};
|
|
1326
|
+
const warn = (msg) => {
|
|
1327
|
+
policyLogger.warn(msg);
|
|
1328
|
+
};
|
|
1329
|
+
// Always reload from disk to avoid serving a stale cached entry when
|
|
1330
|
+
// another process (or this process in an earlier call) already
|
|
1331
|
+
// auto-provisioned a new secret and signalled the daemon via SIGHUP.
|
|
1332
|
+
let config = loadPolicyConfig(policyConfigPath, { forceReload: true });
|
|
1333
|
+
if (!config)
|
|
1334
|
+
config = {};
|
|
1335
|
+
if (!config.accounts)
|
|
1336
|
+
config.accounts = {};
|
|
1337
|
+
if (!config.accounts[accountName])
|
|
1338
|
+
config.accounts[accountName] = {};
|
|
1339
|
+
let secret = config.accounts[accountName].botHmacSecret;
|
|
1340
|
+
if (!secret) {
|
|
1341
|
+
const newSecret = randomBytes(32).toString('hex');
|
|
1342
|
+
config.accounts[accountName].botHmacSecret = newSecret;
|
|
1343
|
+
// Atomic write via unified StorageAdapter.
|
|
1344
|
+
storage.writeJSON(policyConfigPath, config, { mode: 0o600, fsync: true });
|
|
1345
|
+
warn(`[policy] SECURITY: Auto-provisioned strict botHmacSecret for ${accountName} — first-time secret generation`);
|
|
1346
|
+
// Best-effort SIGHUP to the credential daemon so the new secret is
|
|
1347
|
+
// picked up immediately, without waiting for the fs.watch debounce
|
|
1348
|
+
// (500ms) or a SIGHUP from the operator. Three distinct failure
|
|
1349
|
+
// modes are handled separately:
|
|
1350
|
+
// - ready file missing: daemon is not running, nothing to do
|
|
1351
|
+
// - ready file empty: daemon is mid-startup; fs.watch will catch it
|
|
1352
|
+
// - ready file malformed (old format, partial write): warn and skip
|
|
1353
|
+
// - process.kill error (ESRCH=process gone, EPERM=not allowed):
|
|
1354
|
+
// warn — the fs.watch safety net will still pick up the change
|
|
1355
|
+
try {
|
|
1356
|
+
const readyFile = getCredentialReadyFilePath({ root: PATHS.PROJECT_ROOT });
|
|
1357
|
+
if (!storage.exists(readyFile)) {
|
|
1358
|
+
info(`[policy] Ready file ${readyFile} not present; daemon not running, SIGHUP skipped`);
|
|
1359
|
+
secret = newSecret;
|
|
1360
|
+
return secret;
|
|
1361
|
+
}
|
|
1362
|
+
const raw = storage.readFile(readyFile);
|
|
1363
|
+
if (!raw.trim()) {
|
|
1364
|
+
// File exists but is empty: daemon is mid-startup. Don't warn —
|
|
1365
|
+
// this is the expected race window between fork and ready-file write.
|
|
1366
|
+
// The fs.watch safety net will pick up the change within 500ms.
|
|
1367
|
+
debug(`[policy] Ready file ${readyFile} is empty (daemon mid-startup); fs.watch will pick up the change`);
|
|
1368
|
+
secret = newSecret;
|
|
1369
|
+
return secret;
|
|
1370
|
+
}
|
|
1371
|
+
const daemonInfo = JSON.parse(raw);
|
|
1372
|
+
if (daemonInfo && typeof daemonInfo.pid === 'number') {
|
|
1373
|
+
runtime.kill(daemonInfo.pid, 'SIGHUP');
|
|
1374
|
+
info(`[policy] Sent SIGHUP to credential daemon (pid ${daemonInfo.pid}) to activate new secret`);
|
|
1375
|
+
}
|
|
1376
|
+
else {
|
|
1377
|
+
warn(`[policy] Ready file ${readyFile} has no numeric pid field; skipping SIGHUP`);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
catch (e) {
|
|
1381
|
+
if (e && e.code === 'ENOENT') {
|
|
1382
|
+
info(`[policy] Ready file not present; daemon not running, SIGHUP skipped`);
|
|
1383
|
+
}
|
|
1384
|
+
else if (e instanceof SyntaxError) {
|
|
1385
|
+
warn(`[policy] Ready file is malformed JSON (${e.message}); SIGHUP skipped, fs.watch will pick up the change`);
|
|
1386
|
+
}
|
|
1387
|
+
else if (e && (e.code === 'ESRCH' || e.code === 'EPERM')) {
|
|
1388
|
+
warn(`[policy] SIGHUP to daemon failed (${e.code}: ${e.message}); fs.watch will pick up the change`);
|
|
1389
|
+
}
|
|
1390
|
+
else {
|
|
1391
|
+
warn(`[policy] Unexpected error signalling daemon (${e && e.message}); fs.watch will pick up the change`);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
secret = newSecret;
|
|
1395
|
+
}
|
|
1396
|
+
return secret;
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Verify that the signing request was HMAC-signed by the bot holding botHmacSecret.
|
|
1400
|
+
* Session binding: HMAC includes sessionId, so replay is impossible across sessions.
|
|
1401
|
+
*
|
|
1402
|
+
* @param {object} request - Parsed request: { accountName, sessionId, operations, hmac }
|
|
1403
|
+
* @param {object|null} policyConfig - Loaded daemon-policies.json content
|
|
1404
|
+
* @returns {{ valid: boolean, reason: string|null, skipped: boolean }}
|
|
1405
|
+
* skipped is always false — missing secrets are rejected in strict mode.
|
|
1406
|
+
*/
|
|
1407
|
+
function verifySourceHmac(request, policyConfig) {
|
|
1408
|
+
const accountPolicy = policyConfig && policyConfig.accounts && policyConfig.accounts[request.accountName];
|
|
1409
|
+
const secretHex = accountPolicy && accountPolicy.botHmacSecret;
|
|
1410
|
+
// Strict Mode Enforcement: Reject instantly if no secret is configured
|
|
1411
|
+
if (!secretHex) {
|
|
1412
|
+
return { valid: false, reason: 'Strict Mode: botHmacSecret missing in daemon-policies.json', skipped: false };
|
|
1413
|
+
}
|
|
1414
|
+
const providedHmac = request.hmac;
|
|
1415
|
+
if (!providedHmac || typeof providedHmac !== 'string') {
|
|
1416
|
+
return { valid: false, reason: 'missing hmac field', skipped: false };
|
|
1417
|
+
}
|
|
1418
|
+
// Canonical signing payload: must match exactly what the bot computed
|
|
1419
|
+
const signingPayload = JSON.stringify({
|
|
1420
|
+
sessionId: request.sessionId,
|
|
1421
|
+
operations: request.operations,
|
|
1422
|
+
});
|
|
1423
|
+
const expected = createHmac('sha256', Buffer.from(secretHex, 'hex'))
|
|
1424
|
+
.update(signingPayload)
|
|
1425
|
+
.digest('hex');
|
|
1426
|
+
try {
|
|
1427
|
+
const valid = timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(providedHmac, 'hex'));
|
|
1428
|
+
return { valid, reason: valid ? null : 'hmac mismatch', skipped: false };
|
|
1429
|
+
}
|
|
1430
|
+
catch {
|
|
1431
|
+
// Buffer.from throws if provided hmac is not valid hex or wrong length
|
|
1432
|
+
return { valid: false, reason: 'invalid hmac format', skipped: false };
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
module.exports = {
|
|
1436
|
+
POLICY_DENIED_PREFIX,
|
|
1437
|
+
BUILTIN_DEFAULT_POLICY,
|
|
1438
|
+
checkPolicyFileSecurity,
|
|
1439
|
+
ensurePolicyConfig,
|
|
1440
|
+
loadPolicyConfig,
|
|
1441
|
+
loadRequiredPolicyConfig,
|
|
1442
|
+
reloadPolicyFromDisk,
|
|
1443
|
+
validatePolicyConfig,
|
|
1444
|
+
deriveDebtPolicyConstraints,
|
|
1445
|
+
resolveAccountPolicy,
|
|
1446
|
+
buildPolicyContext,
|
|
1447
|
+
evaluatePolicy,
|
|
1448
|
+
verifySourceHmac,
|
|
1449
|
+
loadBotHmacSecret,
|
|
1450
|
+
setExternalAssetResolver,
|
|
1451
|
+
};
|
|
1452
|
+
//# sourceMappingURL=credential_policy.js.map
|