sorokeep 1.0.0
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/CONTRIBUTING.md +296 -0
- package/LICENSE +21 -0
- package/README.md +677 -0
- package/dist/alerts/alerts.d.ts +21 -0
- package/dist/alerts/alerts.d.ts.map +1 -0
- package/dist/alerts/alerts.js +18 -0
- package/dist/alerts/alerts.js.map +1 -0
- package/dist/alerts/discord.d.ts +3 -0
- package/dist/alerts/discord.d.ts.map +1 -0
- package/dist/alerts/discord.js +199 -0
- package/dist/alerts/discord.js.map +1 -0
- package/dist/alerts/dispatcher.d.ts +13 -0
- package/dist/alerts/dispatcher.d.ts.map +1 -0
- package/dist/alerts/dispatcher.js +91 -0
- package/dist/alerts/dispatcher.js.map +1 -0
- package/dist/alerts/keys.d.ts +24 -0
- package/dist/alerts/keys.d.ts.map +1 -0
- package/dist/alerts/keys.js +44 -0
- package/dist/alerts/keys.js.map +1 -0
- package/dist/alerts/pagerduty.d.ts +8 -0
- package/dist/alerts/pagerduty.d.ts.map +1 -0
- package/dist/alerts/pagerduty.js +164 -0
- package/dist/alerts/pagerduty.js.map +1 -0
- package/dist/alerts/resource.d.ts +23 -0
- package/dist/alerts/resource.d.ts.map +1 -0
- package/dist/alerts/resource.js +167 -0
- package/dist/alerts/resource.js.map +1 -0
- package/dist/alerts/slack.d.ts +7 -0
- package/dist/alerts/slack.d.ts.map +1 -0
- package/dist/alerts/slack.js +184 -0
- package/dist/alerts/slack.js.map +1 -0
- package/dist/alerts/telegram.d.ts +9 -0
- package/dist/alerts/telegram.d.ts.map +1 -0
- package/dist/alerts/telegram.js +133 -0
- package/dist/alerts/telegram.js.map +1 -0
- package/dist/alerts/templates.d.ts +109 -0
- package/dist/alerts/templates.d.ts.map +1 -0
- package/dist/alerts/templates.js +139 -0
- package/dist/alerts/templates.js.map +1 -0
- package/dist/alerts/types.d.ts +113 -0
- package/dist/alerts/types.d.ts.map +1 -0
- package/dist/alerts/types.js +87 -0
- package/dist/alerts/types.js.map +1 -0
- package/dist/alerts/webhook.d.ts +13 -0
- package/dist/alerts/webhook.d.ts.map +1 -0
- package/dist/alerts/webhook.js +56 -0
- package/dist/alerts/webhook.js.map +1 -0
- package/dist/cli/schemaFormatter.d.ts +11 -0
- package/dist/cli/schemaFormatter.d.ts.map +1 -0
- package/dist/cli/schemaFormatter.js +74 -0
- package/dist/cli/schemaFormatter.js.map +1 -0
- package/dist/commands/alerts.d.ts +3 -0
- package/dist/commands/alerts.d.ts.map +1 -0
- package/dist/commands/alerts.js +256 -0
- package/dist/commands/alerts.js.map +1 -0
- package/dist/commands/budget.d.ts +3 -0
- package/dist/commands/budget.d.ts.map +1 -0
- package/dist/commands/budget.js +47 -0
- package/dist/commands/budget.js.map +1 -0
- package/dist/commands/channels.d.ts +3 -0
- package/dist/commands/channels.d.ts.map +1 -0
- package/dist/commands/channels.js +84 -0
- package/dist/commands/channels.js.map +1 -0
- package/dist/commands/check.d.ts +3 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +58 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/completion.d.ts +3 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +36 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/costs.d.ts +15 -0
- package/dist/commands/costs.d.ts.map +1 -0
- package/dist/commands/costs.js +280 -0
- package/dist/commands/costs.js.map +1 -0
- package/dist/commands/daemon.d.ts +3 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +93 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/db.d.ts +3 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +140 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/guard.d.ts +3 -0
- package/dist/commands/guard.d.ts.map +1 -0
- package/dist/commands/guard.js +181 -0
- package/dist/commands/guard.js.map +1 -0
- package/dist/commands/history.d.ts +3 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +57 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/inspect.d.ts +3 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +82 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +20 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/pause.d.ts +3 -0
- package/dist/commands/pause.d.ts.map +1 -0
- package/dist/commands/pause.js +32 -0
- package/dist/commands/pause.js.map +1 -0
- package/dist/commands/resources.d.ts +3 -0
- package/dist/commands/resources.d.ts.map +1 -0
- package/dist/commands/resources.js +95 -0
- package/dist/commands/resources.js.map +1 -0
- package/dist/commands/restore.d.ts +3 -0
- package/dist/commands/restore.d.ts.map +1 -0
- package/dist/commands/restore.js +92 -0
- package/dist/commands/restore.js.map +1 -0
- package/dist/commands/resume.d.ts +3 -0
- package/dist/commands/resume.d.ts.map +1 -0
- package/dist/commands/resume.js +31 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +63 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/watch.d.ts +3 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +163 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/core/aws_secrets.d.ts +13 -0
- package/dist/core/aws_secrets.d.ts.map +1 -0
- package/dist/core/aws_secrets.js +34 -0
- package/dist/core/aws_secrets.js.map +1 -0
- package/dist/core/budget.d.ts +10 -0
- package/dist/core/budget.d.ts.map +1 -0
- package/dist/core/budget.js +31 -0
- package/dist/core/budget.js.map +1 -0
- package/dist/core/channels.d.ts +67 -0
- package/dist/core/channels.d.ts.map +1 -0
- package/dist/core/channels.js +136 -0
- package/dist/core/channels.js.map +1 -0
- package/dist/core/check.d.ts +25 -0
- package/dist/core/check.d.ts.map +1 -0
- package/dist/core/check.js +85 -0
- package/dist/core/check.js.map +1 -0
- package/dist/core/completion.d.ts +9 -0
- package/dist/core/completion.d.ts.map +1 -0
- package/dist/core/completion.js +68 -0
- package/dist/core/completion.js.map +1 -0
- package/dist/core/costs.d.ts +90 -0
- package/dist/core/costs.d.ts.map +1 -0
- package/dist/core/costs.js +147 -0
- package/dist/core/costs.js.map +1 -0
- package/dist/core/decoder.d.ts +7 -0
- package/dist/core/decoder.d.ts.map +1 -0
- package/dist/core/decoder.js +38 -0
- package/dist/core/decoder.js.map +1 -0
- package/dist/core/discovery.d.ts +38 -0
- package/dist/core/discovery.d.ts.map +1 -0
- package/dist/core/discovery.js +208 -0
- package/dist/core/discovery.js.map +1 -0
- package/dist/core/extension.d.ts +83 -0
- package/dist/core/extension.d.ts.map +1 -0
- package/dist/core/extension.js +429 -0
- package/dist/core/extension.js.map +1 -0
- package/dist/core/inspect.d.ts +62 -0
- package/dist/core/inspect.d.ts.map +1 -0
- package/dist/core/inspect.js +303 -0
- package/dist/core/inspect.js.map +1 -0
- package/dist/core/introspection.d.ts +8 -0
- package/dist/core/introspection.d.ts.map +1 -0
- package/dist/core/introspection.js +8 -0
- package/dist/core/introspection.js.map +1 -0
- package/dist/core/monitor.d.ts +42 -0
- package/dist/core/monitor.d.ts.map +1 -0
- package/dist/core/monitor.js +188 -0
- package/dist/core/monitor.js.map +1 -0
- package/dist/core/rent_projection.d.ts +153 -0
- package/dist/core/rent_projection.d.ts.map +1 -0
- package/dist/core/rent_projection.js +146 -0
- package/dist/core/rent_projection.js.map +1 -0
- package/dist/core/scvalTranslator.d.ts +11 -0
- package/dist/core/scvalTranslator.d.ts.map +1 -0
- package/dist/core/scvalTranslator.js +36 -0
- package/dist/core/scvalTranslator.js.map +1 -0
- package/dist/core/state_diff.d.ts +45 -0
- package/dist/core/state_diff.d.ts.map +1 -0
- package/dist/core/state_diff.js +112 -0
- package/dist/core/state_diff.js.map +1 -0
- package/dist/core/status.d.ts +24 -0
- package/dist/core/status.d.ts.map +1 -0
- package/dist/core/status.js +57 -0
- package/dist/core/status.js.map +1 -0
- package/dist/core/vault.d.ts +37 -0
- package/dist/core/vault.d.ts.map +1 -0
- package/dist/core/vault.js +179 -0
- package/dist/core/vault.js.map +1 -0
- package/dist/core/watch.d.ts +36 -0
- package/dist/core/watch.d.ts.map +1 -0
- package/dist/core/watch.js +176 -0
- package/dist/core/watch.js.map +1 -0
- package/dist/daemon/loop.d.ts +38 -0
- package/dist/daemon/loop.d.ts.map +1 -0
- package/dist/daemon/loop.js +169 -0
- package/dist/daemon/loop.js.map +1 -0
- package/dist/db/backup.d.ts +12 -0
- package/dist/db/backup.d.ts.map +1 -0
- package/dist/db/backup.js +132 -0
- package/dist/db/backup.js.map +1 -0
- package/dist/db/budget.d.ts +17 -0
- package/dist/db/budget.d.ts.map +1 -0
- package/dist/db/budget.js +31 -0
- package/dist/db/budget.js.map +1 -0
- package/dist/db/database.d.ts +6 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/database.js +134 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/migrations/.gitkeep +1 -0
- package/dist/db/migrations/001_resource_usage_logs.sql +28 -0
- package/dist/db/migrator.d.ts +28 -0
- package/dist/db/migrator.d.ts.map +1 -0
- package/dist/db/migrator.js +75 -0
- package/dist/db/migrator.js.map +1 -0
- package/dist/db/repositories.d.ts +474 -0
- package/dist/db/repositories.d.ts.map +1 -0
- package/dist/db/repositories.js +809 -0
- package/dist/db/repositories.js.map +1 -0
- package/dist/db/schema.sql +207 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.d.ts +20 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +16 -0
- package/dist/lib.js.map +1 -0
- package/dist/logging/index.d.ts +22 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +34 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +14 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +135 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/types.d.ts +10 -0
- package/dist/logging/types.d.ts.map +1 -0
- package/dist/logging/types.js +2 -0
- package/dist/logging/types.js.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +14 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +10 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +51 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/get-extension-costs.d.ts +4 -0
- package/dist/mcp/tools/get-extension-costs.d.ts.map +1 -0
- package/dist/mcp/tools/get-extension-costs.js +33 -0
- package/dist/mcp/tools/get-extension-costs.js.map +1 -0
- package/dist/mcp/tools/get_contract_status.d.ts +8 -0
- package/dist/mcp/tools/get_contract_status.d.ts.map +1 -0
- package/dist/mcp/tools/get_contract_status.js +33 -0
- package/dist/mcp/tools/get_contract_status.js.map +1 -0
- package/dist/rpc/client.d.ts +154 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +766 -0
- package/dist/rpc/client.js.map +1 -0
- package/dist/utils/config.d.ts +51 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +86 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/formatting.d.ts +10 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/formatting.js +66 -0
- package/dist/utils/formatting.js.map +1 -0
- package/dist/utils/watch-config.d.ts +13 -0
- package/dist/utils/watch-config.d.ts.map +1 -0
- package/dist/utils/watch-config.js +32 -0
- package/dist/utils/watch-config.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Soroban rent cost projection model — Issue #168.
|
|
3
|
+
*
|
|
4
|
+
* Implements the canonical Stellar Soroban rent formula from
|
|
5
|
+
* stellar/rs-soroban-env (soroban-env-host/src/fees.rs):
|
|
6
|
+
*
|
|
7
|
+
* rent_stroops = ceil(
|
|
8
|
+
* entry_size_bytes × fee_per_rent_1kb × rent_ledgers
|
|
9
|
+
* / (1024 × rent_rate_denominator)
|
|
10
|
+
* )
|
|
11
|
+
*
|
|
12
|
+
* Where:
|
|
13
|
+
* - entry_size_bytes: in-memory size of the ledger entry
|
|
14
|
+
* - fee_per_rent_1kb: effective rent write fee per 1 KB (in stroops),
|
|
15
|
+
* computed from the current Soroban state size via
|
|
16
|
+
* `compute_rent_write_fee_per_1kb`. For projections, treated as an
|
|
17
|
+
* input (use network defaults or a fetched value).
|
|
18
|
+
* - rent_ledgers: number of ledger increments being projected
|
|
19
|
+
* - rent_rate_denominator: persistent_rent_rate_denominator or
|
|
20
|
+
* temporary_rent_rate_denominator (network configuration)
|
|
21
|
+
*
|
|
22
|
+
* Code entries (WASM) receive a 1/3 discount
|
|
23
|
+
* (CODE_ENTRY_RENT_DISCOUNT_FACTOR = 3).
|
|
24
|
+
*
|
|
25
|
+
* Network default values from stellar/rs-soroban-env and Stellar Lab
|
|
26
|
+
* resource configuration as of mid-2026.
|
|
27
|
+
*/
|
|
28
|
+
/** Average Stellar ledger close time in seconds. */
|
|
29
|
+
export declare const AVG_LEDGER_CLOSE_SECONDS = 5.5;
|
|
30
|
+
/** Approximate number of ledgers per day (86400s ÷ 5.5s/ledger). */
|
|
31
|
+
export declare const LEDGERS_PER_DAY: number;
|
|
32
|
+
/** One XLM = 10,000,000 stroops. */
|
|
33
|
+
export declare const STROOPS_PER_XLM = 10000000;
|
|
34
|
+
/**
|
|
35
|
+
* DATA_SIZE_1KB_INCREMENT from fees.rs — the byte increment used in the
|
|
36
|
+
* fee calculation denominator.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DATA_SIZE_1KB_INCREMENT = 1024;
|
|
39
|
+
/**
|
|
40
|
+
* CODE_ENTRY_RENT_DISCOUNT_FACTOR from fees.rs.
|
|
41
|
+
* WASM code entry rent fees are divided (ceiling) by this value.
|
|
42
|
+
*/
|
|
43
|
+
export declare const CODE_ENTRY_RENT_DISCOUNT_FACTOR = 3;
|
|
44
|
+
/**
|
|
45
|
+
* Default effective rent write fee per 1 KB in stroops.
|
|
46
|
+
*
|
|
47
|
+
* This is the `fee_per_rent_1kb` value, which in production is computed
|
|
48
|
+
* by `compute_rent_write_fee_per_1kb` based on the current Soroban state
|
|
49
|
+
* size. The default here (1000 stroops/KB) corresponds to the minimum
|
|
50
|
+
* floor `MINIMUM_RENT_WRITE_FEE_PER_1KB` defined in fees.rs and is a
|
|
51
|
+
* reasonable baseline for projections when live network data is unavailable.
|
|
52
|
+
*
|
|
53
|
+
* Callers should override this with a freshly-fetched value for production
|
|
54
|
+
* accuracy.
|
|
55
|
+
*/
|
|
56
|
+
export declare const DEFAULT_FEE_PER_RENT_1KB = 1000;
|
|
57
|
+
/**
|
|
58
|
+
* Default denominator for persistent / instance entry rent rate.
|
|
59
|
+
*
|
|
60
|
+
* Source: Stellar network configuration (ConfigSettingsEntry).
|
|
61
|
+
* Current mainnet value is 2103 ledgers, meaning 1 KB of persistent state
|
|
62
|
+
* is charged `fee_per_rent_1kb / 2103` stroops per ledger.
|
|
63
|
+
*/
|
|
64
|
+
export declare const DEFAULT_PERSISTENT_RENT_RATE_DENOMINATOR = 2103;
|
|
65
|
+
/**
|
|
66
|
+
* Default denominator for temporary entry rent rate.
|
|
67
|
+
*
|
|
68
|
+
* Temporary entries are cheaper — the network uses a larger denominator.
|
|
69
|
+
* Current mainnet value is 1000 ledgers.
|
|
70
|
+
*/
|
|
71
|
+
export declare const DEFAULT_TEMPORARY_RENT_RATE_DENOMINATOR = 1000;
|
|
72
|
+
/** Input parameters for a single rent cost projection. */
|
|
73
|
+
export interface RentProjectionInput {
|
|
74
|
+
/** Size of the ledger entry in bytes. */
|
|
75
|
+
entrySizeBytes: number;
|
|
76
|
+
/** Number of days to project over. */
|
|
77
|
+
days: number;
|
|
78
|
+
/**
|
|
79
|
+
* Effective rent write fee per 1 KB in stroops (fee_per_rent_1kb).
|
|
80
|
+
* Defaults to DEFAULT_FEE_PER_RENT_1KB if not provided.
|
|
81
|
+
*/
|
|
82
|
+
feePerRent1kb?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Rent rate denominator for this entry type.
|
|
85
|
+
* Use DEFAULT_PERSISTENT_RENT_RATE_DENOMINATOR for persistent/instance.
|
|
86
|
+
* Use DEFAULT_TEMPORARY_RENT_RATE_DENOMINATOR for temporary.
|
|
87
|
+
*/
|
|
88
|
+
rentRateDenominator?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Whether this is a persistent (or instance) entry.
|
|
91
|
+
* Determines which denominator default to apply if rentRateDenominator
|
|
92
|
+
* is not explicitly provided.
|
|
93
|
+
*/
|
|
94
|
+
isPersistent: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Whether this is a WASM code entry.
|
|
97
|
+
* Code entries receive a 1/3 rent discount per CODE_ENTRY_RENT_DISCOUNT_FACTOR.
|
|
98
|
+
*/
|
|
99
|
+
isCodeEntry?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/** Result of a single rent projection. */
|
|
102
|
+
export interface RentProjectionResult {
|
|
103
|
+
/** Number of days projected. */
|
|
104
|
+
days: number;
|
|
105
|
+
/** Approximate number of ledgers for this duration. */
|
|
106
|
+
ledgerCount: number;
|
|
107
|
+
/** Estimated rent cost in stroops. */
|
|
108
|
+
estimatedFeeStroops: number;
|
|
109
|
+
/** Estimated rent cost in XLM (stroops / 10_000_000). */
|
|
110
|
+
estimatedFeeXlm: number;
|
|
111
|
+
}
|
|
112
|
+
/** A single window result within a multi-window projection. */
|
|
113
|
+
export type RentWindowProjection = RentProjectionResult;
|
|
114
|
+
/** Result of a 30/60/90-day multi-window projection. */
|
|
115
|
+
export interface RentWindowsResult {
|
|
116
|
+
/** Entry size used for this projection. */
|
|
117
|
+
entrySizeBytes: number;
|
|
118
|
+
/** Fee per rent 1 KB used for this projection. */
|
|
119
|
+
feePerRent1kb: number;
|
|
120
|
+
/** Whether this is a persistent entry. */
|
|
121
|
+
isPersistent: boolean;
|
|
122
|
+
/** Whether this is a code entry. */
|
|
123
|
+
isCodeEntry: boolean;
|
|
124
|
+
/** The three projection windows: 30, 60, and 90 days. */
|
|
125
|
+
windows: [RentWindowProjection, RentWindowProjection, RentWindowProjection];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Project the rent cost for a single ledger entry over a given number of days.
|
|
129
|
+
*
|
|
130
|
+
* Uses the canonical Soroban rent formula from fees.rs:
|
|
131
|
+
*
|
|
132
|
+
* rent_stroops = ceil(
|
|
133
|
+
* entry_size_bytes × fee_per_rent_1kb × rent_ledgers
|
|
134
|
+
* / (1024 × rent_rate_denominator)
|
|
135
|
+
* )
|
|
136
|
+
*
|
|
137
|
+
* Code entries receive a discount: `ceil(full_fee / CODE_ENTRY_RENT_DISCOUNT_FACTOR)`.
|
|
138
|
+
*
|
|
139
|
+
* @param input - Projection parameters.
|
|
140
|
+
* @returns Cost estimate for the given duration.
|
|
141
|
+
*/
|
|
142
|
+
export declare function projectRentCost(input: RentProjectionInput): RentProjectionResult;
|
|
143
|
+
/**
|
|
144
|
+
* Project rent costs for the standard 30, 60, and 90-day windows.
|
|
145
|
+
*
|
|
146
|
+
* Convenience wrapper around `projectRentCost` that returns all three
|
|
147
|
+
* windows in a single call.
|
|
148
|
+
*
|
|
149
|
+
* @param input - Base projection parameters (without `days`).
|
|
150
|
+
* @returns Multi-window projection result with 30, 60, and 90-day estimates.
|
|
151
|
+
*/
|
|
152
|
+
export declare function projectRentWindows(input: Omit<RentProjectionInput, "days">): RentWindowsResult;
|
|
153
|
+
//# sourceMappingURL=rent_projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rent_projection.d.ts","sourceRoot":"","sources":["../../src/core/rent_projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,oDAAoD;AACpD,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,oEAAoE;AACpE,eAAO,MAAM,eAAe,QAAmC,CAAC;AAEhE,oCAAoC;AACpC,eAAO,MAAM,eAAe,WAAa,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,wCAAwC,OAAO,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,uCAAuC,OAAO,CAAC;AAI5D,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAChC,yCAAyC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB;IACjC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED,+DAA+D;AAC/D,MAAM,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;AAExD,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAC9B,2CAA2C;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,YAAY,EAAE,OAAO,CAAC;IACtB,oCAAoC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,yDAAyD;IACzD,OAAO,EAAE,CAAC,oBAAoB,EAAE,oBAAoB,EAAE,oBAAoB,CAAC,CAAC;CAC/E;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CAoDhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,GACzC,iBAAiB,CAenB"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Soroban rent cost projection model — Issue #168.
|
|
3
|
+
*
|
|
4
|
+
* Implements the canonical Stellar Soroban rent formula from
|
|
5
|
+
* stellar/rs-soroban-env (soroban-env-host/src/fees.rs):
|
|
6
|
+
*
|
|
7
|
+
* rent_stroops = ceil(
|
|
8
|
+
* entry_size_bytes × fee_per_rent_1kb × rent_ledgers
|
|
9
|
+
* / (1024 × rent_rate_denominator)
|
|
10
|
+
* )
|
|
11
|
+
*
|
|
12
|
+
* Where:
|
|
13
|
+
* - entry_size_bytes: in-memory size of the ledger entry
|
|
14
|
+
* - fee_per_rent_1kb: effective rent write fee per 1 KB (in stroops),
|
|
15
|
+
* computed from the current Soroban state size via
|
|
16
|
+
* `compute_rent_write_fee_per_1kb`. For projections, treated as an
|
|
17
|
+
* input (use network defaults or a fetched value).
|
|
18
|
+
* - rent_ledgers: number of ledger increments being projected
|
|
19
|
+
* - rent_rate_denominator: persistent_rent_rate_denominator or
|
|
20
|
+
* temporary_rent_rate_denominator (network configuration)
|
|
21
|
+
*
|
|
22
|
+
* Code entries (WASM) receive a 1/3 discount
|
|
23
|
+
* (CODE_ENTRY_RENT_DISCOUNT_FACTOR = 3).
|
|
24
|
+
*
|
|
25
|
+
* Network default values from stellar/rs-soroban-env and Stellar Lab
|
|
26
|
+
* resource configuration as of mid-2026.
|
|
27
|
+
*/
|
|
28
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
29
|
+
/** Average Stellar ledger close time in seconds. */
|
|
30
|
+
export const AVG_LEDGER_CLOSE_SECONDS = 5.5;
|
|
31
|
+
/** Approximate number of ledgers per day (86400s ÷ 5.5s/ledger). */
|
|
32
|
+
export const LEDGERS_PER_DAY = 86400 / AVG_LEDGER_CLOSE_SECONDS;
|
|
33
|
+
/** One XLM = 10,000,000 stroops. */
|
|
34
|
+
export const STROOPS_PER_XLM = 10_000_000;
|
|
35
|
+
/**
|
|
36
|
+
* DATA_SIZE_1KB_INCREMENT from fees.rs — the byte increment used in the
|
|
37
|
+
* fee calculation denominator.
|
|
38
|
+
*/
|
|
39
|
+
export const DATA_SIZE_1KB_INCREMENT = 1024;
|
|
40
|
+
/**
|
|
41
|
+
* CODE_ENTRY_RENT_DISCOUNT_FACTOR from fees.rs.
|
|
42
|
+
* WASM code entry rent fees are divided (ceiling) by this value.
|
|
43
|
+
*/
|
|
44
|
+
export const CODE_ENTRY_RENT_DISCOUNT_FACTOR = 3;
|
|
45
|
+
/**
|
|
46
|
+
* Default effective rent write fee per 1 KB in stroops.
|
|
47
|
+
*
|
|
48
|
+
* This is the `fee_per_rent_1kb` value, which in production is computed
|
|
49
|
+
* by `compute_rent_write_fee_per_1kb` based on the current Soroban state
|
|
50
|
+
* size. The default here (1000 stroops/KB) corresponds to the minimum
|
|
51
|
+
* floor `MINIMUM_RENT_WRITE_FEE_PER_1KB` defined in fees.rs and is a
|
|
52
|
+
* reasonable baseline for projections when live network data is unavailable.
|
|
53
|
+
*
|
|
54
|
+
* Callers should override this with a freshly-fetched value for production
|
|
55
|
+
* accuracy.
|
|
56
|
+
*/
|
|
57
|
+
export const DEFAULT_FEE_PER_RENT_1KB = 1000;
|
|
58
|
+
/**
|
|
59
|
+
* Default denominator for persistent / instance entry rent rate.
|
|
60
|
+
*
|
|
61
|
+
* Source: Stellar network configuration (ConfigSettingsEntry).
|
|
62
|
+
* Current mainnet value is 2103 ledgers, meaning 1 KB of persistent state
|
|
63
|
+
* is charged `fee_per_rent_1kb / 2103` stroops per ledger.
|
|
64
|
+
*/
|
|
65
|
+
export const DEFAULT_PERSISTENT_RENT_RATE_DENOMINATOR = 2103;
|
|
66
|
+
/**
|
|
67
|
+
* Default denominator for temporary entry rent rate.
|
|
68
|
+
*
|
|
69
|
+
* Temporary entries are cheaper — the network uses a larger denominator.
|
|
70
|
+
* Current mainnet value is 1000 ledgers.
|
|
71
|
+
*/
|
|
72
|
+
export const DEFAULT_TEMPORARY_RENT_RATE_DENOMINATOR = 1000;
|
|
73
|
+
// ─── Core projection logic ────────────────────────────────────────────────────
|
|
74
|
+
/**
|
|
75
|
+
* Project the rent cost for a single ledger entry over a given number of days.
|
|
76
|
+
*
|
|
77
|
+
* Uses the canonical Soroban rent formula from fees.rs:
|
|
78
|
+
*
|
|
79
|
+
* rent_stroops = ceil(
|
|
80
|
+
* entry_size_bytes × fee_per_rent_1kb × rent_ledgers
|
|
81
|
+
* / (1024 × rent_rate_denominator)
|
|
82
|
+
* )
|
|
83
|
+
*
|
|
84
|
+
* Code entries receive a discount: `ceil(full_fee / CODE_ENTRY_RENT_DISCOUNT_FACTOR)`.
|
|
85
|
+
*
|
|
86
|
+
* @param input - Projection parameters.
|
|
87
|
+
* @returns Cost estimate for the given duration.
|
|
88
|
+
*/
|
|
89
|
+
export function projectRentCost(input) {
|
|
90
|
+
const { entrySizeBytes, days, isPersistent, isCodeEntry = false, } = input;
|
|
91
|
+
const feePerRent1kb = input.feePerRent1kb ?? DEFAULT_FEE_PER_RENT_1KB;
|
|
92
|
+
const rentRateDenominator = input.rentRateDenominator ??
|
|
93
|
+
(isPersistent
|
|
94
|
+
? DEFAULT_PERSISTENT_RENT_RATE_DENOMINATOR
|
|
95
|
+
: DEFAULT_TEMPORARY_RENT_RATE_DENOMINATOR);
|
|
96
|
+
// Zero-input fast paths
|
|
97
|
+
if (entrySizeBytes <= 0 || days <= 0 || feePerRent1kb <= 0) {
|
|
98
|
+
return {
|
|
99
|
+
days,
|
|
100
|
+
ledgerCount: days <= 0 ? 0 : Math.ceil(days * LEDGERS_PER_DAY),
|
|
101
|
+
estimatedFeeStroops: 0,
|
|
102
|
+
estimatedFeeXlm: 0,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// Convert days to ledger count (ceiling to avoid underestimating)
|
|
106
|
+
const ledgerCount = Math.ceil(days * LEDGERS_PER_DAY);
|
|
107
|
+
// Canonical rent formula from fees.rs: rent_fee_for_size_and_ledgers
|
|
108
|
+
// num = entry_size_bytes × fee_per_rent_1kb × rent_ledgers
|
|
109
|
+
// denom = DATA_SIZE_1KB_INCREMENT × rent_rate_denominator
|
|
110
|
+
// fee = ceil(num / denom)
|
|
111
|
+
const denom = DATA_SIZE_1KB_INCREMENT * rentRateDenominator;
|
|
112
|
+
let estimatedFeeStroops = Math.ceil((entrySizeBytes * feePerRent1kb * ledgerCount) / denom);
|
|
113
|
+
// Apply code entry discount: ceil(fee / CODE_ENTRY_RENT_DISCOUNT_FACTOR)
|
|
114
|
+
if (isCodeEntry) {
|
|
115
|
+
estimatedFeeStroops = Math.ceil(estimatedFeeStroops / CODE_ENTRY_RENT_DISCOUNT_FACTOR);
|
|
116
|
+
}
|
|
117
|
+
const estimatedFeeXlm = estimatedFeeStroops / STROOPS_PER_XLM;
|
|
118
|
+
return {
|
|
119
|
+
days,
|
|
120
|
+
ledgerCount,
|
|
121
|
+
estimatedFeeStroops,
|
|
122
|
+
estimatedFeeXlm,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Project rent costs for the standard 30, 60, and 90-day windows.
|
|
127
|
+
*
|
|
128
|
+
* Convenience wrapper around `projectRentCost` that returns all three
|
|
129
|
+
* windows in a single call.
|
|
130
|
+
*
|
|
131
|
+
* @param input - Base projection parameters (without `days`).
|
|
132
|
+
* @returns Multi-window projection result with 30, 60, and 90-day estimates.
|
|
133
|
+
*/
|
|
134
|
+
export function projectRentWindows(input) {
|
|
135
|
+
const resolvedFeePerRent1kb = input.feePerRent1kb ?? DEFAULT_FEE_PER_RENT_1KB;
|
|
136
|
+
const isCodeEntry = input.isCodeEntry ?? false;
|
|
137
|
+
const windows = [30, 60, 90].map(days => projectRentCost({ ...input, days }));
|
|
138
|
+
return {
|
|
139
|
+
entrySizeBytes: input.entrySizeBytes,
|
|
140
|
+
feePerRent1kb: resolvedFeePerRent1kb,
|
|
141
|
+
isPersistent: input.isPersistent,
|
|
142
|
+
isCodeEntry,
|
|
143
|
+
windows,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=rent_projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rent_projection.js","sourceRoot":"","sources":["../../src/core/rent_projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { xdr } from "@stellar/stellar-sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Translate a Soroban `SCVal` into a JSON-safe representation.
|
|
4
|
+
*
|
|
5
|
+
* Design goals:
|
|
6
|
+
* - Recursively translate nested vectors/maps.
|
|
7
|
+
* - Avoid precision loss: large ints are always returned as strings.
|
|
8
|
+
* - Produce human-readable tokens for symbol/address.
|
|
9
|
+
*/
|
|
10
|
+
export declare function scvalToJSON(val: xdr.ScVal): any;
|
|
11
|
+
//# sourceMappingURL=scvalTranslator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scvalTranslator.d.ts","sourceRoot":"","sources":["../../src/core/scvalTranslator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAiB,MAAM,sBAAsB,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAQ/C"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { scValToNative } from "@stellar/stellar-sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Translate a Soroban `SCVal` into a JSON-safe representation.
|
|
4
|
+
*
|
|
5
|
+
* Design goals:
|
|
6
|
+
* - Recursively translate nested vectors/maps.
|
|
7
|
+
* - Avoid precision loss: large ints are always returned as strings.
|
|
8
|
+
* - Produce human-readable tokens for symbol/address.
|
|
9
|
+
*/
|
|
10
|
+
export function scvalToJSON(val) {
|
|
11
|
+
let native;
|
|
12
|
+
try {
|
|
13
|
+
native = scValToNative(val);
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
return { unsupported: val.switch().name };
|
|
17
|
+
}
|
|
18
|
+
return serializeBigInts(native);
|
|
19
|
+
}
|
|
20
|
+
function serializeBigInts(obj) {
|
|
21
|
+
if (typeof obj === "bigint") {
|
|
22
|
+
return obj.toString(10);
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(obj)) {
|
|
25
|
+
return obj.map(serializeBigInts);
|
|
26
|
+
}
|
|
27
|
+
if (obj !== null && typeof obj === "object") {
|
|
28
|
+
const res = {};
|
|
29
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
30
|
+
res[k] = serializeBigInts(v);
|
|
31
|
+
}
|
|
32
|
+
return res;
|
|
33
|
+
}
|
|
34
|
+
return obj;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=scvalTranslator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scvalTranslator.js","sourceRoot":"","sources":["../../src/core/scvalTranslator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,GAAc;IACxC,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAQ;IAChC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,GAAG,GAAQ,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
export interface StateDiffResult {
|
|
3
|
+
/** The kind of change: first appearance, value mutation, or removal. */
|
|
4
|
+
diffType: "created" | "updated" | "deleted";
|
|
5
|
+
/** The previous XDR value (null for `created`). */
|
|
6
|
+
oldValueXdr: string | null;
|
|
7
|
+
/** The current XDR value (null for `deleted`). */
|
|
8
|
+
newValueXdr: string | null;
|
|
9
|
+
/** SHA-256 hex hash of the old value (null for `created`). */
|
|
10
|
+
oldHash: string | null;
|
|
11
|
+
/** SHA-256 hex hash of the new value (null for `deleted`). */
|
|
12
|
+
newHash: string | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compute a SHA-256 hex digest of a raw XDR value string.
|
|
16
|
+
* Used to quickly compare storage values without storing/diffing full payloads
|
|
17
|
+
* every cycle.
|
|
18
|
+
*/
|
|
19
|
+
export declare function computeValueHash(valueXdr: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Compare two XDR value strings and produce a structured diff result.
|
|
22
|
+
*
|
|
23
|
+
* Returns `null` when the values are identical (including both-null),
|
|
24
|
+
* meaning no state change occurred.
|
|
25
|
+
*
|
|
26
|
+
* @param oldXdr - The previous XDR value, or null if the entry didn't exist.
|
|
27
|
+
* @param newXdr - The current XDR value, or null if the entry was removed.
|
|
28
|
+
*/
|
|
29
|
+
export declare function diffStateValues(oldXdr: string | null, newXdr: string | null): StateDiffResult | null;
|
|
30
|
+
/**
|
|
31
|
+
* Process a state diff for a single contract entry within a monitoring cycle.
|
|
32
|
+
*
|
|
33
|
+
* 1. Fetch the latest snapshot for this entry from the DB.
|
|
34
|
+
* 2. Compare the current value hash against the stored hash.
|
|
35
|
+
* 3. If changed → persist a new snapshot and a state_change record.
|
|
36
|
+
* 4. If unchanged → return null (storage-optimised: no writes).
|
|
37
|
+
*
|
|
38
|
+
* @param db - An open better-sqlite3 Database handle.
|
|
39
|
+
* @param contractEntryId - The `contract_entries.id` of the entry being checked.
|
|
40
|
+
* @param currentValueXdr - The XDR-encoded value returned by the RPC for this entry.
|
|
41
|
+
* @param currentLedger - The ledger sequence at which this value was observed.
|
|
42
|
+
* @returns A `StateDiffResult` describing the change, or `null` if unchanged.
|
|
43
|
+
*/
|
|
44
|
+
export declare function processStateDiff(db: Database.Database, contractEntryId: number, currentValueXdr: string, currentLedger: number): StateDiffResult | null;
|
|
45
|
+
//# sourceMappingURL=state_diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state_diff.d.ts","sourceRoot":"","sources":["../../src/core/state_diff.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAY3C,MAAM,WAAW,eAAe;IAC5B,wEAAwE;IACxE,QAAQ,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,mDAAmD;IACnD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kDAAkD;IAClD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,8DAA8D;IAC9D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAID;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,MAAM,EAAE,MAAM,GAAG,IAAI,GACtB,eAAe,GAAG,IAAI,CAqCxB;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,GACtB,eAAe,GAAG,IAAI,CA+CxB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { insertStateSnapshot, getLatestSnapshot, insertStateChange, } from "../db/repositories.js";
|
|
3
|
+
import { getLogger } from "../logging/index.js";
|
|
4
|
+
const logger = getLogger().child({ component: "StateDiff" });
|
|
5
|
+
// ─── Hash computation ─────────────────────────────────────────────────────────
|
|
6
|
+
/**
|
|
7
|
+
* Compute a SHA-256 hex digest of a raw XDR value string.
|
|
8
|
+
* Used to quickly compare storage values without storing/diffing full payloads
|
|
9
|
+
* every cycle.
|
|
10
|
+
*/
|
|
11
|
+
export function computeValueHash(valueXdr) {
|
|
12
|
+
return createHash("sha256").update(valueXdr).digest("hex");
|
|
13
|
+
}
|
|
14
|
+
// ─── Diff logic ───────────────────────────────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* Compare two XDR value strings and produce a structured diff result.
|
|
17
|
+
*
|
|
18
|
+
* Returns `null` when the values are identical (including both-null),
|
|
19
|
+
* meaning no state change occurred.
|
|
20
|
+
*
|
|
21
|
+
* @param oldXdr - The previous XDR value, or null if the entry didn't exist.
|
|
22
|
+
* @param newXdr - The current XDR value, or null if the entry was removed.
|
|
23
|
+
*/
|
|
24
|
+
export function diffStateValues(oldXdr, newXdr) {
|
|
25
|
+
// Both null → no change
|
|
26
|
+
if (oldXdr === null && newXdr === null)
|
|
27
|
+
return null;
|
|
28
|
+
// Both present and identical → no change
|
|
29
|
+
if (oldXdr !== null && newXdr !== null && oldXdr === newXdr)
|
|
30
|
+
return null;
|
|
31
|
+
// Created: entry didn't exist before
|
|
32
|
+
if (oldXdr === null && newXdr !== null) {
|
|
33
|
+
return {
|
|
34
|
+
diffType: "created",
|
|
35
|
+
oldValueXdr: null,
|
|
36
|
+
newValueXdr: newXdr,
|
|
37
|
+
oldHash: null,
|
|
38
|
+
newHash: computeValueHash(newXdr),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// Deleted: entry existed before but is now gone
|
|
42
|
+
if (oldXdr !== null && newXdr === null) {
|
|
43
|
+
return {
|
|
44
|
+
diffType: "deleted",
|
|
45
|
+
oldValueXdr: oldXdr,
|
|
46
|
+
newValueXdr: null,
|
|
47
|
+
oldHash: computeValueHash(oldXdr),
|
|
48
|
+
newHash: null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Updated: both present and different
|
|
52
|
+
return {
|
|
53
|
+
diffType: "updated",
|
|
54
|
+
oldValueXdr: oldXdr,
|
|
55
|
+
newValueXdr: newXdr,
|
|
56
|
+
oldHash: computeValueHash(oldXdr),
|
|
57
|
+
newHash: computeValueHash(newXdr),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// ─── Orchestrator ─────────────────────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Process a state diff for a single contract entry within a monitoring cycle.
|
|
63
|
+
*
|
|
64
|
+
* 1. Fetch the latest snapshot for this entry from the DB.
|
|
65
|
+
* 2. Compare the current value hash against the stored hash.
|
|
66
|
+
* 3. If changed → persist a new snapshot and a state_change record.
|
|
67
|
+
* 4. If unchanged → return null (storage-optimised: no writes).
|
|
68
|
+
*
|
|
69
|
+
* @param db - An open better-sqlite3 Database handle.
|
|
70
|
+
* @param contractEntryId - The `contract_entries.id` of the entry being checked.
|
|
71
|
+
* @param currentValueXdr - The XDR-encoded value returned by the RPC for this entry.
|
|
72
|
+
* @param currentLedger - The ledger sequence at which this value was observed.
|
|
73
|
+
* @returns A `StateDiffResult` describing the change, or `null` if unchanged.
|
|
74
|
+
*/
|
|
75
|
+
export function processStateDiff(db, contractEntryId, currentValueXdr, currentLedger) {
|
|
76
|
+
const currentHash = computeValueHash(currentValueXdr);
|
|
77
|
+
const lastSnapshot = getLatestSnapshot(db, contractEntryId);
|
|
78
|
+
// ── Determine diff ────────────────────────────────────────────────────────
|
|
79
|
+
const oldXdr = lastSnapshot?.value_xdr ?? null;
|
|
80
|
+
const diff = diffStateValues(oldXdr, currentValueXdr);
|
|
81
|
+
if (diff === null) {
|
|
82
|
+
// Value unchanged — skip writes to optimise storage
|
|
83
|
+
logger.debug(`State unchanged for entry ${contractEntryId} at ledger ${currentLedger}`);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
// ── Persist new snapshot ──────────────────────────────────────────────────
|
|
87
|
+
const newSnapshotId = insertStateSnapshot(db, {
|
|
88
|
+
contract_entry_id: contractEntryId,
|
|
89
|
+
snapshot_ledger: currentLedger,
|
|
90
|
+
value_hash: currentHash,
|
|
91
|
+
value_xdr: currentValueXdr,
|
|
92
|
+
});
|
|
93
|
+
// ── Persist state change ─────────────────────────────────────────────────
|
|
94
|
+
const diffJson = JSON.stringify({
|
|
95
|
+
diffType: diff.diffType,
|
|
96
|
+
oldValueXdr: diff.oldValueXdr,
|
|
97
|
+
newValueXdr: diff.newValueXdr,
|
|
98
|
+
oldHash: diff.oldHash,
|
|
99
|
+
newHash: diff.newHash,
|
|
100
|
+
});
|
|
101
|
+
insertStateChange(db, {
|
|
102
|
+
contract_entry_id: contractEntryId,
|
|
103
|
+
old_snapshot_id: lastSnapshot?.id,
|
|
104
|
+
new_snapshot_id: newSnapshotId,
|
|
105
|
+
diff_type: diff.diffType,
|
|
106
|
+
diff_json: diffJson,
|
|
107
|
+
detected_at_ledger: currentLedger,
|
|
108
|
+
});
|
|
109
|
+
logger.info(`State ${diff.diffType} detected for entry ${contractEntryId} at ledger ${currentLedger}`);
|
|
110
|
+
return diff;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=state_diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state_diff.js","sourceRoot":"","sources":["../../src/core/state_diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import { type TTLStatus } from "../utils/formatting.js";
|
|
3
|
+
export type EntryTTLStatus = TTLStatus | "unknown";
|
|
4
|
+
export type ContractStatusEntry = {
|
|
5
|
+
label: string;
|
|
6
|
+
entryType: string;
|
|
7
|
+
entryKeyXdr: string;
|
|
8
|
+
liveUntilLedger: number | null;
|
|
9
|
+
remainingTTL: number | null;
|
|
10
|
+
approximateTimeRemaining: string | null;
|
|
11
|
+
status: EntryTTLStatus;
|
|
12
|
+
};
|
|
13
|
+
export type ContractStatus = {
|
|
14
|
+
contractId: string;
|
|
15
|
+
name: string | null;
|
|
16
|
+
network: string;
|
|
17
|
+
lastCheckedLedger: number | null;
|
|
18
|
+
entries: ContractStatusEntry[];
|
|
19
|
+
};
|
|
20
|
+
export declare class ContractNotFoundError extends Error {
|
|
21
|
+
constructor(contractId: string);
|
|
22
|
+
}
|
|
23
|
+
export declare function getContractStatus(db: Database.Database, contractId: string): ContractStatus;
|
|
24
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/core/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EAGH,KAAK,SAAS,EACjB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAEnD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,MAAM,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAClC,CAAC;AAEF,qBAAa,qBAAsB,SAAQ,KAAK;gBAChC,UAAU,EAAE,MAAM;CAIjC;AAyCD,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAmB3F"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getContract, getEntriesForContract } from "../db/repositories.js";
|
|
2
|
+
import { classifyTTL, formatTimeToCloseLedger, } from "../utils/formatting.js";
|
|
3
|
+
export class ContractNotFoundError extends Error {
|
|
4
|
+
constructor(contractId) {
|
|
5
|
+
super(`Contract ${contractId} is not registered.`);
|
|
6
|
+
this.name = "ContractNotFoundError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function getEntryLabel(entry) {
|
|
10
|
+
if (entry.entry_type === "instance")
|
|
11
|
+
return "Instance";
|
|
12
|
+
if (entry.entry_type === "wasm")
|
|
13
|
+
return "WASM Code";
|
|
14
|
+
return entry.label ?? entry.entry_type;
|
|
15
|
+
}
|
|
16
|
+
function mapEntryStatus(entry, lastCheckedLedger) {
|
|
17
|
+
const label = getEntryLabel(entry);
|
|
18
|
+
const liveUntilLedger = entry.live_until_ledger ?? null;
|
|
19
|
+
if (liveUntilLedger == null || lastCheckedLedger == null) {
|
|
20
|
+
return {
|
|
21
|
+
label,
|
|
22
|
+
entryType: entry.entry_type,
|
|
23
|
+
entryKeyXdr: entry.entry_key_xdr,
|
|
24
|
+
liveUntilLedger,
|
|
25
|
+
remainingTTL: null,
|
|
26
|
+
approximateTimeRemaining: null,
|
|
27
|
+
status: "unknown",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const remainingTTL = liveUntilLedger - lastCheckedLedger;
|
|
31
|
+
const status = classifyTTL(remainingTTL);
|
|
32
|
+
return {
|
|
33
|
+
label,
|
|
34
|
+
entryType: entry.entry_type,
|
|
35
|
+
entryKeyXdr: entry.entry_key_xdr,
|
|
36
|
+
liveUntilLedger,
|
|
37
|
+
remainingTTL,
|
|
38
|
+
approximateTimeRemaining: formatTimeToCloseLedger(remainingTTL),
|
|
39
|
+
status,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function getContractStatus(db, contractId) {
|
|
43
|
+
const contract = getContract(db, contractId);
|
|
44
|
+
if (!contract) {
|
|
45
|
+
throw new ContractNotFoundError(contractId);
|
|
46
|
+
}
|
|
47
|
+
const lastCheckedLedger = contract.last_checked_ledger ?? null;
|
|
48
|
+
const entries = getEntriesForContract(db, contractId).map((entry) => mapEntryStatus(entry, lastCheckedLedger));
|
|
49
|
+
return {
|
|
50
|
+
contractId: contract.id,
|
|
51
|
+
name: contract.name,
|
|
52
|
+
network: contract.network,
|
|
53
|
+
lastCheckedLedger,
|
|
54
|
+
entries,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/core/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE3E,OAAO,EACH,WAAW,EACX,uBAAuB,GAE1B,MAAM,wBAAwB,CAAC;AAsBhC,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC5C,YAAY,UAAkB;QAC1B,KAAK,CAAC,YAAY,UAAU,qBAAqB,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACxC,CAAC;CACJ;AAED,SAAS,aAAa,CAAC,KAAoB;IACvC,IAAI,KAAK,CAAC,UAAU,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IACvD,IAAI,KAAK,CAAC,UAAU,KAAK,MAAM;QAAE,OAAO,WAAW,CAAC;IACpD,OAAO,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;AAC3C,CAAC;AAED,SAAS,cAAc,CACnB,KAAoB,EACpB,iBAAgC;IAEhC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,eAAe,GAAG,KAAK,CAAC,iBAAiB,IAAI,IAAI,CAAC;IAExD,IAAI,eAAe,IAAI,IAAI,IAAI,iBAAiB,IAAI,IAAI,EAAE,CAAC;QACvD,OAAO;YACH,KAAK;YACL,SAAS,EAAE,KAAK,CAAC,UAAU;YAC3B,WAAW,EAAE,KAAK,CAAC,aAAa;YAChC,eAAe;YACf,YAAY,EAAE,IAAI;YAClB,wBAAwB,EAAE,IAAI;YAC9B,MAAM,EAAE,SAAS;SACpB,CAAC;IACN,CAAC;IAED,MAAM,YAAY,GAAG,eAAe,GAAG,iBAAiB,CAAC;IACzD,MAAM,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;IAEzC,OAAO;QACH,KAAK;QACL,SAAS,EAAE,KAAK,CAAC,UAAU;QAC3B,WAAW,EAAE,KAAK,CAAC,aAAa;QAChC,eAAe;QACf,YAAY;QACZ,wBAAwB,EAAE,uBAAuB,CAAC,YAAY,CAAC;QAC/D,MAAM;KACT,CAAC;AACN,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAqB,EAAE,UAAkB;IACvE,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAE7C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,MAAM,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,iBAAiB,GAAG,QAAQ,CAAC,mBAAmB,IAAI,IAAI,CAAC;IAC/D,MAAM,OAAO,GAAG,qBAAqB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAChE,cAAc,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAC3C,CAAC;IAEF,OAAO;QACH,UAAU,EAAE,QAAQ,CAAC,EAAE;QACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,iBAAiB;QACjB,OAAO;KACV,CAAC;AACN,CAAC"}
|