feat(twap-oracle): implement CreatePriceObservations instruction

Adds the CreatePriceObservations instruction to the TWAP oracle program.
The instruction initialises a PriceObservations PDA for a given price
source account and time window, writing the initial tick and timestamp
as the first entry.

Key design decisions:

- Per-window accounts: each (price_source, window_duration) pair maps to
  a distinct PriceObservations PDA. The window duration is baked into the
  PDA seed so a single price source can support multiple TWAP windows
  (24h, 7d, 30d) at independent sampling rates without sharing a buffer.

- window_duration not stored on struct: it is implicit in the PDA address.
  Any reader that located the account already knows the window duration
  used to derive it. Storing it would be redundant.

- Authorization is implicit: the PriceObservations PDA is derived from
  the price source account ID, so is_authorized = true on the price source
  proves the caller controls it without a redundant authority field.

- Impersonation is prevented by the PDA check: passing a controlled price
  source with a victim's observations account ID fails immediately because
  the computed PDA (from the attacker's source) does not match.

Closes #126
This commit is contained in:
r4bbit 2026-05-28 10:35:05 +02:00
parent 7b1696f98e
commit fe9d919299
16 changed files with 1020 additions and 319 deletions

114
Cargo.lock generated
View File

@ -336,9 +336,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "base16ct"
@ -472,9 +472,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.20.2"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytemuck"
@ -599,12 +599,12 @@ dependencies = [
[[package]]
name = "cipher"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
"block-buffer 0.12.0",
"crypto-common 0.2.1",
"crypto-common 0.2.2",
"inout",
]
@ -701,9 +701,9 @@ dependencies = [
[[package]]
name = "crypto-common"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
"hybrid-array",
]
@ -897,9 +897,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@ -964,9 +964,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "elf"
@ -1305,9 +1305,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
dependencies = [
"bytes",
"itoa",
@ -1353,9 +1353,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc"
dependencies = [
"atomic-waker",
"bytes",
@ -1644,9 +1644,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
@ -1730,9 +1730,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@ -1751,9 +1751,9 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "lru-slab"
@ -1772,9 +1772,9 @@ dependencies = [
[[package]]
name = "maybe-async"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c"
dependencies = [
"proc-macro2",
"quote",
@ -1783,9 +1783,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "merlin"
@ -1898,9 +1898,9 @@ dependencies = [
[[package]]
name = "num-conv"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
@ -2074,7 +2074,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit 0.25.11+spec-1.1.0",
"toml_edit 0.25.12+spec-1.1.0",
]
[[package]]
@ -2846,9 +2846,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.149"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
@ -3353,14 +3353,14 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
version = "0.25.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
dependencies = [
"indexmap 2.14.0",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3369,7 +3369,7 @@ version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3395,9 +3395,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.10"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
"bitflags 2.11.1",
"bytes",
@ -3486,6 +3486,7 @@ version = "0.1.0"
dependencies = [
"borsh",
"nssa_core",
"risc0-zkvm",
"serde",
"spel-framework-macros",
]
@ -3494,6 +3495,7 @@ dependencies = [
name = "twap_oracle_program"
version = "0.1.0"
dependencies = [
"clock_core",
"nssa_core",
"twap_oracle_core",
]
@ -3593,9 +3595,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
@ -3606,9 +3608,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.71"
version = "0.4.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3616,9 +3618,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3626,9 +3628,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
@ -3639,9 +3641,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
@ -3695,9 +3697,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3948,9 +3950,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
dependencies = [
"memchr",
]
@ -4091,18 +4093,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
dependencies = [
"proc-macro2",
"quote",

View File

@ -260,6 +260,38 @@
]
}
},
{
"name": "PriceObservations",
"type": {
"kind": "struct",
"fields": [
{
"name": "price_source_id",
"type": "account_id"
},
{
"name": "write_index",
"type": "u32"
},
{
"name": "total_entries",
"type": "u64"
},
{
"name": "last_recorded_tick",
"type": "i32"
},
{
"name": "entries",
"type": {
"vec": {
"defined": "ObservationEntry"
}
}
}
]
}
},
{
"name": "OraclePriceAccount",
"type": {
@ -294,6 +326,20 @@
}
],
"types": [
{
"name": "ObservationEntry",
"kind": "struct",
"fields": [
{
"name": "timestamp",
"type": "u64"
},
{
"name": "tick_cumulative",
"type": "i64"
}
]
},
{
"name": "MetadataStandard",
"kind": "enum",

View File

@ -3,12 +3,72 @@
"name": "twap_oracle",
"instructions": [
{
"name": "noop",
"accounts": [],
"args": []
"name": "create_price_observations",
"accounts": [
{
"name": "price_observations",
"writable": false,
"signer": false,
"init": false
},
{
"name": "price_source",
"writable": false,
"signer": false,
"init": false
},
{
"name": "clock",
"writable": false,
"signer": false,
"init": false
}
],
"args": [
{
"name": "initial_tick",
"type": "i32"
},
{
"name": "window_duration",
"type": "u64"
}
]
}
],
"accounts": [
{
"name": "PriceObservations",
"type": {
"kind": "struct",
"fields": [
{
"name": "price_source_id",
"type": "account_id"
},
{
"name": "write_index",
"type": "u32"
},
{
"name": "total_entries",
"type": "u64"
},
{
"name": "last_recorded_tick",
"type": "i32"
},
{
"name": "entries",
"type": {
"vec": {
"defined": "ObservationEntry"
}
}
}
]
}
},
{
"name": "OraclePriceAccount",
"type": {
@ -42,5 +102,21 @@
}
}
],
"types": [
{
"name": "ObservationEntry",
"kind": "struct",
"fields": [
{
"name": "timestamp",
"type": "u64"
},
{
"name": "tick_cumulative",
"type": "i64"
}
]
}
],
"instruction_type": "twap_oracle_core::Instruction"
}

View File

@ -313,9 +313,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "base16ct"
@ -449,9 +449,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.20.2"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytemuck"
@ -576,12 +576,12 @@ dependencies = [
[[package]]
name = "cipher"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
"block-buffer 0.12.0",
"crypto-common 0.2.1",
"crypto-common 0.2.2",
"inout",
]
@ -669,9 +669,9 @@ dependencies = [
[[package]]
name = "crypto-common"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
"hybrid-array",
]
@ -865,9 +865,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@ -932,9 +932,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "elf"
@ -1273,9 +1273,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
dependencies = [
"bytes",
"itoa",
@ -1321,9 +1321,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc"
dependencies = [
"atomic-waker",
"bytes",
@ -1587,9 +1587,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
@ -1673,9 +1673,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@ -1694,9 +1694,9 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "lru-slab"
@ -1715,9 +1715,9 @@ dependencies = [
[[package]]
name = "maybe-async"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c"
dependencies = [
"proc-macro2",
"quote",
@ -1726,9 +1726,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "merlin"
@ -1819,9 +1819,9 @@ dependencies = [
[[package]]
name = "num-conv"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
@ -1995,7 +1995,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit 0.25.11+spec-1.1.0",
"toml_edit 0.25.12+spec-1.1.0",
]
[[package]]
@ -2766,9 +2766,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.149"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
@ -3238,14 +3238,14 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
version = "0.25.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
dependencies = [
"indexmap 2.14.0",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3254,7 +3254,7 @@ version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3280,9 +3280,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.10"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
"bitflags 2.11.1",
"bytes",
@ -3451,9 +3451,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
@ -3464,9 +3464,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.71"
version = "0.4.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3474,9 +3474,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3484,9 +3484,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
@ -3497,9 +3497,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
@ -3553,9 +3553,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3806,9 +3806,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
dependencies = [
"memchr",
]
@ -3949,18 +3949,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
dependencies = [
"proc-macro2",
"quote",
@ -3969,9 +3969,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]

View File

@ -311,9 +311,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "base16ct"
@ -447,9 +447,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.20.2"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytemuck"
@ -574,12 +574,12 @@ dependencies = [
[[package]]
name = "cipher"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
"block-buffer 0.12.0",
"crypto-common 0.2.1",
"crypto-common 0.2.2",
"inout",
]
@ -667,9 +667,9 @@ dependencies = [
[[package]]
name = "crypto-common"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
"hybrid-array",
]
@ -863,9 +863,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@ -930,9 +930,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "elf"
@ -1271,9 +1271,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
dependencies = [
"bytes",
"itoa",
@ -1319,9 +1319,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc"
dependencies = [
"atomic-waker",
"bytes",
@ -1585,9 +1585,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
@ -1671,9 +1671,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@ -1692,9 +1692,9 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "lru-slab"
@ -1713,9 +1713,9 @@ dependencies = [
[[package]]
name = "maybe-async"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c"
dependencies = [
"proc-macro2",
"quote",
@ -1724,9 +1724,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "merlin"
@ -1817,9 +1817,9 @@ dependencies = [
[[package]]
name = "num-conv"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
@ -1993,7 +1993,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit 0.25.11+spec-1.1.0",
"toml_edit 0.25.12+spec-1.1.0",
]
[[package]]
@ -2764,9 +2764,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.149"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
@ -3236,14 +3236,14 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
version = "0.25.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
dependencies = [
"indexmap 2.14.0",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3252,7 +3252,7 @@ version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3278,9 +3278,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.10"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
"bitflags 2.11.1",
"bytes",
@ -3449,9 +3449,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
@ -3462,9 +3462,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.71"
version = "0.4.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3472,9 +3472,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3482,9 +3482,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
@ -3495,9 +3495,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
@ -3551,9 +3551,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3804,9 +3804,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
dependencies = [
"memchr",
]
@ -3947,18 +3947,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
dependencies = [
"proc-macro2",
"quote",
@ -3967,9 +3967,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]

View File

@ -278,9 +278,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "base16ct"
@ -414,9 +414,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.20.2"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytemuck"
@ -541,12 +541,12 @@ dependencies = [
[[package]]
name = "cipher"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
"block-buffer 0.12.0",
"crypto-common 0.2.1",
"crypto-common 0.2.2",
"inout",
]
@ -634,9 +634,9 @@ dependencies = [
[[package]]
name = "crypto-common"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
"hybrid-array",
]
@ -830,9 +830,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@ -897,9 +897,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "elf"
@ -1238,9 +1238,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
dependencies = [
"bytes",
"itoa",
@ -1286,9 +1286,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc"
dependencies = [
"atomic-waker",
"bytes",
@ -1552,9 +1552,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
@ -1638,9 +1638,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@ -1659,9 +1659,9 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "lru-slab"
@ -1680,9 +1680,9 @@ dependencies = [
[[package]]
name = "maybe-async"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c"
dependencies = [
"proc-macro2",
"quote",
@ -1691,9 +1691,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "merlin"
@ -1784,9 +1784,9 @@ dependencies = [
[[package]]
name = "num-conv"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
@ -1960,7 +1960,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit 0.25.11+spec-1.1.0",
"toml_edit 0.25.12+spec-1.1.0",
]
[[package]]
@ -2731,9 +2731,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.149"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
@ -3239,14 +3239,14 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
version = "0.25.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
dependencies = [
"indexmap 2.14.0",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3255,7 +3255,7 @@ version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3281,9 +3281,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.10"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
"bitflags 2.11.1",
"bytes",
@ -3363,6 +3363,7 @@ version = "0.1.0"
dependencies = [
"borsh",
"nssa_core",
"risc0-zkvm",
"serde",
"spel-framework-macros",
]
@ -3462,9 +3463,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
@ -3475,9 +3476,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.71"
version = "0.4.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3485,9 +3486,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3495,9 +3496,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
@ -3508,9 +3509,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
@ -3564,9 +3565,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3817,9 +3818,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
dependencies = [
"memchr",
]
@ -3960,18 +3961,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
dependencies = [
"proc-macro2",
"quote",

View File

@ -278,9 +278,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "base16ct"
@ -414,9 +414,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.20.2"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytemuck"
@ -541,12 +541,12 @@ dependencies = [
[[package]]
name = "cipher"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
"block-buffer 0.12.0",
"crypto-common 0.2.1",
"crypto-common 0.2.2",
"inout",
]
@ -634,9 +634,9 @@ dependencies = [
[[package]]
name = "crypto-common"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
"hybrid-array",
]
@ -830,9 +830,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@ -897,9 +897,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "elf"
@ -1238,9 +1238,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
dependencies = [
"bytes",
"itoa",
@ -1286,9 +1286,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc"
dependencies = [
"atomic-waker",
"bytes",
@ -1552,9 +1552,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
@ -1638,9 +1638,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@ -1659,9 +1659,9 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "lru-slab"
@ -1680,9 +1680,9 @@ dependencies = [
[[package]]
name = "maybe-async"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c"
dependencies = [
"proc-macro2",
"quote",
@ -1691,9 +1691,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "merlin"
@ -1784,9 +1784,9 @@ dependencies = [
[[package]]
name = "num-conv"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
@ -1960,7 +1960,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit 0.25.11+spec-1.1.0",
"toml_edit 0.25.12+spec-1.1.0",
]
[[package]]
@ -2731,9 +2731,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.149"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
@ -3224,14 +3224,14 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
version = "0.25.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
dependencies = [
"indexmap 2.14.0",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3240,7 +3240,7 @@ version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow 1.0.2",
"winnow 1.0.3",
]
[[package]]
@ -3266,9 +3266,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.10"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
"bitflags 2.11.1",
"bytes",
@ -3437,9 +3437,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
@ -3450,9 +3450,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.71"
version = "0.4.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3460,9 +3460,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3470,9 +3470,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
@ -3483,9 +3483,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
@ -3539,9 +3539,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3792,9 +3792,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
dependencies = [
"memchr",
]
@ -3935,18 +3935,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
dependencies = [
"proc-macro2",
"quote",
@ -3955,9 +3955,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]

View File

@ -5,4 +5,8 @@ edition = "2021"
[dependencies]
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3", features = ["host"] }
clock_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3" }
twap_oracle_core = { path = "core" }
[lints]
workspace = true

View File

@ -3,8 +3,12 @@ name = "twap_oracle_core"
version = "0.1.0"
edition = "2021"
[lints]
workspace = true
[dependencies]
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3", features = ["host"] }
borsh = { version = "1.5", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
spel-framework-macros = { git = "https://github.com/logos-co/spel.git", tag = "v0.3.0", package = "spel-framework-macros" }
risc0-zkvm = { version = "=3.0.5", default-features = false }

View File

@ -1,18 +1,166 @@
use borsh::{BorshDeserialize, BorshSerialize};
use nssa_core::account::{AccountId, Data};
use nssa_core::{
account::{AccountId, Data},
program::{PdaSeed, ProgramId},
};
use serde::{Deserialize, Serialize};
use spel_framework_macros::account_type;
/// TWAP Oracle Program Instruction.
#[derive(Debug, Serialize, Deserialize)]
pub enum Instruction {
/// No-op instruction. Does nothing and returns no state changes.
Noop,
/// Creates and initialises a price feed account for a price source and time window.
///
/// Required accounts (in order):
/// 1. Price feed account — uninitialized PDA derived from
/// `compute_price_observations_pda(self_program_id, price_source.account_id,
/// window_duration)`.
/// 2. Price source account — the account whose ID acts as the feed identifier (e.g. an AMM
/// pool account); must be passed with `is_authorized = true` to prove the caller controls
/// it.
/// 3. Clock account — read-only; supplies the initial observation timestamp.
CreatePriceObservations {
/// Initial price tick: `floor(log_{1.0001}(reserve_b / reserve_a))`.
initial_tick: i32,
/// Duration of the TWAP window this feed serves, in milliseconds.
///
/// Together with `OBSERVATIONS_CAPACITY` this determines the minimum sampling interval
/// enforced by `RecordPrice`: `min_interval = window_duration / OBSERVATIONS_CAPACITY`.
/// It is also part of the PDA seed, so each window gets a distinct account.
window_duration: u64,
},
}
// ──────────────────────────────────────────────────────────────────────────────
// Price feed
// ──────────────────────────────────────────────────────────────────────────────
/// Number of entries in each price feed.
///
/// 6 396 is the maximum that fits within the `DATA_MAX_LENGTH = 100 KiB` runtime ceiling.
/// Each [`ObservationEntry`] is 16 bytes (`timestamp` 8 + `tick_cumulative` 8); fixed overhead
/// is 52 bytes (`price_source_id` 32 + `write_index` 4 + `total_entries` 8 +
/// `last_recorded_tick` 4 + Borsh `Vec` length prefix 4), leaving 102 348 bytes for entries:
/// `floor(102 348 / 16) = 6 396`.
///
/// The effective history window depends on the `window_duration` used to derive the feed PDA
/// and the sampling guard: `min_interval = window_duration / OBSERVATIONS_CAPACITY`. A 24 h feed
/// samples every ~13 s; a 7 d feed every ~94 s; a 30 d feed every ~7 min.
pub const OBSERVATIONS_CAPACITY: u32 = 6396;
/// A single price entry written to a [`PriceObservations`].
#[derive(
Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
)]
pub struct ObservationEntry {
/// Block timestamp (milliseconds) when this entry was recorded.
pub timestamp: u64,
/// Running sum of `tick × elapsed_ms` up to this entry.
///
/// Grows without bound over time, which is why this is `i64` rather than `i32`.
/// The TWAP over any window `[t1, t2]` is computed as
/// `(tick_cumulative[t2] - tick_cumulative[t1]) / (t2 - t1)`.
pub tick_cumulative: i64,
}
/// Circular price feed of tick observations for a price source and time window.
///
/// Owned by the TWAP oracle as a PDA derived from
/// `compute_price_observations_pda(oracle_program_id, price_source_id, window_duration)`.
/// The window duration is not stored here — it is implicit in the PDA address. Any caller
/// that locates this account already knows the window duration used to derive it.
/// Only the account that controls `price_source_id` (proven via `is_authorized = true` at call
/// time) may append new entries via `RecordPrice`.
#[account_type]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct PriceObservations {
/// ID of the price source account this feed is associated with (e.g. an AMM pool).
/// The price feed PDA is derived from this ID and the window duration, so authorization is
/// implicit: whoever controls `price_source_id` is authorized to record prices.
pub price_source_id: AccountId,
/// Index of the *next* slot to write (wraps at `OBSERVATIONS_CAPACITY`).
pub write_index: u32,
/// Total entries ever appended (never resets; used to detect empty/partial-fill state).
pub total_entries: u64,
/// The raw (untruncated) tick from the most recent `RecordTick` call.
///
/// Used by `RecordTick` to compute the tick delta for the next observation:
/// `delta = current_tick - last_recorded_tick`. Stored as the actual tick, not the
/// clamped value, so that each successive delta is computed from the true price position.
pub last_recorded_tick: i32,
/// Circular price entries; always exactly `OBSERVATIONS_CAPACITY` elements.
pub entries: Vec<ObservationEntry>,
}
impl TryFrom<&Data> for PriceObservations {
type Error = std::io::Error;
fn try_from(data: &Data) -> Result<Self, Self::Error> {
Self::try_from_slice(data.as_ref())
}
}
impl From<&PriceObservations> for Data {
fn from(feed: &PriceObservations) -> Self {
let serialized_len =
borsh::object_length(feed).expect("PriceObservations length must be known");
let mut data = Vec::with_capacity(serialized_len);
BorshSerialize::serialize(feed, &mut data).expect("Serialization to Vec should not fail");
Self::try_from(data).expect("PriceObservations encoded data should fit into Data")
}
}
// ──────────────────────────────────────────────────────────────────────────────
// PDA helpers
// ──────────────────────────────────────────────────────────────────────────────
const PRICE_OBSERVATIONS_PDA_SEED: [u8; 32] = [2; 32];
/// Derives the [`AccountId`] for a price source's [`PriceObservations`] PDA.
///
/// The `window_duration` is included in the seed so that each `(price_source, window)` pair
/// maps to a distinct account.
#[must_use]
pub fn compute_price_observations_pda(
oracle_program_id: ProgramId,
price_source_id: AccountId,
window_duration: u64,
) -> AccountId {
AccountId::for_public_pda(
&oracle_program_id,
&compute_price_observations_pda_seed(price_source_id, window_duration),
)
}
/// Derives the [`PdaSeed`] for a price source's [`PriceObservations`].
///
/// Hash input: `price_source_id (32 bytes) || window_duration_le (8 bytes) ||
/// PRICE_OBSERVATIONS_PDA_SEED (32 bytes)`.
#[must_use]
pub fn compute_price_observations_pda_seed(
price_source_id: AccountId,
window_duration: u64,
) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut bytes = [0u8; 72];
bytes[..32].copy_from_slice(&price_source_id.to_bytes());
bytes[32..40].copy_from_slice(&window_duration.to_le_bytes());
bytes[40..72].copy_from_slice(&PRICE_OBSERVATIONS_PDA_SEED);
PdaSeed::new(
Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Hash output must be exactly 32 bytes long"),
)
}
/// Canonical oracle price account consumed by LEZ programs.
///
/// Oracle producers own how this account is written; consumers only read and validate it.
/// Oracle producers own how this account is written; consumers only read and
/// validate it. The account shape is intentionally generic so that any oracle
/// type (TWAP, external adaptor, aggregator) can use the same interface.
#[account_type]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct OraclePriceAccount {

View File

@ -550,6 +550,15 @@ dependencies = [
"inout",
]
[[package]]
name = "clock_core"
version = "0.1.0"
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc3#cf3639d8252040d13b3d4e933feb19b42c76e14a"
dependencies = [
"borsh",
"nssa_core",
]
[[package]]
name = "cobs"
version = "0.3.0"
@ -830,9 +839,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@ -1238,9 +1247,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
dependencies = [
"bytes",
"itoa",
@ -1286,9 +1295,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc"
dependencies = [
"atomic-waker",
"bytes",
@ -1638,9 +1647,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@ -1691,9 +1700,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "merlin"
@ -1960,7 +1969,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit 0.25.11+spec-1.1.0",
"toml_edit 0.25.12+spec-1.1.0",
]
[[package]]
@ -3193,9 +3202,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
version = "0.25.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
dependencies = [
"indexmap 2.14.0",
"toml_datetime 1.1.1+spec-1.1.0",
@ -3316,6 +3325,7 @@ name = "twap-oracle-guest"
version = "0.1.0"
dependencies = [
"borsh",
"clock_core",
"nssa_core",
"risc0-zkvm",
"serde",
@ -3330,6 +3340,7 @@ version = "0.1.0"
dependencies = [
"borsh",
"nssa_core",
"risc0-zkvm",
"serde",
"spel-framework-macros",
]
@ -3338,6 +3349,7 @@ dependencies = [
name = "twap_oracle_program"
version = "0.1.0"
dependencies = [
"clock_core",
"nssa_core",
"twap_oracle_core",
]
@ -3935,18 +3947,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
dependencies = [
"proc-macro2",
"quote",

View File

@ -12,6 +12,7 @@ path = "src/bin/twap_oracle.rs"
[dependencies]
spel-framework = { git = "https://github.com/logos-co/spel.git", tag = "v0.3.0", package = "spel-framework" }
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3" }
clock_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3" }
risc0-zkvm = { version = "=3.0.5", default-features = false }
twap_oracle_core = { path = "../../core" }
twap_oracle_program = { path = "../..", package = "twap_oracle_program" }

View File

@ -1,5 +1,7 @@
#![cfg_attr(not(test), no_main)]
use nssa_core::account::AccountWithMetadata;
use spel_framework::context::ProgramContext;
use spel_framework::prelude::*;
#[cfg(not(test))]
@ -10,9 +12,31 @@ mod twap_oracle {
#[allow(unused_imports)]
use super::*;
/// No-op instruction. Does nothing and returns no state changes.
/// Creates and initialises a price observations account for a price source and time window.
///
/// Expected accounts:
/// 1. `price_observations` — uninitialized PDA owned by this oracle program.
/// 2. `price_source` — account the caller controls (proven via `is_authorized = true`);
/// its ID is used as the observations identifier and to derive the price observations PDA.
/// 3. `clock` — read-only LEZ clock account (any cadence).
#[instruction]
pub fn noop() -> SpelResult {
Ok(spel_framework::SpelOutput::execute(twap_oracle_program::noop::noop(), vec![]))
pub fn create_price_observations(
ctx: ProgramContext,
price_observations: AccountWithMetadata,
price_source: AccountWithMetadata,
clock: AccountWithMetadata,
initial_tick: i32,
window_duration: u64,
) -> SpelResult {
let post_states =
twap_oracle_program::create_price_observations::create_price_observations(
price_observations,
price_source,
clock,
initial_tick,
window_duration,
ctx.self_program_id,
);
Ok(spel_framework::SpelOutput::execute(post_states, vec![]))
}
}

View File

@ -0,0 +1,388 @@
use clock_core::ClockAccountData;
use nssa_core::{
account::{Account, AccountWithMetadata, Data},
program::{AccountPostState, Claim, ProgramId},
};
use twap_oracle_core::{
compute_price_observations_pda, compute_price_observations_pda_seed, ObservationEntry,
PriceObservations, OBSERVATIONS_CAPACITY,
};
/// Creates and initialises a [`PriceObservations`] for a price source account and time window.
///
/// Authorization is implicit in the PDA relationship: the price observations account is derived
/// from `price_source.account_id` and `window_duration`, so whoever controls the price source
/// controls the observations account.
///
/// # Panics
/// Panics if:
/// - `price_observations.account_id` does not match
/// `compute_price_observations_pda(oracle_program_id, price_source.account_id, window_duration)`.
/// - `price_observations.account` is not the default (already initialised).
/// - `price_source.is_authorized` is false (caller does not control the price source account).
pub fn create_price_observations(
price_observations: AccountWithMetadata,
price_source: AccountWithMetadata,
clock: AccountWithMetadata,
initial_tick: i32,
window_duration: u64,
oracle_program_id: ProgramId,
) -> Vec<AccountPostState> {
let price_source_id = price_source.account_id;
assert_eq!(
price_observations.account_id,
compute_price_observations_pda(oracle_program_id, price_source_id, window_duration),
"CreatePriceObservations: price observations account ID does not match expected PDA"
);
assert_eq!(
price_observations.account,
Account::default(),
"CreatePriceObservations: price observations account must be uninitialized"
);
assert!(
price_source.is_authorized,
"CreatePriceObservations: price source account must be authorized (caller must control it via a PDA)"
);
let clock_data = ClockAccountData::from_bytes(clock.account.data.as_ref());
let capacity =
usize::try_from(OBSERVATIONS_CAPACITY).expect("OBSERVATIONS_CAPACITY fits in usize");
let mut entries = vec![ObservationEntry::default(); capacity];
*entries
.first_mut()
.expect("OBSERVATIONS_CAPACITY is non-zero") = ObservationEntry {
timestamp: clock_data.timestamp,
tick_cumulative: 0,
};
let observations = PriceObservations {
price_source_id,
write_index: 1,
total_entries: 1,
last_recorded_tick: initial_tick,
entries,
};
let mut price_observations_post = price_observations.account.clone();
price_observations_post.data = Data::from(&observations);
vec![
AccountPostState::new_claimed(
price_observations_post,
Claim::Pda(compute_price_observations_pda_seed(
price_source_id,
window_duration,
)),
),
AccountPostState::new(price_source.account.clone()),
AccountPostState::new(clock.account.clone()),
]
}
#[cfg(test)]
mod tests {
use nssa_core::account::{AccountId, Nonce};
use super::*;
const ORACLE_PROGRAM_ID: ProgramId = [77u32; 8];
const CLOCK_PROGRAM_ID: ProgramId = [88u32; 8];
/// 24-hour window in milliseconds, used as the default window for tests.
const WINDOW_24H: u64 = 24 * 60 * 60 * 1_000;
fn price_source_id() -> AccountId {
AccountId::new([1u8; 32])
}
fn clock_account_with_timestamp(timestamp: u64) -> AccountWithMetadata {
let data = ClockAccountData {
block_id: 0,
timestamp,
}
.to_bytes();
AccountWithMetadata {
account: Account {
program_owner: CLOCK_PROGRAM_ID,
balance: 0,
data: Data::try_from(data).expect("ClockAccountData fits in Data"),
nonce: Nonce(0),
},
is_authorized: false,
account_id: AccountId::new([99u8; 32]),
}
}
fn price_source_authorized() -> AccountWithMetadata {
AccountWithMetadata {
account: Account {
program_owner: [42u32; 8],
balance: 0,
data: Data::default(),
nonce: Nonce(0),
},
is_authorized: true,
account_id: price_source_id(),
}
}
fn price_observations_uninit() -> AccountWithMetadata {
AccountWithMetadata {
account: Account::default(),
is_authorized: false,
account_id: compute_price_observations_pda(
ORACLE_PROGRAM_ID,
price_source_id(),
WINDOW_24H,
),
}
}
// ── happy path ────────────────────────────────────────────────────────────
#[test]
fn returns_three_post_states() {
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
assert_eq!(post_states.len(), 3);
}
#[test]
fn price_observations_post_state_is_pda_claimed() {
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
assert_eq!(
post_states[0].required_claim(),
Some(Claim::Pda(compute_price_observations_pda_seed(
price_source_id(),
WINDOW_24H
)))
);
}
#[test]
fn price_source_and_clock_post_states_are_unchanged() {
let price_source = price_source_authorized();
let clock = clock_account_with_timestamp(42_000);
let post_states = create_price_observations(
price_observations_uninit(),
price_source.clone(),
clock.clone(),
10,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
assert_eq!(*post_states[1].account(), price_source.account);
assert_eq!(*post_states[2].account(), clock.account);
}
#[test]
fn initial_observation_has_zero_cumulative_and_correct_timestamp() {
let timestamp = 123_456_789u64;
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(timestamp),
-42,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
let feed = PriceObservations::try_from(&post_states[0].account().data)
.expect("post state must contain a valid PriceObservations");
assert_eq!(feed.entries[0].tick_cumulative, 0);
assert_eq!(feed.entries[0].timestamp, timestamp);
}
#[test]
fn initial_tick_stored_as_last_recorded_tick() {
let initial_tick = -42i32;
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(0),
initial_tick,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
let feed = PriceObservations::try_from(&post_states[0].account().data)
.expect("post state must contain a valid PriceObservations");
assert_eq!(feed.last_recorded_tick, initial_tick);
}
#[test]
fn write_index_and_total_entries_start_at_one() {
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
let feed = PriceObservations::try_from(&post_states[0].account().data)
.expect("post state must contain a valid PriceObservations");
assert_eq!(feed.write_index, 1);
assert_eq!(feed.total_entries, 1);
}
#[test]
fn remaining_entries_are_default() {
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
let feed = PriceObservations::try_from(&post_states[0].account().data)
.expect("post state must contain a valid PriceObservations");
assert_eq!(
feed.entries.len(),
usize::try_from(OBSERVATIONS_CAPACITY).expect("OBSERVATIONS_CAPACITY fits in usize")
);
assert!(feed.entries[1..]
.iter()
.all(|e| *e == ObservationEntry::default()));
}
#[test]
fn price_source_id_stored_correctly() {
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
let feed = PriceObservations::try_from(&post_states[0].account().data)
.expect("post state must contain a valid PriceObservations");
assert_eq!(feed.price_source_id, price_source_id());
}
#[test]
fn different_windows_produce_distinct_pdas() {
let window_24h = 24 * 60 * 60 * 1_000u64;
let window_7d = 7 * 24 * 60 * 60 * 1_000u64;
assert_ne!(
compute_price_observations_pda(ORACLE_PROGRAM_ID, price_source_id(), window_24h),
compute_price_observations_pda(ORACLE_PROGRAM_ID, price_source_id(), window_7d),
);
}
#[test]
fn positive_and_negative_initial_ticks_stored_as_last_recorded_tick() {
for tick in [i32::MIN, -1, 0, 1, i32::MAX] {
let post_states = create_price_observations(
price_observations_uninit(),
price_source_authorized(),
clock_account_with_timestamp(0),
tick,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
let feed = PriceObservations::try_from(&post_states[0].account().data)
.expect("post state must contain a valid PriceObservations");
assert_eq!(feed.last_recorded_tick, tick);
}
}
// ── precondition violations ───────────────────────────────────────────────
#[test]
#[should_panic(expected = "price observations account ID does not match expected PDA")]
fn wrong_price_feed_account_id_panics() {
let mut wrong_feed = price_observations_uninit();
wrong_feed.account_id = AccountId::new([0u8; 32]);
create_price_observations(
wrong_feed,
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
}
/// An attacker who controls their own price source cannot register an observations account
/// that claims to be derived from a *different* (victim's) price source.
///
/// The PDA derivation ties the observations account to the price source that was passed: if
/// the caller supplies their own authorized source but the victim's observations account ID,
/// the PDA check will fail because the computed PDA (from attacker's source) won't match.
#[test]
#[should_panic(expected = "price observations account ID does not match expected PDA")]
fn cannot_register_observations_for_another_price_source() {
let victim_source_id = AccountId::new([2u8; 32]);
// The attacker passes the victim's observations PDA as the target account…
let victim_observations_pda =
compute_price_observations_pda(ORACLE_PROGRAM_ID, victim_source_id, WINDOW_24H);
let mut attacker_observations = price_observations_uninit();
attacker_observations.account_id = victim_observations_pda;
// …but only controls their own price source (price_source_id = [1u8; 32]).
create_price_observations(
attacker_observations,
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
}
#[test]
#[should_panic(expected = "price observations account must be uninitialized")]
fn already_initialized_price_feed_panics() {
let mut initialized_feed = price_observations_uninit();
initialized_feed.account.data = Data::try_from(vec![1u8; 10]).expect("fits in Data");
create_price_observations(
initialized_feed,
price_source_authorized(),
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
}
#[test]
#[should_panic(expected = "price source account must be authorized")]
fn unauthorized_price_source_panics() {
let mut unauthorized = price_source_authorized();
unauthorized.is_authorized = false;
create_price_observations(
price_observations_uninit(),
unauthorized,
clock_account_with_timestamp(0),
0,
WINDOW_24H,
ORACLE_PROGRAM_ID,
);
}
}

View File

@ -2,4 +2,4 @@
pub use twap_oracle_core as core;
pub mod noop;
pub mod create_price_observations;

View File

@ -1,5 +0,0 @@
use nssa_core::program::AccountPostState;
pub fn noop() -> Vec<AccountPostState> {
vec![]
}