From 2e59dc0034c2e42744eb3a46ac965fc8bed82524 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 21 Oct 2026 01:31:43 +0200 Subject: [PATCH 01/20] feat(contract): report pending parameter votes by proposal hash in state() --- crates/backup-cli/assets/contract_state.json | 4 +- crates/contract/src/api/governance.rs | 68 ++++++++++++++++ crates/contract/src/api/lifecycle.rs | 3 +- crates/contract/src/dto_mapping.rs | 77 +++++++++++++------ .../src/primitives/threshold_votes.rs | 8 +- .../src/types/state.rs | 27 +++++-- 6 files changed, 152 insertions(+), 35 deletions(-) diff --git a/crates/backup-cli/assets/contract_state.json b/crates/backup-cli/assets/contract_state.json index e36b5e9a0a..33d347d3d7 100644 --- a/crates/backup-cli/assets/contract_state.json +++ b/crates/backup-cli/assets/contract_state.json @@ -164,9 +164,7 @@ }, "threshold": 7 }, - "parameters_votes": { - "proposal_by_account": {} - }, + "parameters_votes": {}, "add_domains_votes": { "proposal_by_account": {} } diff --git a/crates/contract/src/api/governance.rs b/crates/contract/src/api/governance.rs index c82c639b38..812897be54 100644 --- a/crates/contract/src/api/governance.rs +++ b/crates/contract/src/api/governance.rs @@ -125,6 +125,7 @@ mod tests { use crate::errors::{DomainError, InvalidCandidateSet, InvalidState, InvalidThreshold}; use crate::primitives::key_state::{AttemptId, EpochId, KeyEventId, KeyForDomain, Keyset}; use crate::primitives::participants::Participants; + use crate::primitives::proposal_hash::ToProposalHash; use crate::primitives::test_utils::{ authenticate_account_as, bogus_tee_verifier_account_id, gen_participants, }; @@ -576,6 +577,73 @@ mod tests { (contract, participants, domain_id, proposal) } + /// The `state()` tally for `voters` all voting `proposal`. + fn expected_tally( + proposal: &ProposedGovernanceThresholdParameters, + voters: &[&AccountId], + ) -> dtos::GovernanceThresholdParametersVotes { + dtos::GovernanceThresholdParametersVotes(BTreeMap::from([( + proposal.to_proposal_hash(), + voters + .iter() + .map(|voter| dtos::AuthenticatedAccountId((*voter).clone())) + .collect(), + )])) + } + + #[test] + fn state__should_report_pending_parameter_votes_by_proposal_hash() { + // Given + let (mut contract, participants, signer, _) = setup_running_contract_with_domain( + 3, + GovernanceThreshold::new(2), + ReconstructionThreshold::new(2), + ); + let proposal = ProposedGovernanceThresholdParameters::new( + GovernanceThresholdParameters::new(participants, GovernanceThreshold::new(2)).unwrap(), + BTreeMap::new(), + ); + + // When + vote_params(&mut contract, &signer, &proposal).unwrap(); + + // Then + let dtos::ProtocolContractState::Running(running) = contract.state() else { + panic!("expected Running state"); + }; + assert_eq!( + running.parameters_votes, + expected_tally(&proposal, &[&signer]) + ); + } + + #[test] + fn state__should_report_re_proposal_votes_while_resharing() { + // Given + let (mut contract, participants, _, proposal) = resharing_contract_with_domain(); + let (voter, _, _) = &participants.participants()[0]; + testing_env!( + VMContextBuilder::new() + .signer_account_id(voter.clone()) + .predecessor_account_id(voter.clone()) + .build() + ); + + // When + contract + .vote_new_parameters(dtos::EpochId::new(2), (&proposal).into_dto_type()) + .unwrap(); + + // Then + let dtos::ProtocolContractState::Resharing(resharing) = contract.state() else { + panic!("expected Resharing state"); + }; + assert_eq!( + resharing.previous_running_state.parameters_votes, + expected_tally(&proposal, &[voter]) + ); + } + #[test] fn vote_new_parameters__should_record_a_re_proposal_vote_while_resharing() { // Given diff --git a/crates/contract/src/api/lifecycle.rs b/crates/contract/src/api/lifecycle.rs index 513f1d60ee..b8499ed119 100644 --- a/crates/contract/src/api/lifecycle.rs +++ b/crates/contract/src/api/lifecycle.rs @@ -188,7 +188,8 @@ impl MpcContract { } pub fn state(&self) -> near_mpc_contract_interface::types::ProtocolContractState { - (&self.protocol_state).into_dto_type() + let parameters_votes = (&self.parameters_votes).into_dto_type(); + (&self.protocol_state, parameters_votes).into_dto_type() } pub fn config(&self) -> dtos::Config { diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index 7f522259f9..88ff2feeeb 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -14,7 +14,6 @@ use mpc_attestation::{ collateral::Collateral, }; use near_mpc_contract_interface::types as dtos; -use std::collections::BTreeMap; use crate::{ config::Config, @@ -24,6 +23,7 @@ use crate::{ domain::{AddDomainsVotes, DomainRegistry}, key_state::{AuthenticatedAccountId, AuthenticatedParticipantId, KeyForDomain, Keyset}, participants::{ParticipantInfo, Participants}, + threshold_votes::GovernanceThresholdParametersVotes, thresholds::{GovernanceThresholdParameters, ProposedGovernanceThresholdParameters}, votes::Votes, }, @@ -619,7 +619,8 @@ mod test_conversions { impl From for dtos::ProtocolContractState { fn from(state: ProtocolContractState) -> Self { - (&state).into_dto_type() + // Parameter votes live on `MpcContract`, which this path lacks: the tally is empty. + (&state, dtos::GovernanceThresholdParametersVotes::default()).into_dto_type() } } @@ -816,6 +817,21 @@ impl IntoInterfaceType for &AddDomainsVotes { } } +impl IntoInterfaceType + for &GovernanceThresholdParametersVotes +{ + fn into_dto_type(self) -> dtos::GovernanceThresholdParametersVotes { + dtos::GovernanceThresholdParametersVotes( + self.all() + .into_iter() + .map(|(proposal, voters)| { + (proposal, voters.iter().map(|v| v.into_dto_type()).collect()) + }) + .collect(), + ) + } +} + impl IntoInterfaceType for &Votes { fn into_dto_type(self) -> dtos::MeasurementVotes { dtos::MeasurementVotes( @@ -958,54 +974,71 @@ impl IntoInterfaceType for &InitializingContrac } } -impl IntoInterfaceType for &RunningContractState { +/// Parameter votes live on [`crate::MpcContract`], so the caller supplies the converted tally. +impl IntoInterfaceType + for ( + &RunningContractState, + dtos::GovernanceThresholdParametersVotes, + ) +{ fn into_dto_type(self) -> dtos::RunningContractState { + let (state, parameters_votes) = self; dtos::RunningContractState { - domains: (&self.domains).into_dto_type(), - keyset: (&self.keyset).into_dto_type(), - parameters: (&self.parameters).into_dto_type(), - // Pending votes are stored hash-only, so their proposals can't be reported. - parameters_votes: dtos::GovernanceThresholdParametersVotes { - proposal_by_account: BTreeMap::new(), - }, - add_domains_votes: (&self.add_domains_votes).into_dto_type(), - previously_cancelled_resharing_epoch_id: self.previously_cancelled_resharing_epoch_id, + domains: (&state.domains).into_dto_type(), + keyset: (&state.keyset).into_dto_type(), + parameters: (&state.parameters).into_dto_type(), + parameters_votes, + add_domains_votes: (&state.add_domains_votes).into_dto_type(), + previously_cancelled_resharing_epoch_id: state.previously_cancelled_resharing_epoch_id, } } } -impl IntoInterfaceType for &ResharingContractState { +impl IntoInterfaceType + for ( + &ResharingContractState, + dtos::GovernanceThresholdParametersVotes, + ) +{ fn into_dto_type(self) -> dtos::ResharingContractState { + let (state, parameters_votes) = self; dtos::ResharingContractState { - previous_running_state: (&self.previous_running_state).into_dto_type(), - reshared_keys: self + previous_running_state: (&state.previous_running_state, parameters_votes) + .into_dto_type(), + reshared_keys: state .reshared_keys .iter() .map(|k| k.into_dto_type()) .collect(), - resharing_key: (&self.resharing_key).into_dto_type(), - cancellation_requests: self + resharing_key: (&state.resharing_key).into_dto_type(), + cancellation_requests: state .cancellation_requests .iter() .map(|a| a.into_dto_type()) .collect(), - per_domain_thresholds: self.per_domain_thresholds.clone(), + per_domain_thresholds: state.per_domain_thresholds.clone(), } } } -impl IntoInterfaceType for &ProtocolContractState { +impl IntoInterfaceType + for ( + &ProtocolContractState, + dtos::GovernanceThresholdParametersVotes, + ) +{ fn into_dto_type(self) -> dtos::ProtocolContractState { - match self { + let (state, parameters_votes) = self; + match state { ProtocolContractState::NotInitialized => dtos::ProtocolContractState::NotInitialized, ProtocolContractState::Initializing(state) => { dtos::ProtocolContractState::Initializing(state.into_dto_type()) } ProtocolContractState::Running(state) => { - dtos::ProtocolContractState::Running(state.into_dto_type()) + dtos::ProtocolContractState::Running((state, parameters_votes).into_dto_type()) } ProtocolContractState::Resharing(state) => { - dtos::ProtocolContractState::Resharing(state.into_dto_type()) + dtos::ProtocolContractState::Resharing((state, parameters_votes).into_dto_type()) } } } diff --git a/crates/contract/src/primitives/threshold_votes.rs b/crates/contract/src/primitives/threshold_votes.rs index 2714e80c70..5d74018094 100644 --- a/crates/contract/src/primitives/threshold_votes.rs +++ b/crates/contract/src/primitives/threshold_votes.rs @@ -1,9 +1,10 @@ -use crate::primitives::proposal_hash::{Borsh, Sha256, ToProposalHash}; +use crate::primitives::proposal_hash::{Borsh, ProposalHash, Sha256, ToProposalHash}; use crate::primitives::thresholds::ProposedGovernanceThresholdParameters; use crate::primitives::votes::Votes; use crate::primitives::{key_state::AuthenticatedAccountId, participants::Participants}; use crate::storage_keys::StorageKey; use near_sdk::near; +use std::collections::{BTreeMap, BTreeSet}; impl ToProposalHash for ProposedGovernanceThresholdParameters { type Serializer = Borsh; @@ -64,6 +65,11 @@ impl GovernanceThresholdParametersVotes { self.0.clear(); } + /// Pending votes keyed by proposal hash. + pub fn all(&self) -> BTreeMap> { + self.0.all() + } + #[cfg(test)] pub fn is_empty(&self) -> bool { self.0.all().is_empty() diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 2abe8e758e..9f4bf7b300 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -7,6 +7,7 @@ use crate::types::PublicKeyExtended; use crate::types::participants::Participants; use crate::types::primitives::AccountId; use borsh::{BorshDeserialize, BorshSerialize}; +use mpc_primitives::hash::ProposalHash; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; @@ -165,18 +166,28 @@ pub struct ProposedGovernanceThresholdParameters { // Voting Types // ============================================================================= -/// Votes for threshold parameter changes. Always empty: the contract stores only proposal -/// hashes and no longer reports pending votes. Kept for wire compatibility. -// TODO(#2825): report the hash-keyed tally instead, like `MeasurementVotes`. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +/// Voters grouped by the [`ProposalHash`] of the [`ProposedGovernanceThresholdParameters`] +/// they voted for. +#[derive( + Clone, + Debug, + Default, + PartialEq, + Eq, + Serialize, + Deserialize, + BorshSerialize, + BorshDeserialize, + derive_more::Deref, +)] +#[serde(transparent)] #[cfg_attr( all(feature = "abi", not(target_arch = "wasm32")), derive(schemars::JsonSchema) )] -pub struct GovernanceThresholdParametersVotes { - pub proposal_by_account: - BTreeMap, -} +pub struct GovernanceThresholdParametersVotes( + pub BTreeMap>, +); /// Votes for adding new domains. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] From 4adcd904cd4f11fa1060867b5c7abf9d3d86af47 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 21 Oct 2026 01:34:51 +0200 Subject: [PATCH 02/20] test(contract): update the ABI snapshot for the parameter-votes tally --- .../snapshots/abi__abi_has_not_changed.snap | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index 1e073ac842..cb68afcb05 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -3764,21 +3764,6 @@ expression: abi } } }, - "GovernanceThresholdParametersVotes": { - "description": "Votes for threshold parameter changes. Always empty: the contract stores only proposal hashes and no longer reports pending votes. Kept for wire compatibility.", - "type": "object", - "required": [ - "proposal_by_account" - ], - "properties": { - "proposal_by_account": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ProposedGovernanceThresholdParameters" - } - } - } - }, "Hash256": { "type": "string", "pattern": "^(?:[0-9A-Fa-f]{2})*$" @@ -4828,7 +4813,14 @@ expression: abi "$ref": "#/definitions/GovernanceThresholdParameters" }, "parameters_votes": { - "$ref": "#/definitions/GovernanceThresholdParametersVotes" + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + } }, "previously_cancelled_resharing_epoch_id": { "anyOf": [ From 69286e4e8bc2728fd3283dae6bc0c5d9c51498f1 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 21 Oct 2026 02:24:03 +0200 Subject: [PATCH 03/20] fix(contract-interface): accept the legacy parameter-votes report when deserializing --- crates/contract/src/dto_mapping.rs | 24 +++++++ .../src/types/state.rs | 64 ++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index 88ff2feeeb..9861ceab97 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -1170,4 +1170,28 @@ mod tests { )) ); } + + #[test] + fn parameters_votes_dto__should_turn_a_legacy_report_into_the_contract_hashes() { + use crate::primitives::proposal_hash::ToProposalHash; + use crate::primitives::test_utils::gen_proposed_threshold_params; + use std::collections::{BTreeMap, BTreeSet}; + + // Given: the per-voter report of a contract that still stores full proposals + let proposal = gen_proposed_threshold_params(5); + let legacy = serde_json::json!({ + "proposal_by_account": { "alice.near": (&proposal).into_dto_type() } + }); + + // When + let votes: dtos::GovernanceThresholdParametersVotes = + serde_json::from_value(legacy).unwrap(); + + // Then: keyed by the hash the contract computes for the same proposal + let voter = dtos::AuthenticatedAccountId("alice.near".parse().unwrap()); + assert_eq!( + votes.0, + BTreeMap::from([(proposal.to_proposal_hash(), BTreeSet::from([voter]))]) + ); + } } diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 9f4bf7b300..713b86ac83 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -9,6 +9,7 @@ use crate::types::primitives::AccountId; use borsh::{BorshDeserialize, BorshSerialize}; use mpc_primitives::hash::ProposalHash; use serde::{Deserialize, Serialize}; +use sha2::Digest; use std::collections::{BTreeMap, BTreeSet}; use super::primitives::DomainId; @@ -175,7 +176,6 @@ pub struct ProposedGovernanceThresholdParameters { PartialEq, Eq, Serialize, - Deserialize, BorshSerialize, BorshDeserialize, derive_more::Deref, @@ -189,6 +189,42 @@ pub struct GovernanceThresholdParametersVotes( pub BTreeMap>, ); +/// Also accepts the pre-tally report (`{"proposal_by_account": {...}}`) of contracts that +/// still store full proposals, so a newer reader can follow an older contract across an upgrade. +impl<'de> Deserialize<'de> for GovernanceThresholdParametersVotes { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + #[serde(untagged)] + enum Repr { + Tally(BTreeMap>), + Legacy { + proposal_by_account: + BTreeMap, + }, + } + Ok(Self(match Repr::deserialize(deserializer)? { + Repr::Tally(tally) => tally, + Repr::Legacy { + proposal_by_account, + } => tally_by_proposal_hash(proposal_by_account), + })) + } +} + +/// Groups per-voter proposals by the hash the contract stores for them: SHA-256 of the +/// Borsh encoding, which the DTOs share with the contract types. +pub(crate) fn tally_by_proposal_hash( + proposal_by_voter: BTreeMap, +) -> BTreeMap> { + let mut tally: BTreeMap> = BTreeMap::new(); + for (voter, proposal) in proposal_by_voter { + let bytes = borsh::to_vec(&proposal).expect("borsh serialization must succeed"); + let hash = ProposalHash::new(sha2::Sha256::digest(bytes).into()); + tally.entry(hash).or_default().insert(voter); + } + tally +} + /// Votes for adding new domains. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] #[cfg_attr( @@ -512,4 +548,30 @@ mod tests { // Then assert_eq!(parsed.per_domain_thresholds.len(), 0); } + + #[test] + fn parameters_votes_deserialize_the_legacy_empty_report() { + let votes: super::GovernanceThresholdParametersVotes = + serde_json::from_str(r#"{"proposal_by_account":{}}"#).unwrap(); + + assert_eq!(votes, super::GovernanceThresholdParametersVotes::default()); + } + + #[test] + fn parameters_votes_roundtrip_the_tally() { + let votes = + super::GovernanceThresholdParametersVotes(std::collections::BTreeMap::from([( + mpc_primitives::hash::ProposalHash::new([7u8; 32]), + std::collections::BTreeSet::from([super::AuthenticatedAccountId( + "alice.near".parse().unwrap(), + )]), + )])); + + let json = serde_json::to_string(&votes).unwrap(); + + assert_eq!( + serde_json::from_str::(&json).unwrap(), + votes + ); + } } From 0c780d9504e5a535c3d98374941853639bfd086c Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Thu, 22 Oct 2026 13:02:13 +0200 Subject: [PATCH 04/20] test(contract): use the Environment helper in the re-proposal state() test --- crates/contract/src/api/governance.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/contract/src/api/governance.rs b/crates/contract/src/api/governance.rs index 20f9f4dab8..eb060412f2 100644 --- a/crates/contract/src/api/governance.rs +++ b/crates/contract/src/api/governance.rs @@ -614,12 +614,7 @@ mod tests { // Given let (mut contract, participants, _, proposal) = resharing_contract_with_domain(); let (voter, _, _) = &participants.participants()[0]; - testing_env!( - VMContextBuilder::new() - .signer_account_id(voter.clone()) - .predecessor_account_id(voter.clone()) - .build() - ); + Environment::new(Some(0), Some(voter.clone()), None); // When contract From 14ec28688bb75bf7cdd66e93030bd36b1406d136 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Fri, 23 Oct 2026 12:46:48 +0200 Subject: [PATCH 05/20] docs(contract-interface): track removal of the legacy parameter-votes arm --- crates/near-mpc-contract-interface/src/types/state.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 713b86ac83..93d30f96ba 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -197,6 +197,7 @@ impl<'de> Deserialize<'de> for GovernanceThresholdParametersVotes { #[serde(untagged)] enum Repr { Tally(BTreeMap>), + // TODO(#2825): drop once no deployed contract reports the pre-tally voter-keyed shape. Legacy { proposal_by_account: BTreeMap, From 90e714877e255818d85abdf048335c87435427c1 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Fri, 23 Oct 2026 13:26:10 +0200 Subject: [PATCH 06/20] Copilot Nits --- .../src/primitives/threshold_votes.rs | 1 - .../abi__abi_has_not_changed.snap.new | 5547 +++++++++++++++++ .../src/types/state.rs | 18 + 3 files changed, 5565 insertions(+), 1 deletion(-) create mode 100644 crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new diff --git a/crates/contract/src/primitives/threshold_votes.rs b/crates/contract/src/primitives/threshold_votes.rs index 8b78766f55..ac9b80b981 100644 --- a/crates/contract/src/primitives/threshold_votes.rs +++ b/crates/contract/src/primitives/threshold_votes.rs @@ -63,7 +63,6 @@ impl GovernanceThresholdParametersVotes { self.0.clear(); } - /// Pending votes keyed by proposal hash. pub fn all(&self) -> BTreeMap> { self.0.all() } diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new new file mode 100644 index 0000000000..63747990b9 --- /dev/null +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new @@ -0,0 +1,5547 @@ +--- +source: crates/contract/tests/abi.rs +assertion_line: 47 +expression: abi +--- +{ + "schema_version": "0.4.0", + "metadata": { + "name": "mpc-contract", + "version": "3.17.0", + "build": { + "compiler": "[RUSTC_VERSION]", + "builder": "[CARGO_NEAR_BUILD_VERSION]" + }, + "wasm_hash": "[WASM_HASH]" + }, + "body": { + "functions": [ + { + "name": "allowed_docker_image_hashes", + "doc": " Returns all allowed code hashes in descending order of their expiry\n date. Note that the expiration depends on the contract configuration\n (c.f. [`dtos::Config::tee_upgrade_deadline_duration_seconds`]).", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/AllowedMpcDockerImageHash" + } + } + } + }, + { + "name": "allowed_foreign_chain_providers", + "doc": " On-chain RPC provider whitelist keyed by [`ForeignChain`](dtos::ForeignChain). Nodes read this at\n startup to validate their local `foreign_chains.yaml`.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ChainEntry" + } + } + } + }, + { + "name": "allowed_launcher_compose_hashes", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LauncherDockerComposeHash" + } + } + } + }, + { + "name": "allowed_launcher_image_hashes", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LauncherImageHash" + } + } + } + }, + { + "name": "allowed_os_measurements", + "doc": " Returns all currently allowed OS measurements.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ExpectedMeasurements" + } + } + } + }, + { + "name": "available_attestation_grants", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "account_id", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + { + "name": "cancel_node_migration", + "doc": " Cancels a previously started node migration for the calling account.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", + "kind": "call", + "modifiers": [ + "payable" + ], + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "clean_foreign_chain_data", + "doc": " Private endpoint to clean up foreign chain policy votes and node configurations\n for non-participants after resharing.", + "kind": "call", + "modifiers": [ + "private" + ], + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "clean_invalid_attestations", + "doc": " Prunes up to `max_scan` stored attestations that fail re-verification (expired or\n referencing stale whitelists), returning one attestation-storage grant to the owner of\n each entry removed. Returns the number of entries removed. Callable by anyone while the\n protocol is in [`Running`](ProtocolContractState::Running).", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "max_scan", + "type_schema": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + { + "name": "clean_tee_status", + "doc": " Private endpoint to drop votes cast by non-participants after resharing.\n Attestation cleanup is handled separately by [`MpcContract::clean_invalid_attestations`].", + "kind": "call", + "modifiers": [ + "private" + ], + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "cleanup_orphaned_node_migrations", + "kind": "call", + "modifiers": [ + "private" + ], + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "conclude_node_migration", + "doc": " Finalizes a node migration for the calling account.\n\n This method can only be called while the protocol is in a [`Running`](ProtocolContractState::Running) state\n and by an existing participant. On success, the participant’s information is\n updated to the new destination node.\n\n # Errors\n Returns the following errors:\n - [`InvalidState::ProtocolStateNotRunning`]: if protocol is not in [`Running`](ProtocolContractState::Running) state\n - [`InvalidState::NotParticipant`]: if caller is not a current participant\n - [`ConversionError::DataConversion`](crate::errors::ConversionError::DataConversion): if the provided keyset contains a malformed public key\n - [`NodeMigrationError::KeysetMismatch`](crate::errors::NodeMigrationError::KeysetMismatch): if provided keyset does not match the expected keyset\n - [`NodeMigrationError::MigrationNotFound`](crate::errors::NodeMigrationError::MigrationNotFound): if no migration record exists for the caller\n - [`NodeMigrationError::AccountPublicKeyMismatch`](crate::errors::NodeMigrationError::AccountPublicKeyMismatch): if caller’s public key does not match the expected destination node\n - [`InvalidParameters::InvalidTeeRemoteAttestation`]: if destination node’s TEE quote is invalid\n - [`NodeMigrationError::TlsKeyAlreadyClaimed`](crate::errors::NodeMigrationError::TlsKeyAlreadyClaimed): if the destination node's TLS\n public key belongs to another account\n - [`NodeMigrationError::DestinationTlsKeyUnchanged`](crate::errors::NodeMigrationError::DestinationTlsKeyUnchanged): if the destination node reuses the\n caller's current TLS public key", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "keyset", + "type_schema": { + "$ref": "#/definitions/Keyset" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "config", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/Config" + } + } + }, + { + "name": "contract_source_metadata", + "kind": "view" + }, + { + "name": "contract_update_votes", + "doc": " Returns all currently stored votes.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + }, + "uniqueItems": true + } + } + } + }, + { + "name": "derived_public_key", + "doc": " This is the derived public key of the caller given path and predecessor\n if predecessor is not provided, it will be the caller of the contract.\n\n The domain parameter specifies which domain we're deriving the public key for;\n the default is the first domain.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "path", + "type_schema": { + "type": "string" + } + }, + { + "name": "predecessor", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": [ + "string", + "null" + ] + } + }, + { + "name": "domain_id", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/DomainId" + }, + { + "type": "null" + } + ] + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PublicKey" + } + } + }, + { + "name": "fail_attestation_submission", + "kind": "view", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "reason", + "type_schema": { + "type": "string" + } + } + ] + } + }, + { + "name": "fail_on_timeout", + "kind": "view", + "modifiers": [ + "private" + ] + }, + { + "name": "get_attestation", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "tls_public_key", + "type_schema": { + "$ref": "#/definitions/Ed25519PublicKey" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/StoredAttestation" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_available_foreign_chains", + "doc": " The **available** foreign chains: whitelisted chains that are supported\n by at least the signing threshold of active participants.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/AvailableForeignChains" + } + } + }, + { + "name": "get_foreign_chains_configs", + "doc": " Per-participant view of which foreign chains each node currently covers. Feeds the\n available-set computation ([`Self::get_available_foreign_chains`]) and coverage alerting.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/ForeignChainsConfigs" + } + } + }, + { + "name": "get_pending_ckd_request", + "doc": " Presence check for a pending CKD request, exposed as a view call.\n\n See [`Self::get_pending_request`] for the contract: the returned [`dtos::YieldIndex`]\n is an arbitrary representative of a fan-out queue, not \"the\" yield. Only the\n `Some`/`None` distinction is meaningful.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequest" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/YieldIndex" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_pending_request", + "doc": " Presence check for a pending signature request, exposed as a view call.\n\n **The returned [`dtos::YieldIndex`] is an arbitrary representative, not \"the\" yield\n for this request.** Since the duplicate-request fan-out feature (PR #3187),\n a single request key can have N queued yields; this method returns the head of the\n queue. Callers that need to act on the full set are wrong to use this. The\n only correct interpretation is presence: `Some(_)` vs `None`.\n\n The `Option` shape is retained for JSON wire compatibility with\n out-of-tree consumers; the in-tree caller (`tx_sender::observe_tx_result`)\n only matches on presence. Prefer a `bool`-shaped accessor if one is added.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignatureRequest" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/YieldIndex" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_pending_verify_foreign_tx_request", + "doc": " Presence check for a pending foreign-tx verification request, exposed as a\n view call.\n\n See [`Self::get_pending_request`] for the contract: the returned [`dtos::YieldIndex`]\n is an arbitrary representative of a fan-out queue, not \"the\" yield. Only the\n `Some`/`None` distinction is meaningful.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequest" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/YieldIndex" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_tee_accounts", + "doc": " Returns all accounts that have TEE attestations stored in the contract.\n Note: This includes both current protocol participants and accounts that may have\n submitted TEE information but are not currently part of the active participant set.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/NodeId" + } + } + } + }, + { + "name": "init", + "kind": "call", + "modifiers": [ + "init" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "parameters", + "type_schema": { + "$ref": "#/definitions/GovernanceThresholdParameters" + } + }, + { + "name": "tee_verifier_account_id", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + } + }, + { + "name": "init_config", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/InitConfig" + }, + { + "type": "null" + } + ] + } + } + ] + } + }, + { + "name": "init_running", + "kind": "call", + "modifiers": [ + "init", + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "domains", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig" + } + } + }, + { + "name": "next_domain_id", + "type_schema": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + { + "name": "keyset", + "type_schema": { + "$ref": "#/definitions/Keyset" + } + }, + { + "name": "parameters", + "type_schema": { + "$ref": "#/definitions/GovernanceThresholdParameters" + } + }, + { + "name": "tee_verifier_account_id", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + } + }, + { + "name": "init_config", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/InitConfig" + }, + { + "type": "null" + } + ] + } + } + ] + } + }, + { + "name": "latest_key_version", + "doc": " Key versions refer new versions of the root key that we may choose to generate on cohort\n changes. Older key versions will always work but newer key versions were never held by\n older signers. Newer key versions may also add new security features, like only existing\n within a secure enclave. The signature_scheme parameter specifies which protocol\n we're querying the latest version for. The default is Secp256k1. The default is **NOT**\n to query across all protocols.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "signature_scheme", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/Curve" + }, + { + "type": "null" + } + ] + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + { + "name": "launcher_hash_votes", + "doc": " Returns pending launcher hash votes, may include former participants' votes", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + } + } + } + }, + { + "name": "migrate", + "doc": " This will be called internally by the contract to migrate the state when a new contract\n is deployed. This function should be changed every time state is changed to do the proper\n migrate flow.\n\n If nothing is changed, then this function will just return the current state. If it fails\n to read the state, then it will return an error.", + "kind": "call", + "modifiers": [ + "init", + "private" + ] + }, + { + "name": "migration_info", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/MigrationInfo" + } + } + }, + { + "name": "mpc_node_manifest_digest_votes", + "doc": " Returns pending MPC node manifest digest votes, may include former participants' votes", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + } + } + } + }, + { + "name": "os_measurement_votes", + "doc": " Returns pending OS measurement votes, may include former participants' votes", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + } + } + } + }, + { + "name": "prepay_attestation_storage", + "doc": " Buys `grants` attestation-storage grants for `account_id`.\n\n Permissionless, which is what lets an operator fund a node whose function-call key\n cannot attach a deposit. Requires exactly the fee times `grants`; no refunds, no\n withdrawal.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "account_id", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + } + }, + { + "name": "grants", + "type_schema": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "public_key", + "doc": " This is the root public key combined from all the public keys of the participants.\n The domain parameter specifies which domain we're querying the public key for;\n the default is the first domain.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "domain_id", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/DomainId" + }, + { + "type": "null" + } + ] + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PublicKey" + } + } + }, + { + "name": "register_backup_service", + "doc": " Registers or updates the backup service information for the caller account.\n\n The caller (`signer_account_id`) must be an existing or prospective participant.\n Otherwise, the transaction will fail.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "backup_service_info", + "type_schema": { + "$ref": "#/definitions/BackupServiceInfo" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "register_foreign_chains_config", + "doc": " (Re)registers the foreign chains this node currently covers.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "foreign_chains_config", + "type_schema": { + "$ref": "#/definitions/ForeignChainsConfig" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "remove_contract_update_vote", + "doc": " Withdraws the caller's update vote.", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "remove_non_participant_contract_update_votes", + "doc": " Removes update votes from non-participants.\n Can only be called by participants or by the contract itself.", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "remove_non_participant_tee_verifier_votes", + "doc": " Private endpoint to drop verifier-change votes cast by non-participants\n after resharing.", + "kind": "call", + "modifiers": [ + "private" + ], + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "request_app_private_key", + "doc": " The derived key is fully determined by the calling account id (taken\n implicitly from the predecessor), the derivation path and the domain —\n no other account can obtain the same key. `app_public_key` does not\n influence the derived key: it is a caller-chosen ephemeral key the\n response is encrypted to; see [`dtos::CKDResponse`] for the encryption\n layout and how to decrypt.\n\n To avoid overloading the network with too many requests,\n we ask for a small deposit for each ckd request.\n\n Note: identity points are accepted in\n [`AppPublicKeyPV`](near_mpc_contract_interface::types::CKDAppPublicKey::AppPublicKeyPV)\n to support use cases\n where the derived key is intentionally public (no encryption).", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequestArgs" + } + } + ] + } + }, + { + "name": "resolve_verification", + "doc": " Verify-quote callback: on a verifier verdict it runs the post-DCAP checks and stores the\n attestation, consuming one attestation-storage grant if the entry is new. On any failure\n it fails the submitter's transaction.", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "borsh", + "args": [ + { + "name": "context", + "type_schema": { + "declaration": "VerificationContext", + "definitions": { + "()": { + "Primitive": 0 + }, + "AccountId": { + "Struct": [ + "String" + ] + }, + "Ed25519PublicKey": { + "Struct": [ + "[u8; 32]" + ] + }, + "EventLog": { + "Struct": [ + [ + "imr", + "u32" + ], + [ + "event_type", + "u32" + ], + [ + "digest", + "HexBytes<48>" + ], + [ + "event", + "String" + ], + [ + "event_payload", + "String" + ] + ] + }, + "HexBytes<32>": { + "Struct": [ + "[u8; 32]" + ] + }, + "HexBytes<48>": { + "Struct": [ + "[u8; 48]" + ] + }, + "NodeId": { + "Struct": [ + [ + "account_id", + "AccountId" + ], + [ + "tls_public_key", + "Ed25519PublicKey" + ], + [ + "account_public_key", + "Ed25519PublicKey" + ] + ] + }, + "Option>": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "None", + "()" + ], + [ + 1, + "Some", + "HexBytes<32>" + ] + ] + } + }, + "String": { + "Sequence": { + "length_width": 4, + "length_range": { + "start": 0, + "end": 4294967295 + }, + "elements": "u8" + } + }, + "TcbInfo": { + "Struct": [ + [ + "mrtd", + "HexBytes<48>" + ], + [ + "rtmr0", + "HexBytes<48>" + ], + [ + "rtmr1", + "HexBytes<48>" + ], + [ + "rtmr2", + "HexBytes<48>" + ], + [ + "rtmr3", + "HexBytes<48>" + ], + [ + "os_image_hash", + "Option>" + ], + [ + "compose_hash", + "HexBytes<32>" + ], + [ + "device_id", + "HexBytes<32>" + ], + [ + "app_compose", + "String" + ], + [ + "event_log", + "Vec" + ] + ] + }, + "Vec": { + "Sequence": { + "length_width": 4, + "length_range": { + "start": 0, + "end": 4294967295 + }, + "elements": "EventLog" + } + }, + "VerificationContext": { + "Struct": [ + [ + "node_id", + "NodeId" + ], + [ + "tcb_info", + "TcbInfo" + ] + ] + }, + "[u8; 32]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 32, + "end": 32 + }, + "elements": "u8" + } + }, + "[u8; 48]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 48, + "end": 48 + }, + "elements": "u8" + } + }, + "u32": { + "Primitive": 4 + }, + "u8": { + "Primitive": 1 + } + } + } + } + ] + }, + "callbacks": [ + { + "serialization_type": "borsh", + "type_schema": { + "declaration": "VerificationResult", + "definitions": { + "EnclaveReport": { + "Struct": [ + [ + "cpu_svn", + "[u8; 16]" + ], + [ + "misc_select", + "u32" + ], + [ + "reserved1", + "[u8; 28]" + ], + [ + "attributes", + "[u8; 16]" + ], + [ + "mr_enclave", + "[u8; 32]" + ], + [ + "reserved2", + "[u8; 32]" + ], + [ + "mr_signer", + "[u8; 32]" + ], + [ + "reserved3", + "[u8; 96]" + ], + [ + "isv_prod_id", + "u16" + ], + [ + "isv_svn", + "u16" + ], + [ + "reserved4", + "[u8; 60]" + ], + [ + "report_data", + "[u8; 64]" + ] + ] + }, + "Report": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "SgxEnclave", + "Report__SgxEnclave" + ], + [ + 1, + "TD10", + "Report__TD10" + ], + [ + 2, + "TD15", + "Report__TD15" + ], + [ + 3, + "TD15Ex", + "Report__TD15Ex" + ] + ] + } + }, + "Report__SgxEnclave": { + "Struct": [ + "EnclaveReport" + ] + }, + "Report__TD10": { + "Struct": [ + "TDReport10" + ] + }, + "Report__TD15": { + "Struct": [ + "TDReport15" + ] + }, + "Report__TD15Ex": { + "Struct": [ + "TDReport15Ex" + ] + }, + "String": { + "Sequence": { + "length_width": 4, + "length_range": { + "start": 0, + "end": 4294967295 + }, + "elements": "u8" + } + }, + "TDReport10": { + "Struct": [ + [ + "tee_tcb_svn", + "[u8; 16]" + ], + [ + "mr_seam", + "[u8; 48]" + ], + [ + "mr_signer_seam", + "[u8; 48]" + ], + [ + "seam_attributes", + "[u8; 8]" + ], + [ + "td_attributes", + "[u8; 8]" + ], + [ + "xfam", + "[u8; 8]" + ], + [ + "mr_td", + "[u8; 48]" + ], + [ + "mr_config_id", + "[u8; 48]" + ], + [ + "mr_owner", + "[u8; 48]" + ], + [ + "mr_owner_config", + "[u8; 48]" + ], + [ + "rt_mr0", + "[u8; 48]" + ], + [ + "rt_mr1", + "[u8; 48]" + ], + [ + "rt_mr2", + "[u8; 48]" + ], + [ + "rt_mr3", + "[u8; 48]" + ], + [ + "report_data", + "[u8; 64]" + ] + ] + }, + "TDReport15": { + "Struct": [ + [ + "base", + "TDReport10" + ], + [ + "tee_tcb_svn2", + "[u8; 16]" + ], + [ + "mr_service_td", + "[u8; 48]" + ] + ] + }, + "TDReport15Ex": { + "Struct": [ + [ + "base", + "TDReport15" + ], + [ + "vmid", + "u8" + ], + [ + "td_id", + "[u8; 32]" + ], + [ + "dev_info", + "[u8; 48]" + ], + [ + "init_service_td_hash", + "[u8; 48]" + ], + [ + "init_service_td_attributes", + "[u8; 8]" + ], + [ + "init_cpu_svn", + "[u8; 16]" + ], + [ + "init_tee_tcb_svn", + "[u8; 16]" + ], + [ + "init_tee_fmspc", + "[u8; 12]" + ], + [ + "cur_service_td_hash", + "[u8; 48]" + ], + [ + "cur_service_td_attributes", + "[u8; 8]" + ] + ] + }, + "TcbStatus": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "UpToDate", + "TcbStatus__UpToDate" + ], + [ + 1, + "OutOfDateConfigurationNeeded", + "TcbStatus__OutOfDateConfigurationNeeded" + ], + [ + 2, + "OutOfDate", + "TcbStatus__OutOfDate" + ], + [ + 3, + "ConfigurationAndSWHardeningNeeded", + "TcbStatus__ConfigurationAndSWHardeningNeeded" + ], + [ + 4, + "ConfigurationNeeded", + "TcbStatus__ConfigurationNeeded" + ], + [ + 5, + "SWHardeningNeeded", + "TcbStatus__SWHardeningNeeded" + ], + [ + 6, + "Revoked", + "TcbStatus__Revoked" + ], + [ + 7, + "TDRelaunchAdvised", + "TcbStatus__TDRelaunchAdvised" + ], + [ + 8, + "TDRelaunchAdvisedConfigurationNeeded", + "TcbStatus__TDRelaunchAdvisedConfigurationNeeded" + ] + ] + } + }, + "TcbStatusWithAdvisory": { + "Struct": [ + [ + "status", + "TcbStatus" + ], + [ + "advisory_ids", + "Vec" + ] + ] + }, + "TcbStatus__ConfigurationAndSWHardeningNeeded": { + "Struct": null + }, + "TcbStatus__ConfigurationNeeded": { + "Struct": null + }, + "TcbStatus__OutOfDate": { + "Struct": null + }, + "TcbStatus__OutOfDateConfigurationNeeded": { + "Struct": null + }, + "TcbStatus__Revoked": { + "Struct": null + }, + "TcbStatus__SWHardeningNeeded": { + "Struct": null + }, + "TcbStatus__TDRelaunchAdvised": { + "Struct": null + }, + "TcbStatus__TDRelaunchAdvisedConfigurationNeeded": { + "Struct": null + }, + "TcbStatus__UpToDate": { + "Struct": null + }, + "Vec": { + "Sequence": { + "length_width": 4, + "length_range": { + "start": 0, + "end": 4294967295 + }, + "elements": "String" + } + }, + "Vec": { + "Sequence": { + "length_width": 4, + "length_range": { + "start": 0, + "end": 4294967295 + }, + "elements": "u8" + } + }, + "VerificationResult": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "Verified", + "VerificationResult__Verified" + ], + [ + 1, + "Rejected", + "VerificationResult__Rejected" + ] + ] + } + }, + "VerificationResult__Rejected": { + "Struct": [ + "VerifierError" + ] + }, + "VerificationResult__Verified": { + "Struct": [ + "VerifiedReport" + ] + }, + "VerifiedReport": { + "Struct": [ + [ + "status", + "String" + ], + [ + "advisory_ids", + "Vec" + ], + [ + "report", + "Report" + ], + [ + "ppid", + "Vec" + ], + [ + "qe_status", + "TcbStatusWithAdvisory" + ], + [ + "platform_status", + "TcbStatusWithAdvisory" + ] + ] + }, + "VerifierError": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "DcapVerification", + "VerifierError__DcapVerification" + ] + ] + } + }, + "VerifierError__DcapVerification": { + "Struct": [ + "String" + ] + }, + "[u8; 12]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 12, + "end": 12 + }, + "elements": "u8" + } + }, + "[u8; 16]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 16, + "end": 16 + }, + "elements": "u8" + } + }, + "[u8; 28]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 28, + "end": 28 + }, + "elements": "u8" + } + }, + "[u8; 32]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 32, + "end": 32 + }, + "elements": "u8" + } + }, + "[u8; 48]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 48, + "end": 48 + }, + "elements": "u8" + } + }, + "[u8; 60]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 60, + "end": 60 + }, + "elements": "u8" + } + }, + "[u8; 64]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 64, + "end": 64 + }, + "elements": "u8" + } + }, + "[u8; 8]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 8, + "end": 8 + }, + "elements": "u8" + } + }, + "[u8; 96]": { + "Sequence": { + "length_width": 0, + "length_range": { + "start": 96, + "end": 96 + }, + "elements": "u8" + } + }, + "u16": { + "Primitive": 2 + }, + "u32": { + "Primitive": 4 + }, + "u8": { + "Primitive": 1 + } + } + } + } + ], + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueNull" + } + } + }, + { + "name": "respond", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignatureRequest" + } + }, + { + "name": "response", + "type_schema": { + "$ref": "#/definitions/SignatureResponse" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "respond_ckd", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequest" + } + }, + { + "name": "response", + "type_schema": { + "$ref": "#/definitions/CKDResponse" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "respond_verify_foreign_tx", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequest" + } + }, + { + "name": "response", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionResponse" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "return_ck_and_clean_state_on_success", + "doc": " Yield-resume callback for a single queued CKD request.\n\n On success, returns the confidential key to the original caller. On timeout,\n pops this yield's slot (the head of the FIFO fan-out queue) from the\n pending-request map and fires `fail_on_timeout` to fail the original\n transaction. Sibling yields queued under the same request key remain pending\n and are cleaned up by their own timeouts (or drained together by a subsequent\n `respond_ckd`).", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequest" + } + } + ] + }, + "callbacks": [ + { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/CKDResponse" + } + } + ], + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueCKDResponse" + } + } + }, + { + "name": "return_signature_and_clean_state_on_success", + "doc": " Yield-resume callback for a single queued `sign` request.\n\n On success, returns the signature to the original caller. On timeout, pops this\n yield's slot (the head of the FIFO fan-out queue) from the pending-request map\n and fires `fail_on_timeout` to fail the original transaction. Sibling yields\n queued under the same request key remain pending and are cleaned up by their\n own timeouts (or drained together by a subsequent `respond`).", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignatureRequest" + } + } + ] + }, + "callbacks": [ + { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/SignatureResponse" + } + } + ], + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueSignatureResponse" + } + } + }, + { + "name": "return_verify_foreign_tx_and_clean_state_on_success", + "doc": " Yield-resume callback for a single queued foreign-tx verification request.\n\n On success, returns the verification response to the original caller. On\n timeout, pops this yield's slot (the head of the FIFO fan-out queue) from the\n pending-request map and fires `fail_on_timeout` to fail the original\n transaction. Sibling yields queued under the same request key remain pending\n and are cleaned up by their own timeouts (or drained together by a subsequent\n `respond_verify_foreign_tx`).", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequest" + } + } + ] + }, + "callbacks": [ + { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionResponse" + } + } + ], + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueVerifyForeignTransactionResponse" + } + } + }, + { + "name": "sign", + "doc": " `key_version` must be less than or equal to the value at `latest_key_version`\n To avoid overloading the network with too many requests,\n we ask for a small deposit for each signature request.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignRequestArgs" + } + } + ] + } + }, + { + "name": "start_keygen_instance", + "doc": " Starts a new attempt to generate a key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "start_node_migration", + "doc": " Sets the destination node for the calling account.\n\n This function can only be called while the protocol is in a [`Running`](ProtocolContractState::Running) state.\n The signer must be a current participant of the current epoch, otherwise an error is returned.\n On success, the provided [`DestinationNodeInfo`](dtos::DestinationNodeInfo) is stored in the contract state\n under the signer’s account ID.\n\n # Errors\n - [`InvalidState::ProtocolStateNotRunning`] if the protocol is not in the [`Running`](ProtocolContractState::Running) state.\n - [`InvalidState::NotParticipant`] if the signer is not a current participant.\n - [`NodeMigrationError::TlsKeyAlreadyClaimed`](crate::errors::NodeMigrationError::TlsKeyAlreadyClaimed) if the destination node's TLS\n public key belongs to another account.\n - [`NodeMigrationError::DestinationTlsKeyUnchanged`](crate::errors::NodeMigrationError::DestinationTlsKeyUnchanged) if the destination node reuses the\n signer's current TLS public key. Use [`Self::update_participant_url`] to change only the url.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "destination_node_info", + "type_schema": { + "$ref": "#/definitions/DestinationNodeInfo" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "start_reshare_instance", + "doc": " Starts a new attempt to reshare the key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "state", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/ProtocolContractState" + } + } + }, + { + "name": "submit_contract_update", + "doc": " Submits an update and applies it. Fails if the update doesn't yet have enough\n participant votes.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "borsh", + "args": [ + { + "name": "update", + "type_schema": { + "declaration": "Update", + "definitions": { + "Config": { + "Struct": [ + [ + "key_event_timeout_blocks", + "u64" + ], + [ + "tee_upgrade_deadline_duration_seconds", + "u64" + ], + [ + "apply_contract_update_tera_gas", + "u64" + ], + [ + "sign_call_gas_attachment_requirement_tera_gas", + "u64" + ], + [ + "ckd_call_gas_attachment_requirement_tera_gas", + "u64" + ], + [ + "return_signature_and_clean_state_on_success_call_tera_gas", + "u64" + ], + [ + "return_ck_and_clean_state_on_success_call_tera_gas", + "u64" + ], + [ + "fail_on_timeout_tera_gas", + "u64" + ], + [ + "fail_attestation_submission_tera_gas", + "u64" + ], + [ + "clean_tee_status_tera_gas", + "u64" + ], + [ + "clean_invalid_attestations_tera_gas", + "u64" + ], + [ + "cleanup_orphaned_node_migrations_tera_gas", + "u64" + ], + [ + "remove_non_participant_update_votes_tera_gas", + "u64" + ], + [ + "clean_foreign_chain_data_tera_gas", + "u64" + ], + [ + "remove_non_participant_tee_verifier_votes_tera_gas", + "u64" + ], + [ + "verifier_tera_gas", + "u64" + ], + [ + "resolve_verification_tera_gas", + "u64" + ], + [ + "launcher_hash_unused_ttl_seconds", + "u64" + ], + [ + "attestation_storage_fee_millinear", + "u64" + ] + ] + }, + "Update": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "Code", + "Update__Code" + ], + [ + 1, + "Config", + "Update__Config" + ] + ] + } + }, + "Update__Code": { + "Struct": [ + "Vec" + ] + }, + "Update__Config": { + "Struct": [ + "Config" + ] + }, + "Vec": { + "Sequence": { + "length_width": 4, + "length_range": { + "start": 0, + "end": 4294967295 + }, + "elements": "u8" + } + }, + "u64": { + "Primitive": 8 + }, + "u8": { + "Primitive": 1 + } + } + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "submit_participant_info", + "doc": " Submit a TEE attestation for a current or prospective participant.\n\n - [`Attestation::Mock`] is verified synchronously.\n - [`Attestation::Dstack`] is verified asynchronously via a cross-contract\n `verify_quote` call, with [`Self::resolve_verification`] chained as its\n callback to run the post-DCAP checks and store the attestation.\n\n A node submits with no deposit via its function-call access key. Storing a *new* entry\n consumes one attestation-storage grant, prepaid for the node's account by whoever\n onboards it; a re-attestation under a key the account already owns consumes none.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "proposed_participant_attestation", + "type_schema": { + "$ref": "#/definitions/Attestation" + } + }, + { + "name": "tls_public_key", + "type_schema": { + "$ref": "#/definitions/Ed25519PublicKey" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueNull" + } + } + }, + { + "name": "tee_verifier_account_id", + "doc": " Returns the trusted TEE verifier contract account, set at init and\n changed via [`Self::vote_tee_verifier_change`].", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + } + } + }, + { + "name": "tee_verifier_votes", + "doc": " Returns the pending TEE verifier-change votes, keyed by proposal.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedParticipantId" + }, + "uniqueItems": true + } + } + } + }, + { + "name": "update_config", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "config", + "type_schema": { + "$ref": "#/definitions/Config" + } + } + ] + } + }, + { + "name": "update_participant_url", + "doc": " Updates the calling participant's registered URL, keeping the TLS key and participant ID.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "url", + "type_schema": { + "$ref": "#/definitions/BoundedString_256" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "verify_foreign_transaction", + "doc": " Submit a verification + signing request for a foreign chain transaction.\n MPC nodes will verify the transaction on the foreign chain before signing.\n The signed payload is derived from the transaction ID (hash of tx_id).", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequestArgs" + } + } + ] + } + }, + { + "name": "verify_tee", + "doc": " Verifies if all current participants have an accepted TEE state.\n Automatically enters a resharing, in case one or more participants do not have an accepted\n TEE state.\n Returns `false` and stops the contract from accepting new signature requests or responses,\n in case the participants running in an accepted TEE State are too few for the\n GovernanceThreshold or for any domain's signing protocol.\n Also retires launcher hashes that no current participant uses (see\n [`dtos::Config::launcher_hash_unused_ttl_seconds`]).", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "boolean" + } + } + }, + { + "name": "version", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "string" + } + } + }, + { + "name": "vote_abort_key_event_instance", + "doc": " Casts a vote to abort the current key event instance. If succesful, the contract aborts the\n instance and a new instance with the next attempt_id can be started.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_add_domains", + "doc": " Propose adding a new set of domains for the MPC network.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Initializing state to generate keys for the new domains.\n\n The specified list of domains must have increasing and contiguous IDs, and the first ID\n must be the same as the `next_domain_id` returned by state().", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "domains", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig" + } + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_add_launcher_hash", + "doc": " Vote to add a new launcher image hash to the allowed set. Requires threshold votes.\n When the threshold is reached, compose hashes are automatically derived for all\n currently allowed MPC image hashes.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "launcher_hash", + "type_schema": { + "$ref": "#/definitions/LauncherImageHash" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_add_os_measurement", + "doc": " Vote to add a new OS measurement set to the allowed list. Requires threshold votes.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "measurement", + "type_schema": { + "$ref": "#/definitions/ExpectedMeasurements" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_cancel_keygen", + "doc": " Casts a vote to cancel key generation. Any keys that have already been generated\n are kept and we transition into Running state; remaining domains are permanently deleted.\n Deleted domain IDs cannot be reused again in future calls to vote_add_domains.\n\n A next_domain_id that matches that in the state's domains struct must be passed in. This is\n to prevent stale requests from accidentally cancelling a future key generation state.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "next_domain_id", + "type_schema": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_cancel_resharing", + "doc": " Casts a vote to cancel the current key resharing. If a threshold number of unique\n votes are collected to cancel the resharing, the contract state will revert back to the\n previous running state.\n\n - This method is idempotent, meaning a single account can not make more than one vote.\n - Only nodes from the previous running state are allowed to vote.\n\n Return value:\n - [Ok] if the vote was successfully collected.\n - [Err] if:\n - The signer is not a participant in the previous running state.\n - The contract is not in a resharing state.", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_contract_update", + "doc": " Replaces the caller's earlier vote, if any. Returns whether `update_hash` is approved.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "update_hash", + "type_schema": { + "$ref": "#/definitions/UpdateHash" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "boolean" + } + } + }, + { + "name": "vote_mpc_node_manifest_digest", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "mpc_node_manifest_digest", + "type_schema": { + "$ref": "#/definitions/DockerImageHash" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_new_parameters", + "doc": " Propose new parameters for the MPC network: participants, governance\n threshold, and optional per-domain\n [`ReconstructionThreshold`](near_mpc_contract_interface::types::ReconstructionThreshold) updates\n (empty map keeps the current ones), applied on resharing completion.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Resharing state.\n\n The epoch_id must be equal to 1 plus the current epoch ID (if Running) or prospective epoch\n ID (if Resharing). Otherwise the vote is ignored. This is to prevent late transactions from\n accidentally voting on outdated proposals.\n\n Like the other governance voting methods, this must be called directly from the\n participant's own NEAR account: [`assert_caller_is_signer()`](MpcContract::assert_caller_is_signer) requires\n `signer_account_id == predecessor_account_id`, so calls forwarded through another\n contract are rejected.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "prospective_epoch_id", + "type_schema": { + "$ref": "#/definitions/EpochId" + } + }, + { + "name": "proposal", + "type_schema": { + "$ref": "#/definitions/ProposedGovernanceThresholdParameters" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_pk", + "doc": " Casts a vote for `public_key` for the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key generation\n attempt (including if the attempt timed out), if the signer is not a participant, or if\n the key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key generation attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - This vote is for a public key that disagrees from an earlier voted public key, causing\n the attempt to abort; another call to `start` is then necessary.\n - Everyone has now voted for the same public key; the state transitions into generating a\n key for the next domain.\n - Same as the last case, except that all domains have a generated key now, and the state\n transitions into Running with the newly generated keys.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + }, + { + "name": "public_key", + "type_schema": { + "$ref": "#/definitions/PublicKey" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_remove_launcher_hash", + "doc": " Vote to remove a launcher image hash from the allowed set. Requires ALL participants\n to vote for removal, since this invalidates attestations of nodes running that launcher.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "launcher_hash", + "type_schema": { + "$ref": "#/definitions/LauncherImageHash" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_remove_os_measurement", + "doc": " Vote to remove an OS measurement set from the allowed list. Requires ALL participants\n to vote for removal.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "measurement", + "type_schema": { + "$ref": "#/definitions/ExpectedMeasurements" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_reshared", + "doc": " Casts a vote for the successful resharing of the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key resharing attempt\n (including if the attempt timed out), if the signer is not a participant, or if the\n key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key resharing attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - Everyone has now voted; the state transitions into resharing the key for the next\n domain.\n - Same as the last case, except that all domains' keys have been reshared now, and the\n state transitions into Running with the newly reshared keys.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_tee_verifier_change", + "doc": " Vote for a candidate account to become the trusted verifier contract\n account, committing to the code hash the voter audited. When the proposal\n crosses the governance threshold, the trusted verifier account is updated\n and all pending verifier-change votes are cleared.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "candidate_account_id", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + } + }, + { + "name": "expected_code_hash", + "type_schema": { + "$ref": "#/definitions/TeeVerifierCodeHash" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_update_foreign_chain_providers", + "doc": " Vote on per-chain RPC provider whitelist state. The input is keyed by\n [`ForeignChain`](dtos::ForeignChain); each [`ChainEntry`](dtos::ChainEntry) value carries the proposed full provider list\n and the RPC response quorum for that chain. The chain's stored state is replaced\n once the protocol's signing threshold of participants has voted the same\n `(providers, quorum)` pair. [`NonEmptyBTreeMap`](near_mpc_bounded_collections::NonEmptyBTreeMap) enforces a non-empty batch and\n at-most-one entry per chain at deserialize time.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "votes", + "type_schema": { + "$ref": "#/definitions/NonEmptyBTreeMap_ForeignChain_ChainEntry" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ForeignChain" + } + } + } + }, + { + "name": "withdraw_tee_verifier_vote", + "doc": " Withdraw the caller's current vote on any pending verifier-change\n proposal. No-op if the caller has not voted.", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + } + ], + "root_schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "String", + "type": "string", + "definitions": { + "AddDomainsVotes": { + "description": "Votes for adding new domains.", + "type": "object", + "required": [ + "proposal_by_account" + ], + "properties": { + "proposal_by_account": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig" + } + } + } + } + }, + "AllowedMpcDockerImageHash": { + "type": "object", + "required": [ + "image_hash" + ], + "properties": { + "expiry_timestamp_seconds": { + "description": "block-time at which this hash is evicted from the allowlist. None if expiration date is not yet known.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "image_hash": { + "$ref": "#/definitions/DockerImageHash" + } + } + }, + "AptosExtractor": { + "oneOf": [ + { + "type": "object", + "required": [ + "Event" + ], + "properties": { + "Event": { + "type": "object", + "required": [ + "event_index" + ], + "properties": { + "event_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "AptosFinality": { + "type": "string", + "enum": [ + "Committed" + ] + }, + "AptosRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "$ref": "#/definitions/BoundedVec_AptosExtractor_Min0_Max32" + }, + "finality": { + "$ref": "#/definitions/AptosFinality" + }, + "tx_id": { + "$ref": "#/definitions/AptosTxId" + } + } + }, + "AptosTxId": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "AttemptId": { + "description": "Attempt identifier within a key event. Incremented for each attempt within the same epoch and domain.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "Attestation": { + "oneOf": [ + { + "type": "object", + "required": [ + "Dstack" + ], + "properties": { + "Dstack": { + "$ref": "#/definitions/DstackAttestation" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Mock" + ], + "properties": { + "Mock": { + "$ref": "#/definitions/MockAttestation" + } + }, + "additionalProperties": false + } + ] + }, + "AuthScheme": { + "description": "Where the operator's API key/token gets injected into the assembled RPC URL. Lives on the contract (not in operator yaml) so the operator can't pick a custom auth shape that lets them inject extra path or query components.", + "oneOf": [ + { + "description": "Token sent in an HTTP header (e.g. `Authorization: Bearer `).", + "type": "object", + "required": [ + "Header" + ], + "properties": { + "Header": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "scheme": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Token substituted into a `{placeholder}` in the URL path.", + "type": "object", + "required": [ + "Path" + ], + "properties": { + "Path": { + "type": "object", + "required": [ + "placeholder" + ], + "properties": { + "placeholder": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Token sent as a query parameter (`?=`).", + "type": "object", + "required": [ + "Query" + ], + "properties": { + "Query": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Public endpoint, no auth.", + "type": "string", + "enum": [ + "None" + ] + } + ] + }, + "AuthenticatedAccountId": { + "description": "An account ID that has been authenticated (i.e., the caller is this account).", + "type": "string" + }, + "AuthenticatedParticipantId": { + "description": "A participant ID that has been authenticated (i.e., the caller is this participant).", + "allOf": [ + { + "$ref": "#/definitions/ParticipantId" + } + ] + }, + "AvailableForeignChains": { + "description": "The set of foreign chains available across the threshold of active participants. Returned by `get_available_foreign_chains`; computed from the per-node [`ForeignChainsConfig`] reports.", + "type": "array", + "items": { + "$ref": "#/definitions/ForeignChain" + }, + "uniqueItems": true + }, + "BackupServiceInfo": { + "type": "object", + "required": [ + "public_key" + ], + "properties": { + "public_key": { + "$ref": "#/definitions/Ed25519PublicKey" + } + } + }, + "BitcoinExtractor": { + "type": "string", + "enum": [ + "BlockHash" + ] + }, + "BitcoinRpcRequest": { + "type": "object", + "required": [ + "confirmations", + "extractors", + "tx_id" + ], + "properties": { + "confirmations": { + "$ref": "#/definitions/BlockConfirmations" + }, + "extractors": { + "$ref": "#/definitions/BoundedVec_BitcoinExtractor_Min0_Max32" + }, + "tx_id": { + "$ref": "#/definitions/BitcoinTxId" + } + } + }, + "BitcoinTxId": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "BlockConfirmations": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "Bls12381G1PublicKey": { + "type": "string" + }, + "Bls12381G2PublicKey": { + "type": "string" + }, + "BoundedString_256": { + "type": "string" + }, + "BoundedVec_AptosExtractor_Min0_Max32": { + "type": "array", + "items": { + "$ref": "#/definitions/AptosExtractor" + }, + "maxItems": 32, + "minItems": 0 + }, + "BoundedVec_BitcoinExtractor_Min0_Max32": { + "type": "array", + "items": { + "$ref": "#/definitions/BitcoinExtractor" + }, + "maxItems": 32, + "minItems": 0 + }, + "BoundedVec_EvmExtractor_Min0_Max32": { + "type": "array", + "items": { + "$ref": "#/definitions/EvmExtractor" + }, + "maxItems": 32, + "minItems": 0 + }, + "BoundedVec_StarknetExtractor_Min0_Max32": { + "type": "array", + "items": { + "$ref": "#/definitions/StarknetExtractor" + }, + "maxItems": 32, + "minItems": 0 + }, + "BoundedVec_SuiExtractor_Min0_Max32": { + "type": "array", + "items": { + "$ref": "#/definitions/SuiExtractor" + }, + "maxItems": 32, + "minItems": 0 + }, + "BoundedVec_SvmExtractor_Min0_Max32": { + "type": "array", + "items": { + "$ref": "#/definitions/SvmExtractor" + }, + "maxItems": 32, + "minItems": 0 + }, + "BoundedVec_TonExtractor_Min0_Max32": { + "type": "array", + "items": { + "$ref": "#/definitions/TonExtractor" + }, + "maxItems": 32, + "minItems": 0 + }, + "CKDAppPublicKey": { + "oneOf": [ + { + "type": "object", + "required": [ + "AppPublicKey" + ], + "properties": { + "AppPublicKey": { + "$ref": "#/definitions/Bls12381G1PublicKey" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "AppPublicKeyPV" + ], + "properties": { + "AppPublicKeyPV": { + "$ref": "#/definitions/CKDAppPublicKeyPV" + } + }, + "additionalProperties": false + } + ] + }, + "CKDAppPublicKeyPV": { + "type": "object", + "required": [ + "pk1", + "pk2" + ], + "properties": { + "pk1": { + "$ref": "#/definitions/Bls12381G1PublicKey" + }, + "pk2": { + "$ref": "#/definitions/Bls12381G2PublicKey" + } + } + }, + "CKDRequest": { + "description": "A CKD request as tracked by the contract, with the app id already derived from the caller's account id and derivation path via [`derive_app_id`](crate::kdf::derive_app_id).", + "type": "object", + "required": [ + "app_id", + "app_public_key", + "domain_id" + ], + "properties": { + "app_id": { + "$ref": "#/definitions/CkdAppId" + }, + "app_public_key": { + "$ref": "#/definitions/CKDAppPublicKey" + }, + "domain_id": { + "$ref": "#/definitions/DomainId" + } + } + }, + "CKDRequestArgs": { + "type": "object", + "required": [ + "app_public_key", + "derivation_path", + "domain_id" + ], + "properties": { + "app_public_key": { + "description": "Public key used to encrypt the response. Can be chosen independently for each request and does not affect the derived key.", + "allOf": [ + { + "$ref": "#/definitions/CKDAppPublicKey" + } + ] + }, + "derivation_path": { + "description": "Identifies the derived key. The key is determined by the caller's account ID and this derivation path. Different paths produce different keys.", + "type": "string" + }, + "domain_id": { + "description": "Identifies the CKD domain used to derive the key.", + "allOf": [ + { + "$ref": "#/definitions/DomainId" + } + ] + } + } + }, + "CKDResponse": { + "description": "Response to a CKD request: the derived key, ElGamal-encrypted to the request's app public key (`pk1` in the publicly-verifiable variant).\n\nFor an app key pair `(a, A = a·G1)` and an ephemeral scalar `y` chosen by the MPC network, `big_y` holds `Y = y·G1` and `big_c` holds `C = derived_key + y·A`; decrypt with `derived_key = C - a·Y`. The derived key is a BLS signature on the app id under the domain's public key; verify it as such before use. Neither field is a public key: the field type is reused for its 48-byte compressed G1 point encoding.", + "type": "object", + "required": [ + "big_c", + "big_y" + ], + "properties": { + "big_c": { + "$ref": "#/definitions/Bls12381G1PublicKey" + }, + "big_y": { + "$ref": "#/definitions/Bls12381G1PublicKey" + } + } + }, + "ChainEntry": { + "description": "Stored state for one chain in the on-chain whitelist: a non-empty map from [`ProviderId`] to that provider's per-chain configuration, plus the voted RPC response quorum. Returned by the `allowed_foreign_chain_providers` view fn. [`NonEmptyBTreeMap`] enforces a non-empty provider set and at-most-one entry per [`ProviderId`] at deserialize time, and the map iterates in [`ProviderId`] order — so the canonical hash matches across voters without an explicit sort step.", + "type": "object", + "required": [ + "providers", + "quorum" + ], + "properties": { + "providers": { + "$ref": "#/definitions/NonEmptyBTreeMap_ProviderId_ProviderConfig" + }, + "quorum": { + "description": "Voted RPC response quorum. Stored for a deferred quorum policy and not yet consumed: nodes currently require every provider that reaches a verdict to agree on it.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "ChainRouting": { + "description": "How chain identity is encoded in the RPC URL. Exactly one of the three encodings, modelled as an enum so a vote can't accidentally produce an \"all three\" shape.", + "oneOf": [ + { + "description": "Chain identity already encoded in `base_url` (subdomain or path prefix). E.g. Alchemy's `eth-mainnet.g.alchemy.com`, Infura's `mainnet.infura.io`, or any chain-dedicated endpoint.", + "type": "string", + "enum": [ + "Embedded" + ] + }, + { + "description": "Append `segment` after `base_url`'s path. E.g. Ankr Ethereum: `\"eth\"`. `segment` MUST NOT contain `/` (validated when a vote applies).", + "type": "object", + "required": [ + "PathSegment" + ], + "properties": { + "PathSegment": { + "type": "object", + "required": [ + "segment" + ], + "properties": { + "segment": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Merge a single chain-identifying query param into the URL. E.g. dRPC Ethereum: `{ name: \"network\", value: \"ethereum\" }`. When `AuthScheme::Query { name: auth_name }` is used, `name` here MUST differ from `auth_name` (validated when a vote applies).", + "type": "object", + "required": [ + "QueryParam" + ], + "properties": { + "QueryParam": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "CkdAppId": { + "description": "AppId for CKD", + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "Collateral": { + "type": "object", + "required": [ + "pck_crl", + "pck_crl_issuer_chain", + "qe_identity", + "qe_identity_issuer_chain", + "qe_identity_signature", + "root_ca_crl", + "tcb_info", + "tcb_info_issuer_chain", + "tcb_info_signature" + ], + "properties": { + "pck_certificate_chain": { + "type": [ + "string", + "null" + ] + }, + "pck_crl": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "pck_crl_issuer_chain": { + "type": "string" + }, + "qe_identity": { + "type": "string" + }, + "qe_identity_issuer_chain": { + "type": "string" + }, + "qe_identity_signature": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "root_ca_crl": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "tcb_info": { + "type": "string" + }, + "tcb_info_issuer_chain": { + "type": "string" + }, + "tcb_info_signature": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + }, + "Config": { + "description": "Configuration parameters of the contract.", + "type": "object", + "required": [ + "apply_contract_update_tera_gas", + "attestation_storage_fee_millinear", + "ckd_call_gas_attachment_requirement_tera_gas", + "clean_foreign_chain_data_tera_gas", + "clean_invalid_attestations_tera_gas", + "clean_tee_status_tera_gas", + "cleanup_orphaned_node_migrations_tera_gas", + "fail_attestation_submission_tera_gas", + "fail_on_timeout_tera_gas", + "key_event_timeout_blocks", + "launcher_hash_unused_ttl_seconds", + "remove_non_participant_tee_verifier_votes_tera_gas", + "remove_non_participant_update_votes_tera_gas", + "resolve_verification_tera_gas", + "return_ck_and_clean_state_on_success_call_tera_gas", + "return_signature_and_clean_state_on_success_call_tera_gas", + "sign_call_gas_attachment_requirement_tera_gas", + "tee_upgrade_deadline_duration_seconds", + "verifier_tera_gas" + ], + "properties": { + "apply_contract_update_tera_gas": { + "description": "Prepaid gas for applying contract and config updates.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "attestation_storage_fee_millinear": { + "description": "Fee, in milliNEAR, for one attestation-storage grant.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "ckd_call_gas_attachment_requirement_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "clean_foreign_chain_data_tera_gas": { + "description": "Prepaid gas for a `clean_foreign_chain_data` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "clean_invalid_attestations_tera_gas": { + "description": "Prepaid gas for the reshare-time `clean_invalid_attestations` promise.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "clean_tee_status_tera_gas": { + "description": "Prepaid gas for a `clean_tee_status` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "cleanup_orphaned_node_migrations_tera_gas": { + "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "fail_attestation_submission_tera_gas": { + "description": "Prepaid gas for a `fail_attestation_submission` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "fail_on_timeout_tera_gas": { + "description": "Prepaid gas for a `fail_on_timeout` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "key_event_timeout_blocks": { + "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "launcher_hash_unused_ttl_seconds": { + "description": "How long a launcher hash that no current participant uses stays allowed after its last vote or the last `verify_tee` that saw it in use. Removal happens only in `verify_tee`, so it can lag this TTL; a hash in use is never removed automatically.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "remove_non_participant_tee_verifier_votes_tera_gas": { + "description": "Prepaid gas for a `remove_non_participant_tee_verifier_votes` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "remove_non_participant_update_votes_tera_gas": { + "description": "Prepaid gas for a `remove_non_participant_contract_update_votes` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "resolve_verification_tera_gas": { + "description": "Prepaid gas for the `resolve_verification` callback.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "return_ck_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "return_signature_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "sign_call_gas_attachment_requirement_tera_gas": { + "description": "Gas required for a sign request.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "tee_upgrade_deadline_duration_seconds": { + "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "verifier_tera_gas": { + "description": "Gas attached to the cross-contract `verify_quote` call on the verifier.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "Curve": { + "description": "Elliptic curve used by a domain.", + "type": "string", + "enum": [ + "Secp256k1", + "Edwards25519", + "Bls12381" + ] + }, + "DestinationNodeInfo": { + "type": "object", + "required": [ + "destination_node_info", + "signer_account_pk" + ], + "properties": { + "destination_node_info": { + "$ref": "#/definitions/ParticipantInfo" + }, + "signer_account_pk": { + "description": "The public key used by the node to sign transactions to the contract. This key is different from the TLS key stored in [`ParticipantInfo::tls_public_key`].", + "allOf": [ + { + "$ref": "#/definitions/Ed25519PublicKey" + } + ] + } + } + }, + "DockerImageHash": { + "type": "string", + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-fA-F]+$" + }, + "DomainConfig": { + "description": "Configuration for a signature domain.", + "type": "object", + "required": [ + "id", + "protocol", + "purpose", + "reconstruction_threshold" + ], + "properties": { + "id": { + "$ref": "#/definitions/DomainId" + }, + "protocol": { + "$ref": "#/definitions/Protocol" + }, + "purpose": { + "$ref": "#/definitions/DomainPurpose" + }, + "reconstruction_threshold": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "DomainId": { + "description": "Each domain corresponds to a specific root key on a specific elliptic curve. There may be multiple domains per curve. The domain ID uniquely identifies a domain.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "DomainPurpose": { + "description": "The purpose that a domain serves.", + "oneOf": [ + { + "description": "Domain is used by `sign()`.", + "type": "string", + "enum": [ + "Sign" + ] + }, + { + "description": "Domain is used by `verify_foreign_transaction()`.", + "type": "string", + "enum": [ + "ForeignTx" + ] + }, + { + "description": "Domain is used by `request_app_private_key()` (Confidential Key Derivation).", + "type": "string", + "enum": [ + "CKD" + ] + } + ] + }, + "DomainRegistry": { + "description": "Registry of all signature domains.", + "type": "object", + "required": [ + "domains", + "next_domain_id" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig" + } + }, + "next_domain_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "DstackAttestation": { + "type": "object", + "required": [ + "collateral", + "quote", + "tcb_info" + ], + "properties": { + "collateral": { + "$ref": "#/definitions/Collateral" + }, + "quote": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "tcb_info": { + "$ref": "#/definitions/TcbInfo" + } + } + }, + "Ed25519PublicKey": { + "type": "string" + }, + "Ed25519Signature": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + }, + "EpochId": { + "description": "An EpochId uniquely identifies a GovernanceThresholdParameters (but not vice-versa). Every time we change the GovernanceThresholdParameters (participants and threshold), we increment EpochId. Locally on each node, each keyshare is uniquely identified by the tuple (EpochId, DomainId, AttemptId).", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "EventLog": { + "description": "Represents an event log entry in the system", + "type": "object", + "required": [ + "digest", + "event", + "event_payload", + "event_type", + "imr" + ], + "properties": { + "digest": { + "description": "The cryptographic digest of the event", + "type": "string" + }, + "event": { + "description": "The type of event as a string", + "type": "string" + }, + "event_payload": { + "description": "The payload data associated with the event", + "type": "string" + }, + "event_type": { + "description": "The type of event being logged", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "imr": { + "description": "The index of the IMR (Integrity Measurement Register)", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + "EvmExtractor": { + "oneOf": [ + { + "type": "string", + "enum": [ + "BlockHash" + ] + }, + { + "type": "object", + "required": [ + "Log" + ], + "properties": { + "Log": { + "type": "object", + "required": [ + "log_index" + ], + "properties": { + "log_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "EvmFinality": { + "type": "string", + "enum": [ + "Latest", + "Safe", + "Finalized" + ] + }, + "EvmRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "$ref": "#/definitions/BoundedVec_EvmExtractor_Min0_Max32" + }, + "finality": { + "$ref": "#/definitions/EvmFinality" + }, + "tx_id": { + "$ref": "#/definitions/EvmTxId" + } + } + }, + "EvmTxId": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "ExpectedMeasurements": { + "description": "The TDX measurements an attestation is required to match.", + "type": "object", + "required": [ + "key_provider_event_digest", + "mrtd", + "rtmr0", + "rtmr1", + "rtmr2" + ], + "properties": { + "key_provider_event_digest": { + "$ref": "#/definitions/KeyProviderEventDigest" + }, + "mrtd": { + "$ref": "#/definitions/MrtdHash" + }, + "rtmr0": { + "$ref": "#/definitions/Rtmr0Hash" + }, + "rtmr1": { + "$ref": "#/definitions/Rtmr1Hash" + }, + "rtmr2": { + "$ref": "#/definitions/Rtmr2Hash" + } + } + }, + "ForeignChain": { + "type": "string", + "enum": [ + "Solana", + "Bitcoin", + "Ethereum", + "Base", + "Bnb", + "Arbitrum", + "Abstract", + "Starknet", + "Polygon", + "HyperEvm", + "Ton", + "Aptos", + "Sui", + "Avalanche", + "Adi", + "Fogo" + ] + }, + "ForeignChainRpcRequest": { + "oneOf": [ + { + "type": "object", + "required": [ + "Abstract" + ], + "properties": { + "Abstract": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Ethereum" + ], + "properties": { + "Ethereum": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Solana" + ], + "properties": { + "Solana": { + "$ref": "#/definitions/SvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Bitcoin" + ], + "properties": { + "Bitcoin": { + "$ref": "#/definitions/BitcoinRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Starknet" + ], + "properties": { + "Starknet": { + "$ref": "#/definitions/StarknetRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Bnb" + ], + "properties": { + "Bnb": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Base" + ], + "properties": { + "Base": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Arbitrum" + ], + "properties": { + "Arbitrum": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Polygon" + ], + "properties": { + "Polygon": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "HyperEvm" + ], + "properties": { + "HyperEvm": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Ton" + ], + "properties": { + "Ton": { + "$ref": "#/definitions/TonRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Aptos" + ], + "properties": { + "Aptos": { + "$ref": "#/definitions/AptosRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Sui" + ], + "properties": { + "Sui": { + "$ref": "#/definitions/SuiRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Avalanche" + ], + "properties": { + "Avalanche": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Adi" + ], + "properties": { + "Adi": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Fogo" + ], + "properties": { + "Fogo": { + "$ref": "#/definitions/SvmRpcRequest" + } + }, + "additionalProperties": false + } + ] + }, + "ForeignChainsConfig": { + "description": "Set of foreign chains a node reports it can serve; aggregated into [`AvailableForeignChains`] by the contract.", + "type": "array", + "items": { + "$ref": "#/definitions/ForeignChain" + }, + "uniqueItems": true + }, + "ForeignChainsConfigs": { + "description": "Per-node foreign-chain configs, keyed by each node's TLS public key.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ForeignChainsConfig" + } + }, + "GovernanceThreshold": { + "description": "Network-wide governance threshold (`k`): the minimum number of participants that must agree to approve a governance action (participant set changes, resharing, parameter updates). Distinct from a domain's [`ReconstructionThreshold`], the per-domain `t` needed to reconstruct a key.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "GovernanceThresholdParameters": { + "description": "GovernanceThreshold parameters for distributed key operations: the current participant set and the governance threshold. This is the stored, always-current shape; per-domain reconstruction-threshold *proposals* live on [`ProposedGovernanceThresholdParameters`].", + "type": "object", + "required": [ + "participants", + "threshold" + ], + "properties": { + "participants": { + "$ref": "#/definitions/Participants" + }, + "threshold": { + "$ref": "#/definitions/GovernanceThreshold" + } + } + }, + "Hash256": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "HexString_Min0_Max1232": { + "type": "string", + "maxLength": 2464, + "minLength": 0, + "pattern": "^[0-9a-fA-F]*$" + }, + "HexString_Min32_Max32": { + "type": "string", + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-fA-F]*$" + }, + "InitConfig": { + "description": "The initial configuration parameters for when initializing the contract. All fields are optional, as the contract can fill in defaults for any missing fields.", + "type": "object", + "properties": { + "apply_contract_update_tera_gas": { + "description": "Prepaid gas for applying contract and config updates.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "attestation_storage_fee_millinear": { + "description": "Fee, in milliNEAR, for one attestation-storage grant.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "ckd_call_gas_attachment_requirement_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "clean_foreign_chain_data_tera_gas": { + "description": "Prepaid gas for a `clean_foreign_chain_data` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "clean_invalid_attestations_tera_gas": { + "description": "Prepaid gas for the reshare-time `clean_invalid_attestations` promise.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "clean_tee_status_tera_gas": { + "description": "Prepaid gas for a `clean_tee_status` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "cleanup_orphaned_node_migrations_tera_gas": { + "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "fail_attestation_submission_tera_gas": { + "description": "Prepaid gas for a `fail_attestation_submission` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "fail_on_timeout_tera_gas": { + "description": "Prepaid gas for a `fail_on_timeout` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "key_event_timeout_blocks": { + "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "launcher_hash_unused_ttl_seconds": { + "description": "TTL for launcher hashes no current participant uses; see [`Config::launcher_hash_unused_ttl_seconds`].", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "remove_non_participant_tee_verifier_votes_tera_gas": { + "description": "Prepaid gas for a `remove_non_participant_tee_verifier_votes` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "remove_non_participant_update_votes_tera_gas": { + "description": "Prepaid gas for a `remove_non_participant_contract_update_votes` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "resolve_verification_tera_gas": { + "description": "Prepaid gas for the `resolve_verification` callback.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "return_ck_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "return_signature_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "sign_call_gas_attachment_requirement_tera_gas": { + "description": "Gas required for a sign request.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "tee_upgrade_deadline_duration_seconds": { + "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "verifier_tera_gas": { + "description": "Gas attached to the cross-contract `verify_quote` call on the verifier.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + }, + "InitializingContractState": { + "description": "State when the contract is generating keys for new domains.", + "type": "object", + "required": [ + "cancel_votes", + "domains", + "epoch_id", + "generated_keys", + "generating_key" + ], + "properties": { + "cancel_votes": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedParticipantId" + }, + "uniqueItems": true + }, + "domains": { + "$ref": "#/definitions/DomainRegistry" + }, + "epoch_id": { + "$ref": "#/definitions/EpochId" + }, + "generated_keys": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyForDomain" + } + }, + "generating_key": { + "$ref": "#/definitions/KeyEvent" + } + } + }, + "K256AffinePoint": { + "description": "AffinePoint on the Secp256k1 curve", + "type": "object", + "required": [ + "affine_point" + ], + "properties": { + "affine_point": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + }, + "K256Scalar": { + "type": "object", + "required": [ + "scalar" + ], + "properties": { + "scalar": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + }, + "KeyEvent": { + "description": "Key generation or resharing event state.", + "type": "object", + "required": [ + "domain", + "epoch_id", + "next_attempt_id", + "parameters" + ], + "properties": { + "domain": { + "$ref": "#/definitions/DomainConfig" + }, + "epoch_id": { + "$ref": "#/definitions/EpochId" + }, + "instance": { + "anyOf": [ + { + "$ref": "#/definitions/KeyEventInstance" + }, + { + "type": "null" + } + ] + }, + "next_attempt_id": { + "$ref": "#/definitions/AttemptId" + }, + "parameters": { + "$ref": "#/definitions/GovernanceThresholdParameters" + } + } + }, + "KeyEventId": { + "description": "A unique identifier for a key event (generation or resharing): `epoch_id`: identifies the GovernanceThresholdParameters that this key is intended to function in. `domain_id`: the domain this key is intended for. `attempt_id`: identifies a particular attempt for this key event, in case multiple attempts yielded partially valid results. This is incremented for each attempt within the same epoch and domain.", + "type": "object", + "required": [ + "attempt_id", + "domain_id", + "epoch_id" + ], + "properties": { + "attempt_id": { + "$ref": "#/definitions/AttemptId" + }, + "domain_id": { + "$ref": "#/definitions/DomainId" + }, + "epoch_id": { + "$ref": "#/definitions/EpochId" + } + } + }, + "KeyEventInstance": { + "description": "State of a key generation/resharing instance.", + "type": "object", + "required": [ + "attempt_id", + "completed", + "expires_on", + "started_in" + ], + "properties": { + "attempt_id": { + "$ref": "#/definitions/AttemptId" + }, + "completed": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedParticipantId" + }, + "uniqueItems": true + }, + "expires_on": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "public_key": { + "anyOf": [ + { + "$ref": "#/definitions/PublicKeyExtended" + }, + { + "type": "null" + } + ] + }, + "started_in": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "KeyForDomain": { + "description": "The identification of a specific distributed key, based on which a node would know exactly what keyshare it has corresponds to this distributed key. (A distributed key refers to a specific set of keyshares that nodes have which can be pieced together to form the secret key.)", + "type": "object", + "required": [ + "attempt", + "domain_id", + "key" + ], + "properties": { + "attempt": { + "description": "The attempt ID that generated (initially or as a result of resharing) this distributed key. Nodes may have made multiple attempts to generate the distributed key, and this uniquely identifies which one should ultimately be used.", + "allOf": [ + { + "$ref": "#/definitions/AttemptId" + } + ] + }, + "domain_id": { + "description": "Identifies the domain this key is intended for.", + "allOf": [ + { + "$ref": "#/definitions/DomainId" + } + ] + }, + "key": { + "description": "Identifies the public key. Although technically redundant given that we have the AttemptId, we keep it here in the contract so that it can be verified against and queried.", + "allOf": [ + { + "$ref": "#/definitions/PublicKeyExtended" + } + ] + } + } + }, + "KeyProviderEventDigest": { + "type": "string", + "maxLength": 96, + "minLength": 96, + "pattern": "^[0-9a-fA-F]+$" + }, + "Keyset": { + "description": "Represents a key for every domain in a specific epoch.", + "type": "object", + "required": [ + "domains", + "epoch_id" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyForDomain" + } + }, + "epoch_id": { + "$ref": "#/definitions/EpochId" + } + } + }, + "LauncherDockerComposeHash": { + "type": "string", + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-fA-F]+$" + }, + "LauncherImageHash": { + "type": "string", + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-fA-F]+$" + }, + "MigrationInfo": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": [ + { + "anyOf": [ + { + "$ref": "#/definitions/BackupServiceInfo" + }, + { + "type": "null" + } + ] + }, + { + "anyOf": [ + { + "$ref": "#/definitions/DestinationNodeInfo" + }, + { + "type": "null" + } + ] + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "MockAttestation": { + "oneOf": [ + { + "description": "Always pass validation", + "type": "string", + "enum": [ + "Valid" + ] + }, + { + "description": "Always fails validation", + "type": "string", + "enum": [ + "Invalid" + ] + }, + { + "description": "Pass validation depending on the set constraints", + "type": "object", + "required": [ + "WithConstraints" + ], + "properties": { + "WithConstraints": { + "type": "object", + "properties": { + "expected_measurements": { + "anyOf": [ + { + "$ref": "#/definitions/ExpectedMeasurements" + }, + { + "type": "null" + } + ] + }, + "expiry_timestamp_seconds": { + "description": "Unix time stamp for when this attestation expires.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "launcher_docker_compose_hash": { + "anyOf": [ + { + "$ref": "#/definitions/LauncherDockerComposeHash" + }, + { + "type": "null" + } + ] + }, + "mpc_docker_image_hash": { + "anyOf": [ + { + "$ref": "#/definitions/DockerImageHash" + }, + { + "type": "null" + } + ] + } + } + } + }, + "additionalProperties": false + } + ] + }, + "MrtdHash": { + "type": "string", + "maxLength": 96, + "minLength": 96, + "pattern": "^[0-9a-fA-F]+$" + }, + "NodeId": { + "type": "object", + "required": [ + "account_id", + "account_public_key", + "tls_public_key" + ], + "properties": { + "account_id": { + "description": "Operator account.", + "type": "string" + }, + "account_public_key": { + "description": "Full-access Ed25519 public key of the operator account.", + "allOf": [ + { + "$ref": "#/definitions/Ed25519PublicKey" + } + ] + }, + "tls_public_key": { + "description": "TLS public key used by the node for peer-to-peer communication.", + "allOf": [ + { + "$ref": "#/definitions/Ed25519PublicKey" + } + ] + } + } + }, + "NonEmptyBTreeMap_ForeignChain_ChainEntry": { + "type": "object", + "minProperties": 1, + "additionalProperties": { + "$ref": "#/definitions/ChainEntry" + } + }, + "NonEmptyBTreeMap_ProviderId_ProviderConfig": { + "type": "object", + "minProperties": 1, + "additionalProperties": { + "$ref": "#/definitions/ProviderConfig" + } + }, + "ParticipantId": { + "description": "Stable identifier for a participant within the MPC protocol's participant set.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "ParticipantInfo": { + "type": "object", + "required": [ + "tls_public_key", + "url" + ], + "properties": { + "tls_public_key": { + "$ref": "#/definitions/Ed25519PublicKey" + }, + "url": { + "$ref": "#/definitions/BoundedString_256" + } + } + }, + "Participants": { + "description": "DTO representation of the contract-internal [`Participants`] type.\n\nIt decouples the JSON wire format (used in view methods like `state()` via [`GovernanceThresholdParameters`](crate::types::state::GovernanceThresholdParameters) from the internal [`Participants`] representation, allowing internal changes (e.g., migrating to [`BTreeMap`](std::collections::BTreeMap) in [#1861](https://github.com/near/mpc/pull/1861)) without breaking the public API.", + "type": "object", + "required": [ + "next_id", + "participants" + ], + "properties": { + "next_id": { + "$ref": "#/definitions/ParticipantId" + }, + "participants": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + }, + { + "$ref": "#/definitions/ParticipantId" + }, + { + "$ref": "#/definitions/ParticipantInfo" + } + ], + "maxItems": 3, + "minItems": 3 + } + } + } + }, + "Payload": { + "description": "A signature payload; the right payload must be passed in for the curve. The json encoding for this payload converts the bytes to hex string.", + "oneOf": [ + { + "type": "object", + "required": [ + "Ecdsa" + ], + "properties": { + "Ecdsa": { + "$ref": "#/definitions/HexString_Min32_Max32" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Eddsa" + ], + "properties": { + "Eddsa": { + "$ref": "#/definitions/HexString_Min0_Max1232" + } + }, + "additionalProperties": false + } + ] + }, + "PromiseOrValueCKDResponse": { + "description": "Response to a CKD request: the derived key, ElGamal-encrypted to the request's app public key (`pk1` in the publicly-verifiable variant).\n\nFor an app key pair `(a, A = a·G1)` and an ephemeral scalar `y` chosen by the MPC network, `big_y` holds `Y = y·G1` and `big_c` holds `C = derived_key + y·A`; decrypt with `derived_key = C - a·Y`. The derived key is a BLS signature on the app id under the domain's public key; verify it as such before use. Neither field is a public key: the field type is reused for its 48-byte compressed G1 point encoding.", + "type": "object", + "required": [ + "big_c", + "big_y" + ], + "properties": { + "big_c": { + "$ref": "#/definitions/Bls12381G1PublicKey" + }, + "big_y": { + "$ref": "#/definitions/Bls12381G1PublicKey" + } + } + }, + "PromiseOrValueNull": { + "type": "null" + }, + "PromiseOrValueSignatureResponse": { + "oneOf": [ + { + "type": "object", + "required": [ + "big_r", + "recovery_id", + "s", + "scheme" + ], + "properties": { + "big_r": { + "$ref": "#/definitions/K256AffinePoint" + }, + "recovery_id": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "s": { + "$ref": "#/definitions/K256Scalar" + }, + "scheme": { + "type": "string", + "enum": [ + "Secp256k1" + ] + } + } + }, + { + "type": "object", + "required": [ + "scheme", + "signature" + ], + "properties": { + "scheme": { + "type": "string", + "enum": [ + "Ed25519" + ] + }, + "signature": { + "$ref": "#/definitions/Ed25519Signature" + } + } + } + ] + }, + "PromiseOrValueVerifyForeignTransactionResponse": { + "type": "object", + "required": [ + "payload_hash", + "signature" + ], + "properties": { + "payload_hash": { + "$ref": "#/definitions/Hash256" + }, + "signature": { + "$ref": "#/definitions/SignatureResponse" + } + } + }, + "ProposedGovernanceThresholdParameters": { + "description": "A proposed set of threshold parameters submitted to `vote_new_parameters`: the proposed [`GovernanceThresholdParameters`] plus per-domain [`ReconstructionThreshold`] updates for the resharing it would trigger. An empty `per_domain_thresholds` keeps the current ones; a populated map must reference only existing domains (contract-validated), is applied to the [`DomainRegistry`] on resharing, and never persists onto the stored [`GovernanceThresholdParameters`].", + "type": "object", + "required": [ + "parameters" + ], + "properties": { + "parameters": { + "$ref": "#/definitions/GovernanceThresholdParameters" + }, + "per_domain_thresholds": { + "default": {}, + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "Protocol": { + "description": "MPC protocol run for a domain.", + "type": "string", + "enum": [ + "CaitSith", + "Frost", + "ConfidentialKeyDerivation", + "RobustEcdsa" + ] + }, + "ProtocolContractState": { + "description": "The main protocol contract state enum.", + "oneOf": [ + { + "type": "string", + "enum": [ + "NotInitialized" + ] + }, + { + "type": "object", + "required": [ + "Initializing" + ], + "properties": { + "Initializing": { + "$ref": "#/definitions/InitializingContractState" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Running" + ], + "properties": { + "Running": { + "$ref": "#/definitions/RunningContractState" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Resharing" + ], + "properties": { + "Resharing": { + "$ref": "#/definitions/ResharingContractState" + } + }, + "additionalProperties": false + } + ] + }, + "ProviderConfig": { + "description": "One provider's per-chain configuration, stored as a value in `ChainEntry.providers` (keyed by [`ProviderId`]). Read by nodes at startup to assemble the actual RPC URL (`base_url` + `chain_routing` + operator-supplied token via `auth_scheme`).", + "type": "object", + "required": [ + "auth_scheme", + "base_url", + "chain_routing" + ], + "properties": { + "auth_scheme": { + "$ref": "#/definitions/AuthScheme" + }, + "base_url": { + "description": "Provider's stable base. When `chain_routing == Embedded`, the chain identifier is already inside `base_url` (subdomain or path prefix). Otherwise `base_url` is chain-agnostic and `chain_routing` carries the chain marker.\n\nA single `{}` allows per-operator slug (e.g. QuickNode's `https://{}.sui-testnet.quiknode.pro`); nodes match it against exactly one label of the local URL, keeping the rest of the host pinned.", + "type": "string" + }, + "chain_routing": { + "$ref": "#/definitions/ChainRouting" + } + } + }, + "PublicKey": { + "oneOf": [ + { + "type": "object", + "required": [ + "Secp256k1" + ], + "properties": { + "Secp256k1": { + "$ref": "#/definitions/Secp256k1PublicKey" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Ed25519" + ], + "properties": { + "Ed25519": { + "$ref": "#/definitions/Ed25519PublicKey" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Bls12381" + ], + "properties": { + "Bls12381": { + "$ref": "#/definitions/Bls12381G2PublicKey" + } + }, + "additionalProperties": false + } + ] + }, + "PublicKeyExtended": { + "description": "Extended public key representation for different signature schemes.", + "oneOf": [ + { + "description": "Secp256k1 public key (ECDSA).", + "type": "object", + "required": [ + "Secp256k1" + ], + "properties": { + "Secp256k1": { + "type": "object", + "required": [ + "near_public_key" + ], + "properties": { + "near_public_key": { + "description": "The public key in NEAR SDK format (string representation).", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Ed25519 public key.", + "type": "object", + "required": [ + "Ed25519" + ], + "properties": { + "Ed25519": { + "type": "object", + "required": [ + "edwards_point", + "near_public_key_compressed" + ], + "properties": { + "edwards_point": { + "description": "The Edwards point (32 bytes).", + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "near_public_key_compressed": { + "description": "The compressed public key in NEAR SDK format.", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "BLS12-381 public key.", + "type": "object", + "required": [ + "Bls12381" + ], + "properties": { + "Bls12381": { + "type": "object", + "required": [ + "public_key" + ], + "properties": { + "public_key": { + "description": "The public key.", + "allOf": [ + { + "$ref": "#/definitions/PublicKey" + } + ] + } + } + } + }, + "additionalProperties": false + } + ] + }, + "ResharingContractState": { + "description": "State when the contract is resharing keys to new participants.", + "type": "object", + "required": [ + "cancellation_requests", + "previous_running_state", + "reshared_keys", + "resharing_key" + ], + "properties": { + "cancellation_requests": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + }, + "per_domain_thresholds": { + "description": "Per-domain [`ReconstructionThreshold`] updates carried from the accepted proposal. Applied to the [`DomainRegistry`] when resharing completes.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "previous_running_state": { + "description": "The state being reshared from; while resharing, its `parameters_votes` hold the re-proposal votes for the prospective epoch.", + "allOf": [ + { + "$ref": "#/definitions/RunningContractState" + } + ] + }, + "reshared_keys": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyForDomain" + } + }, + "resharing_key": { + "$ref": "#/definitions/KeyEvent" + } + } + }, + "Rtmr0Hash": { + "type": "string", + "maxLength": 96, + "minLength": 96, + "pattern": "^[0-9a-fA-F]+$" + }, + "Rtmr1Hash": { + "type": "string", + "maxLength": 96, + "minLength": 96, + "pattern": "^[0-9a-fA-F]+$" + }, + "Rtmr2Hash": { + "type": "string", + "maxLength": 96, + "minLength": 96, + "pattern": "^[0-9a-fA-F]+$" + }, + "RunningContractState": { + "description": "State when the contract is ready for signature operations.", + "type": "object", + "required": [ + "add_domains_votes", + "domains", + "keyset", + "parameters", + "parameters_votes" + ], + "properties": { + "add_domains_votes": { + "$ref": "#/definitions/AddDomainsVotes" + }, + "domains": { + "$ref": "#/definitions/DomainRegistry" + }, + "keyset": { + "$ref": "#/definitions/Keyset" + }, + "parameters": { + "$ref": "#/definitions/GovernanceThresholdParameters" + }, + "parameters_votes": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + } + }, + "previously_cancelled_resharing_epoch_id": { + "anyOf": [ + { + "$ref": "#/definitions/EpochId" + }, + { + "type": "null" + } + ] + } + } + }, + "Secp256k1PublicKey": { + "type": "string" + }, + "SignRequestArgs": { + "description": "Sign request args with backward-compatible deserialization.\n\nThe struct field is `payload` but serializes as `payload_v2` on the wire for compatibility with existing consumers. Deserialization accepts both `payload_v2` and the deprecated `payload` (as raw `[u8; 32]`) plus `key_version` as an alias for `domain_id`.", + "type": "object", + "required": [ + "domain_id", + "path", + "payload_v2" + ], + "properties": { + "domain_id": { + "description": "Identifies the domain whose distributed key is used to derive the signing key.", + "allOf": [ + { + "$ref": "#/definitions/DomainId" + } + ] + }, + "path": { + "description": "Identifies the derived key. The key is determined by the caller's account ID and this derivation path. Different paths produce different keys.", + "type": "string" + }, + "payload_v2": { + "$ref": "#/definitions/Payload" + } + } + }, + "SignatureRequest": { + "description": "A signature request after computing the tweak from the caller's account and derivation path. This is what gets stored in the contract state and sent back to the respond function.", + "type": "object", + "required": [ + "domain_id", + "payload", + "tweak" + ], + "properties": { + "domain_id": { + "$ref": "#/definitions/DomainId" + }, + "payload": { + "$ref": "#/definitions/Payload" + }, + "tweak": { + "$ref": "#/definitions/Tweak" + } + } + }, + "SignatureResponse": { + "oneOf": [ + { + "type": "object", + "required": [ + "big_r", + "recovery_id", + "s", + "scheme" + ], + "properties": { + "big_r": { + "$ref": "#/definitions/K256AffinePoint" + }, + "recovery_id": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "s": { + "$ref": "#/definitions/K256Scalar" + }, + "scheme": { + "type": "string", + "enum": [ + "Secp256k1" + ] + } + } + }, + { + "type": "object", + "required": [ + "scheme", + "signature" + ], + "properties": { + "scheme": { + "type": "string", + "enum": [ + "Ed25519" + ] + }, + "signature": { + "$ref": "#/definitions/Ed25519Signature" + } + } + } + ] + }, + "StarknetExtractor": { + "oneOf": [ + { + "type": "string", + "enum": [ + "BlockHash" + ] + }, + { + "type": "object", + "required": [ + "Log" + ], + "properties": { + "Log": { + "type": "object", + "required": [ + "log_index" + ], + "properties": { + "log_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "StarknetFelt": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "StarknetFinality": { + "type": "string", + "enum": [ + "AcceptedOnL2", + "AcceptedOnL1" + ] + }, + "StarknetRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "$ref": "#/definitions/BoundedVec_StarknetExtractor_Min0_Max32" + }, + "finality": { + "$ref": "#/definitions/StarknetFinality" + }, + "tx_id": { + "$ref": "#/definitions/StarknetTxId" + } + } + }, + "StarknetTxId": { + "$ref": "#/definitions/StarknetFelt" + }, + "StoredAttestation": { + "description": "An attestation as the contract stores it.", + "type": "object", + "required": [ + "attestation" + ], + "properties": { + "accepted_at_seconds": { + "description": "Block time at which the contract accepted this attestation. Every accepted submission restamps it, so a submitter can tell whether its own submission landed. `None` for an entry stored before the contract recorded it.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "attestation": { + "$ref": "#/definitions/VerifiedAttestation" + } + } + }, + "SuiExtractor": { + "oneOf": [ + { + "type": "object", + "required": [ + "Event" + ], + "properties": { + "Event": { + "type": "object", + "required": [ + "event_index" + ], + "properties": { + "event_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "SuiFinality": { + "description": "Sui has no reorgs; a transaction is final once it is included in a committee-certified checkpoint.", + "type": "string", + "enum": [ + "Checkpointed" + ] + }, + "SuiRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "$ref": "#/definitions/BoundedVec_SuiExtractor_Min0_Max32" + }, + "finality": { + "$ref": "#/definitions/SuiFinality" + }, + "tx_id": { + "$ref": "#/definitions/SuiTxId" + } + } + }, + "SuiTxId": { + "description": "32-byte Sui transaction digest (Blake2b-256 of the signed transaction data). Sui APIs display it base58-encoded; here it is carried as raw bytes (hex in JSON).", + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "SvmAddress": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "SvmExtractor": { + "oneOf": [ + { + "type": "object", + "required": [ + "InnerInstruction" + ], + "properties": { + "InnerInstruction": { + "type": "object", + "required": [ + "inner_instruction_index", + "instruction_index" + ], + "properties": { + "inner_instruction_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "instruction_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "AccountState" + ], + "properties": { + "AccountState": { + "type": "object", + "required": [ + "pubkey" + ], + "properties": { + "pubkey": { + "$ref": "#/definitions/SvmAddress" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "SvmFinality": { + "type": "string", + "enum": [ + "Confirmed", + "Finalized" + ] + }, + "SvmRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "$ref": "#/definitions/BoundedVec_SvmExtractor_Min0_Max32" + }, + "finality": { + "$ref": "#/definitions/SvmFinality" + }, + "tx_id": { + "$ref": "#/definitions/SvmTxId" + } + } + }, + "SvmTxId": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2}){64}$" + }, + "TcbInfo": { + "description": "Trusted Computing Base information structure", + "type": "object", + "required": [ + "app_compose", + "compose_hash", + "device_id", + "event_log", + "mrtd", + "rtmr0", + "rtmr1", + "rtmr2", + "rtmr3" + ], + "properties": { + "app_compose": { + "description": "The app compose", + "type": "string" + }, + "compose_hash": { + "description": "The hash of the compose configuration", + "type": "string" + }, + "device_id": { + "description": "The device identifier", + "type": "string" + }, + "event_log": { + "description": "The event log entries", + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "mrtd": { + "description": "The measurement root of trust", + "type": "string" + }, + "os_image_hash": { + "description": "The hash of the OS image. This is empty if the OS image is not measured by KMS.", + "default": "", + "type": "string" + }, + "rtmr0": { + "description": "The value of RTMR0 (Runtime Measurement Register 0)", + "type": "string" + }, + "rtmr1": { + "description": "The value of RTMR1 (Runtime Measurement Register 1)", + "type": "string" + }, + "rtmr2": { + "description": "The value of RTMR2 (Runtime Measurement Register 2)", + "type": "string" + }, + "rtmr3": { + "description": "The value of RTMR3 (Runtime Measurement Register 3)", + "type": "string" + } + } + }, + "TeeVerifierCodeHash": { + "type": "string", + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-fA-F]+$" + }, + "TonAddress": { + "type": "object", + "required": [ + "hash", + "workchain" + ], + "properties": { + "hash": { + "$ref": "#/definitions/Hash256" + }, + "workchain": { + "type": "integer", + "format": "int32" + } + } + }, + "TonExtractor": { + "oneOf": [ + { + "type": "object", + "required": [ + "Log" + ], + "properties": { + "Log": { + "type": "object", + "required": [ + "message_index" + ], + "properties": { + "message_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "TonFinality": { + "type": "string", + "enum": [ + "MasterchainIncluded" + ] + }, + "TonRpcRequest": { + "type": "object", + "required": [ + "account", + "extractors", + "finality", + "tx_id" + ], + "properties": { + "account": { + "$ref": "#/definitions/TonAddress" + }, + "extractors": { + "$ref": "#/definitions/BoundedVec_TonExtractor_Min0_Max32" + }, + "finality": { + "$ref": "#/definitions/TonFinality" + }, + "tx_id": { + "$ref": "#/definitions/TonTxId" + } + } + }, + "TonTxId": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "Tweak": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "UpdateHash": { + "description": "Identifies an [`Update`] by content.", + "oneOf": [ + { + "type": "object", + "required": [ + "Code" + ], + "properties": { + "Code": { + "$ref": "#/definitions/Hash256" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Config" + ], + "properties": { + "Config": { + "$ref": "#/definitions/Hash256" + } + }, + "additionalProperties": false + } + ] + }, + "VerifiedAttestation": { + "oneOf": [ + { + "type": "object", + "required": [ + "Dstack" + ], + "properties": { + "Dstack": { + "$ref": "#/definitions/VerifiedDstackAttestation" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Mock" + ], + "properties": { + "Mock": { + "$ref": "#/definitions/MockAttestation" + } + }, + "additionalProperties": false + } + ] + }, + "VerifiedDstackAttestation": { + "type": "object", + "required": [ + "expiry_timestamp_seconds", + "launcher_compose_hash", + "measurements", + "mpc_image_hash" + ], + "properties": { + "expiry_timestamp_seconds": { + "description": "Unix time stamp for when this attestation expires.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "launcher_compose_hash": { + "description": "The digest of the launcher compose file running.", + "allOf": [ + { + "$ref": "#/definitions/LauncherDockerComposeHash" + } + ] + }, + "measurements": { + "description": "The OS measurements that were verified during initial attestation.", + "allOf": [ + { + "$ref": "#/definitions/VerifiedMeasurements" + } + ] + }, + "mpc_image_hash": { + "description": "The digest of the MPC image running.", + "allOf": [ + { + "$ref": "#/definitions/DockerImageHash" + } + ] + } + } + }, + "VerifiedMeasurements": { + "type": "object", + "required": [ + "key_provider_event_digest", + "mrtd", + "rtmr0", + "rtmr1", + "rtmr2" + ], + "properties": { + "key_provider_event_digest": { + "$ref": "#/definitions/KeyProviderEventDigest" + }, + "mrtd": { + "$ref": "#/definitions/MrtdHash" + }, + "rtmr0": { + "$ref": "#/definitions/Rtmr0Hash" + }, + "rtmr1": { + "$ref": "#/definitions/Rtmr1Hash" + }, + "rtmr2": { + "$ref": "#/definitions/Rtmr2Hash" + } + } + }, + "VerifyForeignTransactionRequest": { + "type": "object", + "required": [ + "domain_id", + "payload_version", + "request" + ], + "properties": { + "domain_id": { + "$ref": "#/definitions/DomainId" + }, + "expected_payload_hash": { + "anyOf": [ + { + "$ref": "#/definitions/Hash256" + }, + { + "type": "null" + } + ] + }, + "payload_version": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "request": { + "$ref": "#/definitions/ForeignChainRpcRequest" + } + } + }, + "VerifyForeignTransactionRequestArgs": { + "type": "object", + "required": [ + "domain_id", + "payload_version", + "request" + ], + "properties": { + "domain_id": { + "$ref": "#/definitions/DomainId" + }, + "expected_payload_hash": { + "anyOf": [ + { + "$ref": "#/definitions/Hash256" + }, + { + "type": "null" + } + ] + }, + "payload_version": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "request": { + "$ref": "#/definitions/ForeignChainRpcRequest" + } + } + }, + "VerifyForeignTransactionResponse": { + "type": "object", + "required": [ + "payload_hash", + "signature" + ], + "properties": { + "payload_hash": { + "$ref": "#/definitions/Hash256" + }, + "signature": { + "$ref": "#/definitions/SignatureResponse" + } + } + }, + "YieldIndex": { + "description": "The index into calling the YieldResume feature of NEAR. This will allow to resume a yield call after the contract has been called back via this index.", + "type": "object", + "required": [ + "data_id" + ], + "properties": { + "data_id": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + } + } + } + } + } +} diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 93d30f96ba..06b2a66e1e 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -308,6 +308,8 @@ pub struct RunningContractState { derive(schemars::JsonSchema) )] pub struct ResharingContractState { + /// The state being reshared from; while resharing, its `parameters_votes` hold the + /// re-proposal votes for the prospective epoch. pub previous_running_state: RunningContractState, pub reshared_keys: Vec, pub resharing_key: KeyEvent, @@ -550,6 +552,22 @@ mod tests { assert_eq!(parsed.per_domain_thresholds.len(), 0); } + #[test] + fn parameters_votes_serialize_as_a_transparent_map_keyed_by_proposal_hash() { + // Given + let proposal = ProposalHash::new([0xCD; 32]); + let votes = GovernanceThresholdParametersVotes(BTreeMap::from([( + proposal, + BTreeSet::from([AuthenticatedAccountId("alice.near".parse().unwrap())]), + )])); + + // When + let json = serde_json::to_value(&votes).unwrap(); + + // Then + assert_eq!(json[proposal.as_hex()][0], "alice.near"); + } + #[test] fn parameters_votes_deserialize_the_legacy_empty_report() { let votes: super::GovernanceThresholdParametersVotes = From 0e1fe8427a410a3cee37433603fcbc466833ae81 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Fri, 23 Oct 2026 13:27:33 +0200 Subject: [PATCH 07/20] test(contract): accept the ABI snapshot and drop the stray .snap.new --- .../snapshots/abi__abi_has_not_changed.snap | 7 +- .../abi__abi_has_not_changed.snap.new | 5547 ----------------- 2 files changed, 6 insertions(+), 5548 deletions(-) delete mode 100644 crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index cb68afcb05..f9cc00dff1 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -4758,7 +4758,12 @@ expression: abi } }, "previous_running_state": { - "$ref": "#/definitions/RunningContractState" + "description": "The state being reshared from; while resharing, its `parameters_votes` hold the re-proposal votes for the prospective epoch.", + "allOf": [ + { + "$ref": "#/definitions/RunningContractState" + } + ] }, "reshared_keys": { "type": "array", diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new deleted file mode 100644 index 63747990b9..0000000000 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new +++ /dev/null @@ -1,5547 +0,0 @@ ---- -source: crates/contract/tests/abi.rs -assertion_line: 47 -expression: abi ---- -{ - "schema_version": "0.4.0", - "metadata": { - "name": "mpc-contract", - "version": "3.17.0", - "build": { - "compiler": "[RUSTC_VERSION]", - "builder": "[CARGO_NEAR_BUILD_VERSION]" - }, - "wasm_hash": "[WASM_HASH]" - }, - "body": { - "functions": [ - { - "name": "allowed_docker_image_hashes", - "doc": " Returns all allowed code hashes in descending order of their expiry\n date. Note that the expiration depends on the contract configuration\n (c.f. [`dtos::Config::tee_upgrade_deadline_duration_seconds`]).", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/AllowedMpcDockerImageHash" - } - } - } - }, - { - "name": "allowed_foreign_chain_providers", - "doc": " On-chain RPC provider whitelist keyed by [`ForeignChain`](dtos::ForeignChain). Nodes read this at\n startup to validate their local `foreign_chains.yaml`.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ChainEntry" - } - } - } - }, - { - "name": "allowed_launcher_compose_hashes", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/LauncherDockerComposeHash" - } - } - } - }, - { - "name": "allowed_launcher_image_hashes", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/LauncherImageHash" - } - } - } - }, - { - "name": "allowed_os_measurements", - "doc": " Returns all currently allowed OS measurements.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ExpectedMeasurements" - } - } - } - }, - { - "name": "available_attestation_grants", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "account_id", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - }, - { - "name": "cancel_node_migration", - "doc": " Cancels a previously started node migration for the calling account.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", - "kind": "call", - "modifiers": [ - "payable" - ], - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "clean_foreign_chain_data", - "doc": " Private endpoint to clean up foreign chain policy votes and node configurations\n for non-participants after resharing.", - "kind": "call", - "modifiers": [ - "private" - ], - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "clean_invalid_attestations", - "doc": " Prunes up to `max_scan` stored attestations that fail re-verification (expired or\n referencing stale whitelists), returning one attestation-storage grant to the owner of\n each entry removed. Returns the number of entries removed. Callable by anyone while the\n protocol is in [`Running`](ProtocolContractState::Running).", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "max_scan", - "type_schema": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - }, - { - "name": "clean_tee_status", - "doc": " Private endpoint to drop votes cast by non-participants after resharing.\n Attestation cleanup is handled separately by [`MpcContract::clean_invalid_attestations`].", - "kind": "call", - "modifiers": [ - "private" - ], - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "cleanup_orphaned_node_migrations", - "kind": "call", - "modifiers": [ - "private" - ], - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "conclude_node_migration", - "doc": " Finalizes a node migration for the calling account.\n\n This method can only be called while the protocol is in a [`Running`](ProtocolContractState::Running) state\n and by an existing participant. On success, the participant’s information is\n updated to the new destination node.\n\n # Errors\n Returns the following errors:\n - [`InvalidState::ProtocolStateNotRunning`]: if protocol is not in [`Running`](ProtocolContractState::Running) state\n - [`InvalidState::NotParticipant`]: if caller is not a current participant\n - [`ConversionError::DataConversion`](crate::errors::ConversionError::DataConversion): if the provided keyset contains a malformed public key\n - [`NodeMigrationError::KeysetMismatch`](crate::errors::NodeMigrationError::KeysetMismatch): if provided keyset does not match the expected keyset\n - [`NodeMigrationError::MigrationNotFound`](crate::errors::NodeMigrationError::MigrationNotFound): if no migration record exists for the caller\n - [`NodeMigrationError::AccountPublicKeyMismatch`](crate::errors::NodeMigrationError::AccountPublicKeyMismatch): if caller’s public key does not match the expected destination node\n - [`InvalidParameters::InvalidTeeRemoteAttestation`]: if destination node’s TEE quote is invalid\n - [`NodeMigrationError::TlsKeyAlreadyClaimed`](crate::errors::NodeMigrationError::TlsKeyAlreadyClaimed): if the destination node's TLS\n public key belongs to another account\n - [`NodeMigrationError::DestinationTlsKeyUnchanged`](crate::errors::NodeMigrationError::DestinationTlsKeyUnchanged): if the destination node reuses the\n caller's current TLS public key", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "keyset", - "type_schema": { - "$ref": "#/definitions/Keyset" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "config", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/Config" - } - } - }, - { - "name": "contract_source_metadata", - "kind": "view" - }, - { - "name": "contract_update_votes", - "doc": " Returns all currently stored votes.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - }, - "uniqueItems": true - } - } - } - }, - { - "name": "derived_public_key", - "doc": " This is the derived public key of the caller given path and predecessor\n if predecessor is not provided, it will be the caller of the contract.\n\n The domain parameter specifies which domain we're deriving the public key for;\n the default is the first domain.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "path", - "type_schema": { - "type": "string" - } - }, - { - "name": "predecessor", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": [ - "string", - "null" - ] - } - }, - { - "name": "domain_id", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/DomainId" - }, - { - "type": "null" - } - ] - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PublicKey" - } - } - }, - { - "name": "fail_attestation_submission", - "kind": "view", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "reason", - "type_schema": { - "type": "string" - } - } - ] - } - }, - { - "name": "fail_on_timeout", - "kind": "view", - "modifiers": [ - "private" - ] - }, - { - "name": "get_attestation", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "tls_public_key", - "type_schema": { - "$ref": "#/definitions/Ed25519PublicKey" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/StoredAttestation" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_available_foreign_chains", - "doc": " The **available** foreign chains: whitelisted chains that are supported\n by at least the signing threshold of active participants.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/AvailableForeignChains" - } - } - }, - { - "name": "get_foreign_chains_configs", - "doc": " Per-participant view of which foreign chains each node currently covers. Feeds the\n available-set computation ([`Self::get_available_foreign_chains`]) and coverage alerting.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/ForeignChainsConfigs" - } - } - }, - { - "name": "get_pending_ckd_request", - "doc": " Presence check for a pending CKD request, exposed as a view call.\n\n See [`Self::get_pending_request`] for the contract: the returned [`dtos::YieldIndex`]\n is an arbitrary representative of a fan-out queue, not \"the\" yield. Only the\n `Some`/`None` distinction is meaningful.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequest" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/YieldIndex" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_pending_request", - "doc": " Presence check for a pending signature request, exposed as a view call.\n\n **The returned [`dtos::YieldIndex`] is an arbitrary representative, not \"the\" yield\n for this request.** Since the duplicate-request fan-out feature (PR #3187),\n a single request key can have N queued yields; this method returns the head of the\n queue. Callers that need to act on the full set are wrong to use this. The\n only correct interpretation is presence: `Some(_)` vs `None`.\n\n The `Option` shape is retained for JSON wire compatibility with\n out-of-tree consumers; the in-tree caller (`tx_sender::observe_tx_result`)\n only matches on presence. Prefer a `bool`-shaped accessor if one is added.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignatureRequest" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/YieldIndex" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_pending_verify_foreign_tx_request", - "doc": " Presence check for a pending foreign-tx verification request, exposed as a\n view call.\n\n See [`Self::get_pending_request`] for the contract: the returned [`dtos::YieldIndex`]\n is an arbitrary representative of a fan-out queue, not \"the\" yield. Only the\n `Some`/`None` distinction is meaningful.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequest" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/YieldIndex" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_tee_accounts", - "doc": " Returns all accounts that have TEE attestations stored in the contract.\n Note: This includes both current protocol participants and accounts that may have\n submitted TEE information but are not currently part of the active participant set.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/NodeId" - } - } - } - }, - { - "name": "init", - "kind": "call", - "modifiers": [ - "init" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "parameters", - "type_schema": { - "$ref": "#/definitions/GovernanceThresholdParameters" - } - }, - { - "name": "tee_verifier_account_id", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - } - }, - { - "name": "init_config", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/InitConfig" - }, - { - "type": "null" - } - ] - } - } - ] - } - }, - { - "name": "init_running", - "kind": "call", - "modifiers": [ - "init", - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "domains", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig" - } - } - }, - { - "name": "next_domain_id", - "type_schema": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - { - "name": "keyset", - "type_schema": { - "$ref": "#/definitions/Keyset" - } - }, - { - "name": "parameters", - "type_schema": { - "$ref": "#/definitions/GovernanceThresholdParameters" - } - }, - { - "name": "tee_verifier_account_id", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - } - }, - { - "name": "init_config", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/InitConfig" - }, - { - "type": "null" - } - ] - } - } - ] - } - }, - { - "name": "latest_key_version", - "doc": " Key versions refer new versions of the root key that we may choose to generate on cohort\n changes. Older key versions will always work but newer key versions were never held by\n older signers. Newer key versions may also add new security features, like only existing\n within a secure enclave. The signature_scheme parameter specifies which protocol\n we're querying the latest version for. The default is Secp256k1. The default is **NOT**\n to query across all protocols.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "signature_scheme", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/Curve" - }, - { - "type": "null" - } - ] - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - }, - { - "name": "launcher_hash_votes", - "doc": " Returns pending launcher hash votes, may include former participants' votes", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedAccountId" - }, - "uniqueItems": true - } - } - } - }, - { - "name": "migrate", - "doc": " This will be called internally by the contract to migrate the state when a new contract\n is deployed. This function should be changed every time state is changed to do the proper\n migrate flow.\n\n If nothing is changed, then this function will just return the current state. If it fails\n to read the state, then it will return an error.", - "kind": "call", - "modifiers": [ - "init", - "private" - ] - }, - { - "name": "migration_info", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/MigrationInfo" - } - } - }, - { - "name": "mpc_node_manifest_digest_votes", - "doc": " Returns pending MPC node manifest digest votes, may include former participants' votes", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedAccountId" - }, - "uniqueItems": true - } - } - } - }, - { - "name": "os_measurement_votes", - "doc": " Returns pending OS measurement votes, may include former participants' votes", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedAccountId" - }, - "uniqueItems": true - } - } - } - }, - { - "name": "prepay_attestation_storage", - "doc": " Buys `grants` attestation-storage grants for `account_id`.\n\n Permissionless, which is what lets an operator fund a node whose function-call key\n cannot attach a deposit. Requires exactly the fee times `grants`; no refunds, no\n withdrawal.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "account_id", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - } - }, - { - "name": "grants", - "type_schema": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "public_key", - "doc": " This is the root public key combined from all the public keys of the participants.\n The domain parameter specifies which domain we're querying the public key for;\n the default is the first domain.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "domain_id", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/DomainId" - }, - { - "type": "null" - } - ] - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PublicKey" - } - } - }, - { - "name": "register_backup_service", - "doc": " Registers or updates the backup service information for the caller account.\n\n The caller (`signer_account_id`) must be an existing or prospective participant.\n Otherwise, the transaction will fail.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "backup_service_info", - "type_schema": { - "$ref": "#/definitions/BackupServiceInfo" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "register_foreign_chains_config", - "doc": " (Re)registers the foreign chains this node currently covers.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "foreign_chains_config", - "type_schema": { - "$ref": "#/definitions/ForeignChainsConfig" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "remove_contract_update_vote", - "doc": " Withdraws the caller's update vote.", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "remove_non_participant_contract_update_votes", - "doc": " Removes update votes from non-participants.\n Can only be called by participants or by the contract itself.", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "remove_non_participant_tee_verifier_votes", - "doc": " Private endpoint to drop verifier-change votes cast by non-participants\n after resharing.", - "kind": "call", - "modifiers": [ - "private" - ], - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "request_app_private_key", - "doc": " The derived key is fully determined by the calling account id (taken\n implicitly from the predecessor), the derivation path and the domain —\n no other account can obtain the same key. `app_public_key` does not\n influence the derived key: it is a caller-chosen ephemeral key the\n response is encrypted to; see [`dtos::CKDResponse`] for the encryption\n layout and how to decrypt.\n\n To avoid overloading the network with too many requests,\n we ask for a small deposit for each ckd request.\n\n Note: identity points are accepted in\n [`AppPublicKeyPV`](near_mpc_contract_interface::types::CKDAppPublicKey::AppPublicKeyPV)\n to support use cases\n where the derived key is intentionally public (no encryption).", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequestArgs" - } - } - ] - } - }, - { - "name": "resolve_verification", - "doc": " Verify-quote callback: on a verifier verdict it runs the post-DCAP checks and stores the\n attestation, consuming one attestation-storage grant if the entry is new. On any failure\n it fails the submitter's transaction.", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "borsh", - "args": [ - { - "name": "context", - "type_schema": { - "declaration": "VerificationContext", - "definitions": { - "()": { - "Primitive": 0 - }, - "AccountId": { - "Struct": [ - "String" - ] - }, - "Ed25519PublicKey": { - "Struct": [ - "[u8; 32]" - ] - }, - "EventLog": { - "Struct": [ - [ - "imr", - "u32" - ], - [ - "event_type", - "u32" - ], - [ - "digest", - "HexBytes<48>" - ], - [ - "event", - "String" - ], - [ - "event_payload", - "String" - ] - ] - }, - "HexBytes<32>": { - "Struct": [ - "[u8; 32]" - ] - }, - "HexBytes<48>": { - "Struct": [ - "[u8; 48]" - ] - }, - "NodeId": { - "Struct": [ - [ - "account_id", - "AccountId" - ], - [ - "tls_public_key", - "Ed25519PublicKey" - ], - [ - "account_public_key", - "Ed25519PublicKey" - ] - ] - }, - "Option>": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "None", - "()" - ], - [ - 1, - "Some", - "HexBytes<32>" - ] - ] - } - }, - "String": { - "Sequence": { - "length_width": 4, - "length_range": { - "start": 0, - "end": 4294967295 - }, - "elements": "u8" - } - }, - "TcbInfo": { - "Struct": [ - [ - "mrtd", - "HexBytes<48>" - ], - [ - "rtmr0", - "HexBytes<48>" - ], - [ - "rtmr1", - "HexBytes<48>" - ], - [ - "rtmr2", - "HexBytes<48>" - ], - [ - "rtmr3", - "HexBytes<48>" - ], - [ - "os_image_hash", - "Option>" - ], - [ - "compose_hash", - "HexBytes<32>" - ], - [ - "device_id", - "HexBytes<32>" - ], - [ - "app_compose", - "String" - ], - [ - "event_log", - "Vec" - ] - ] - }, - "Vec": { - "Sequence": { - "length_width": 4, - "length_range": { - "start": 0, - "end": 4294967295 - }, - "elements": "EventLog" - } - }, - "VerificationContext": { - "Struct": [ - [ - "node_id", - "NodeId" - ], - [ - "tcb_info", - "TcbInfo" - ] - ] - }, - "[u8; 32]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 32, - "end": 32 - }, - "elements": "u8" - } - }, - "[u8; 48]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 48, - "end": 48 - }, - "elements": "u8" - } - }, - "u32": { - "Primitive": 4 - }, - "u8": { - "Primitive": 1 - } - } - } - } - ] - }, - "callbacks": [ - { - "serialization_type": "borsh", - "type_schema": { - "declaration": "VerificationResult", - "definitions": { - "EnclaveReport": { - "Struct": [ - [ - "cpu_svn", - "[u8; 16]" - ], - [ - "misc_select", - "u32" - ], - [ - "reserved1", - "[u8; 28]" - ], - [ - "attributes", - "[u8; 16]" - ], - [ - "mr_enclave", - "[u8; 32]" - ], - [ - "reserved2", - "[u8; 32]" - ], - [ - "mr_signer", - "[u8; 32]" - ], - [ - "reserved3", - "[u8; 96]" - ], - [ - "isv_prod_id", - "u16" - ], - [ - "isv_svn", - "u16" - ], - [ - "reserved4", - "[u8; 60]" - ], - [ - "report_data", - "[u8; 64]" - ] - ] - }, - "Report": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "SgxEnclave", - "Report__SgxEnclave" - ], - [ - 1, - "TD10", - "Report__TD10" - ], - [ - 2, - "TD15", - "Report__TD15" - ], - [ - 3, - "TD15Ex", - "Report__TD15Ex" - ] - ] - } - }, - "Report__SgxEnclave": { - "Struct": [ - "EnclaveReport" - ] - }, - "Report__TD10": { - "Struct": [ - "TDReport10" - ] - }, - "Report__TD15": { - "Struct": [ - "TDReport15" - ] - }, - "Report__TD15Ex": { - "Struct": [ - "TDReport15Ex" - ] - }, - "String": { - "Sequence": { - "length_width": 4, - "length_range": { - "start": 0, - "end": 4294967295 - }, - "elements": "u8" - } - }, - "TDReport10": { - "Struct": [ - [ - "tee_tcb_svn", - "[u8; 16]" - ], - [ - "mr_seam", - "[u8; 48]" - ], - [ - "mr_signer_seam", - "[u8; 48]" - ], - [ - "seam_attributes", - "[u8; 8]" - ], - [ - "td_attributes", - "[u8; 8]" - ], - [ - "xfam", - "[u8; 8]" - ], - [ - "mr_td", - "[u8; 48]" - ], - [ - "mr_config_id", - "[u8; 48]" - ], - [ - "mr_owner", - "[u8; 48]" - ], - [ - "mr_owner_config", - "[u8; 48]" - ], - [ - "rt_mr0", - "[u8; 48]" - ], - [ - "rt_mr1", - "[u8; 48]" - ], - [ - "rt_mr2", - "[u8; 48]" - ], - [ - "rt_mr3", - "[u8; 48]" - ], - [ - "report_data", - "[u8; 64]" - ] - ] - }, - "TDReport15": { - "Struct": [ - [ - "base", - "TDReport10" - ], - [ - "tee_tcb_svn2", - "[u8; 16]" - ], - [ - "mr_service_td", - "[u8; 48]" - ] - ] - }, - "TDReport15Ex": { - "Struct": [ - [ - "base", - "TDReport15" - ], - [ - "vmid", - "u8" - ], - [ - "td_id", - "[u8; 32]" - ], - [ - "dev_info", - "[u8; 48]" - ], - [ - "init_service_td_hash", - "[u8; 48]" - ], - [ - "init_service_td_attributes", - "[u8; 8]" - ], - [ - "init_cpu_svn", - "[u8; 16]" - ], - [ - "init_tee_tcb_svn", - "[u8; 16]" - ], - [ - "init_tee_fmspc", - "[u8; 12]" - ], - [ - "cur_service_td_hash", - "[u8; 48]" - ], - [ - "cur_service_td_attributes", - "[u8; 8]" - ] - ] - }, - "TcbStatus": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "UpToDate", - "TcbStatus__UpToDate" - ], - [ - 1, - "OutOfDateConfigurationNeeded", - "TcbStatus__OutOfDateConfigurationNeeded" - ], - [ - 2, - "OutOfDate", - "TcbStatus__OutOfDate" - ], - [ - 3, - "ConfigurationAndSWHardeningNeeded", - "TcbStatus__ConfigurationAndSWHardeningNeeded" - ], - [ - 4, - "ConfigurationNeeded", - "TcbStatus__ConfigurationNeeded" - ], - [ - 5, - "SWHardeningNeeded", - "TcbStatus__SWHardeningNeeded" - ], - [ - 6, - "Revoked", - "TcbStatus__Revoked" - ], - [ - 7, - "TDRelaunchAdvised", - "TcbStatus__TDRelaunchAdvised" - ], - [ - 8, - "TDRelaunchAdvisedConfigurationNeeded", - "TcbStatus__TDRelaunchAdvisedConfigurationNeeded" - ] - ] - } - }, - "TcbStatusWithAdvisory": { - "Struct": [ - [ - "status", - "TcbStatus" - ], - [ - "advisory_ids", - "Vec" - ] - ] - }, - "TcbStatus__ConfigurationAndSWHardeningNeeded": { - "Struct": null - }, - "TcbStatus__ConfigurationNeeded": { - "Struct": null - }, - "TcbStatus__OutOfDate": { - "Struct": null - }, - "TcbStatus__OutOfDateConfigurationNeeded": { - "Struct": null - }, - "TcbStatus__Revoked": { - "Struct": null - }, - "TcbStatus__SWHardeningNeeded": { - "Struct": null - }, - "TcbStatus__TDRelaunchAdvised": { - "Struct": null - }, - "TcbStatus__TDRelaunchAdvisedConfigurationNeeded": { - "Struct": null - }, - "TcbStatus__UpToDate": { - "Struct": null - }, - "Vec": { - "Sequence": { - "length_width": 4, - "length_range": { - "start": 0, - "end": 4294967295 - }, - "elements": "String" - } - }, - "Vec": { - "Sequence": { - "length_width": 4, - "length_range": { - "start": 0, - "end": 4294967295 - }, - "elements": "u8" - } - }, - "VerificationResult": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "Verified", - "VerificationResult__Verified" - ], - [ - 1, - "Rejected", - "VerificationResult__Rejected" - ] - ] - } - }, - "VerificationResult__Rejected": { - "Struct": [ - "VerifierError" - ] - }, - "VerificationResult__Verified": { - "Struct": [ - "VerifiedReport" - ] - }, - "VerifiedReport": { - "Struct": [ - [ - "status", - "String" - ], - [ - "advisory_ids", - "Vec" - ], - [ - "report", - "Report" - ], - [ - "ppid", - "Vec" - ], - [ - "qe_status", - "TcbStatusWithAdvisory" - ], - [ - "platform_status", - "TcbStatusWithAdvisory" - ] - ] - }, - "VerifierError": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "DcapVerification", - "VerifierError__DcapVerification" - ] - ] - } - }, - "VerifierError__DcapVerification": { - "Struct": [ - "String" - ] - }, - "[u8; 12]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 12, - "end": 12 - }, - "elements": "u8" - } - }, - "[u8; 16]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 16, - "end": 16 - }, - "elements": "u8" - } - }, - "[u8; 28]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 28, - "end": 28 - }, - "elements": "u8" - } - }, - "[u8; 32]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 32, - "end": 32 - }, - "elements": "u8" - } - }, - "[u8; 48]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 48, - "end": 48 - }, - "elements": "u8" - } - }, - "[u8; 60]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 60, - "end": 60 - }, - "elements": "u8" - } - }, - "[u8; 64]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 64, - "end": 64 - }, - "elements": "u8" - } - }, - "[u8; 8]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 8, - "end": 8 - }, - "elements": "u8" - } - }, - "[u8; 96]": { - "Sequence": { - "length_width": 0, - "length_range": { - "start": 96, - "end": 96 - }, - "elements": "u8" - } - }, - "u16": { - "Primitive": 2 - }, - "u32": { - "Primitive": 4 - }, - "u8": { - "Primitive": 1 - } - } - } - } - ], - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueNull" - } - } - }, - { - "name": "respond", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignatureRequest" - } - }, - { - "name": "response", - "type_schema": { - "$ref": "#/definitions/SignatureResponse" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "respond_ckd", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequest" - } - }, - { - "name": "response", - "type_schema": { - "$ref": "#/definitions/CKDResponse" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "respond_verify_foreign_tx", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequest" - } - }, - { - "name": "response", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionResponse" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "return_ck_and_clean_state_on_success", - "doc": " Yield-resume callback for a single queued CKD request.\n\n On success, returns the confidential key to the original caller. On timeout,\n pops this yield's slot (the head of the FIFO fan-out queue) from the\n pending-request map and fires `fail_on_timeout` to fail the original\n transaction. Sibling yields queued under the same request key remain pending\n and are cleaned up by their own timeouts (or drained together by a subsequent\n `respond_ckd`).", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequest" - } - } - ] - }, - "callbacks": [ - { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/CKDResponse" - } - } - ], - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueCKDResponse" - } - } - }, - { - "name": "return_signature_and_clean_state_on_success", - "doc": " Yield-resume callback for a single queued `sign` request.\n\n On success, returns the signature to the original caller. On timeout, pops this\n yield's slot (the head of the FIFO fan-out queue) from the pending-request map\n and fires `fail_on_timeout` to fail the original transaction. Sibling yields\n queued under the same request key remain pending and are cleaned up by their\n own timeouts (or drained together by a subsequent `respond`).", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignatureRequest" - } - } - ] - }, - "callbacks": [ - { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/SignatureResponse" - } - } - ], - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueSignatureResponse" - } - } - }, - { - "name": "return_verify_foreign_tx_and_clean_state_on_success", - "doc": " Yield-resume callback for a single queued foreign-tx verification request.\n\n On success, returns the verification response to the original caller. On\n timeout, pops this yield's slot (the head of the FIFO fan-out queue) from the\n pending-request map and fires `fail_on_timeout` to fail the original\n transaction. Sibling yields queued under the same request key remain pending\n and are cleaned up by their own timeouts (or drained together by a subsequent\n `respond_verify_foreign_tx`).", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequest" - } - } - ] - }, - "callbacks": [ - { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionResponse" - } - } - ], - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueVerifyForeignTransactionResponse" - } - } - }, - { - "name": "sign", - "doc": " `key_version` must be less than or equal to the value at `latest_key_version`\n To avoid overloading the network with too many requests,\n we ask for a small deposit for each signature request.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignRequestArgs" - } - } - ] - } - }, - { - "name": "start_keygen_instance", - "doc": " Starts a new attempt to generate a key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "start_node_migration", - "doc": " Sets the destination node for the calling account.\n\n This function can only be called while the protocol is in a [`Running`](ProtocolContractState::Running) state.\n The signer must be a current participant of the current epoch, otherwise an error is returned.\n On success, the provided [`DestinationNodeInfo`](dtos::DestinationNodeInfo) is stored in the contract state\n under the signer’s account ID.\n\n # Errors\n - [`InvalidState::ProtocolStateNotRunning`] if the protocol is not in the [`Running`](ProtocolContractState::Running) state.\n - [`InvalidState::NotParticipant`] if the signer is not a current participant.\n - [`NodeMigrationError::TlsKeyAlreadyClaimed`](crate::errors::NodeMigrationError::TlsKeyAlreadyClaimed) if the destination node's TLS\n public key belongs to another account.\n - [`NodeMigrationError::DestinationTlsKeyUnchanged`](crate::errors::NodeMigrationError::DestinationTlsKeyUnchanged) if the destination node reuses the\n signer's current TLS public key. Use [`Self::update_participant_url`] to change only the url.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "destination_node_info", - "type_schema": { - "$ref": "#/definitions/DestinationNodeInfo" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "start_reshare_instance", - "doc": " Starts a new attempt to reshare the key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "state", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/ProtocolContractState" - } - } - }, - { - "name": "submit_contract_update", - "doc": " Submits an update and applies it. Fails if the update doesn't yet have enough\n participant votes.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "borsh", - "args": [ - { - "name": "update", - "type_schema": { - "declaration": "Update", - "definitions": { - "Config": { - "Struct": [ - [ - "key_event_timeout_blocks", - "u64" - ], - [ - "tee_upgrade_deadline_duration_seconds", - "u64" - ], - [ - "apply_contract_update_tera_gas", - "u64" - ], - [ - "sign_call_gas_attachment_requirement_tera_gas", - "u64" - ], - [ - "ckd_call_gas_attachment_requirement_tera_gas", - "u64" - ], - [ - "return_signature_and_clean_state_on_success_call_tera_gas", - "u64" - ], - [ - "return_ck_and_clean_state_on_success_call_tera_gas", - "u64" - ], - [ - "fail_on_timeout_tera_gas", - "u64" - ], - [ - "fail_attestation_submission_tera_gas", - "u64" - ], - [ - "clean_tee_status_tera_gas", - "u64" - ], - [ - "clean_invalid_attestations_tera_gas", - "u64" - ], - [ - "cleanup_orphaned_node_migrations_tera_gas", - "u64" - ], - [ - "remove_non_participant_update_votes_tera_gas", - "u64" - ], - [ - "clean_foreign_chain_data_tera_gas", - "u64" - ], - [ - "remove_non_participant_tee_verifier_votes_tera_gas", - "u64" - ], - [ - "verifier_tera_gas", - "u64" - ], - [ - "resolve_verification_tera_gas", - "u64" - ], - [ - "launcher_hash_unused_ttl_seconds", - "u64" - ], - [ - "attestation_storage_fee_millinear", - "u64" - ] - ] - }, - "Update": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "Code", - "Update__Code" - ], - [ - 1, - "Config", - "Update__Config" - ] - ] - } - }, - "Update__Code": { - "Struct": [ - "Vec" - ] - }, - "Update__Config": { - "Struct": [ - "Config" - ] - }, - "Vec": { - "Sequence": { - "length_width": 4, - "length_range": { - "start": 0, - "end": 4294967295 - }, - "elements": "u8" - } - }, - "u64": { - "Primitive": 8 - }, - "u8": { - "Primitive": 1 - } - } - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "submit_participant_info", - "doc": " Submit a TEE attestation for a current or prospective participant.\n\n - [`Attestation::Mock`] is verified synchronously.\n - [`Attestation::Dstack`] is verified asynchronously via a cross-contract\n `verify_quote` call, with [`Self::resolve_verification`] chained as its\n callback to run the post-DCAP checks and store the attestation.\n\n A node submits with no deposit via its function-call access key. Storing a *new* entry\n consumes one attestation-storage grant, prepaid for the node's account by whoever\n onboards it; a re-attestation under a key the account already owns consumes none.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "proposed_participant_attestation", - "type_schema": { - "$ref": "#/definitions/Attestation" - } - }, - { - "name": "tls_public_key", - "type_schema": { - "$ref": "#/definitions/Ed25519PublicKey" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueNull" - } - } - }, - { - "name": "tee_verifier_account_id", - "doc": " Returns the trusted TEE verifier contract account, set at init and\n changed via [`Self::vote_tee_verifier_change`].", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - } - } - }, - { - "name": "tee_verifier_votes", - "doc": " Returns the pending TEE verifier-change votes, keyed by proposal.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedParticipantId" - }, - "uniqueItems": true - } - } - } - }, - { - "name": "update_config", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "config", - "type_schema": { - "$ref": "#/definitions/Config" - } - } - ] - } - }, - { - "name": "update_participant_url", - "doc": " Updates the calling participant's registered URL, keeping the TLS key and participant ID.\n\n Requires a deposit of at least [`MINIMUM_NODE_MANAGEMENT_DEPOSIT`] (excess is refunded), so\n the call must be signed by a full-access key rather than the node's function-call access\n key.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "url", - "type_schema": { - "$ref": "#/definitions/BoundedString_256" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "verify_foreign_transaction", - "doc": " Submit a verification + signing request for a foreign chain transaction.\n MPC nodes will verify the transaction on the foreign chain before signing.\n The signed payload is derived from the transaction ID (hash of tx_id).", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequestArgs" - } - } - ] - } - }, - { - "name": "verify_tee", - "doc": " Verifies if all current participants have an accepted TEE state.\n Automatically enters a resharing, in case one or more participants do not have an accepted\n TEE state.\n Returns `false` and stops the contract from accepting new signature requests or responses,\n in case the participants running in an accepted TEE State are too few for the\n GovernanceThreshold or for any domain's signing protocol.\n Also retires launcher hashes that no current participant uses (see\n [`dtos::Config::launcher_hash_unused_ttl_seconds`]).", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "boolean" - } - } - }, - { - "name": "version", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "string" - } - } - }, - { - "name": "vote_abort_key_event_instance", - "doc": " Casts a vote to abort the current key event instance. If succesful, the contract aborts the\n instance and a new instance with the next attempt_id can be started.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_add_domains", - "doc": " Propose adding a new set of domains for the MPC network.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Initializing state to generate keys for the new domains.\n\n The specified list of domains must have increasing and contiguous IDs, and the first ID\n must be the same as the `next_domain_id` returned by state().", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "domains", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig" - } - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_add_launcher_hash", - "doc": " Vote to add a new launcher image hash to the allowed set. Requires threshold votes.\n When the threshold is reached, compose hashes are automatically derived for all\n currently allowed MPC image hashes.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "launcher_hash", - "type_schema": { - "$ref": "#/definitions/LauncherImageHash" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_add_os_measurement", - "doc": " Vote to add a new OS measurement set to the allowed list. Requires threshold votes.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "measurement", - "type_schema": { - "$ref": "#/definitions/ExpectedMeasurements" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_cancel_keygen", - "doc": " Casts a vote to cancel key generation. Any keys that have already been generated\n are kept and we transition into Running state; remaining domains are permanently deleted.\n Deleted domain IDs cannot be reused again in future calls to vote_add_domains.\n\n A next_domain_id that matches that in the state's domains struct must be passed in. This is\n to prevent stale requests from accidentally cancelling a future key generation state.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "next_domain_id", - "type_schema": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_cancel_resharing", - "doc": " Casts a vote to cancel the current key resharing. If a threshold number of unique\n votes are collected to cancel the resharing, the contract state will revert back to the\n previous running state.\n\n - This method is idempotent, meaning a single account can not make more than one vote.\n - Only nodes from the previous running state are allowed to vote.\n\n Return value:\n - [Ok] if the vote was successfully collected.\n - [Err] if:\n - The signer is not a participant in the previous running state.\n - The contract is not in a resharing state.", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_contract_update", - "doc": " Replaces the caller's earlier vote, if any. Returns whether `update_hash` is approved.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "update_hash", - "type_schema": { - "$ref": "#/definitions/UpdateHash" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "boolean" - } - } - }, - { - "name": "vote_mpc_node_manifest_digest", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "mpc_node_manifest_digest", - "type_schema": { - "$ref": "#/definitions/DockerImageHash" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_new_parameters", - "doc": " Propose new parameters for the MPC network: participants, governance\n threshold, and optional per-domain\n [`ReconstructionThreshold`](near_mpc_contract_interface::types::ReconstructionThreshold) updates\n (empty map keeps the current ones), applied on resharing completion.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Resharing state.\n\n The epoch_id must be equal to 1 plus the current epoch ID (if Running) or prospective epoch\n ID (if Resharing). Otherwise the vote is ignored. This is to prevent late transactions from\n accidentally voting on outdated proposals.\n\n Like the other governance voting methods, this must be called directly from the\n participant's own NEAR account: [`assert_caller_is_signer()`](MpcContract::assert_caller_is_signer) requires\n `signer_account_id == predecessor_account_id`, so calls forwarded through another\n contract are rejected.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "prospective_epoch_id", - "type_schema": { - "$ref": "#/definitions/EpochId" - } - }, - { - "name": "proposal", - "type_schema": { - "$ref": "#/definitions/ProposedGovernanceThresholdParameters" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_pk", - "doc": " Casts a vote for `public_key` for the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key generation\n attempt (including if the attempt timed out), if the signer is not a participant, or if\n the key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key generation attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - This vote is for a public key that disagrees from an earlier voted public key, causing\n the attempt to abort; another call to `start` is then necessary.\n - Everyone has now voted for the same public key; the state transitions into generating a\n key for the next domain.\n - Same as the last case, except that all domains have a generated key now, and the state\n transitions into Running with the newly generated keys.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - }, - { - "name": "public_key", - "type_schema": { - "$ref": "#/definitions/PublicKey" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_remove_launcher_hash", - "doc": " Vote to remove a launcher image hash from the allowed set. Requires ALL participants\n to vote for removal, since this invalidates attestations of nodes running that launcher.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "launcher_hash", - "type_schema": { - "$ref": "#/definitions/LauncherImageHash" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_remove_os_measurement", - "doc": " Vote to remove an OS measurement set from the allowed list. Requires ALL participants\n to vote for removal.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "measurement", - "type_schema": { - "$ref": "#/definitions/ExpectedMeasurements" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_reshared", - "doc": " Casts a vote for the successful resharing of the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key resharing attempt\n (including if the attempt timed out), if the signer is not a participant, or if the\n key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key resharing attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - Everyone has now voted; the state transitions into resharing the key for the next\n domain.\n - Same as the last case, except that all domains' keys have been reshared now, and the\n state transitions into Running with the newly reshared keys.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_tee_verifier_change", - "doc": " Vote for a candidate account to become the trusted verifier contract\n account, committing to the code hash the voter audited. When the proposal\n crosses the governance threshold, the trusted verifier account is updated\n and all pending verifier-change votes are cleared.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "candidate_account_id", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - } - }, - { - "name": "expected_code_hash", - "type_schema": { - "$ref": "#/definitions/TeeVerifierCodeHash" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_update_foreign_chain_providers", - "doc": " Vote on per-chain RPC provider whitelist state. The input is keyed by\n [`ForeignChain`](dtos::ForeignChain); each [`ChainEntry`](dtos::ChainEntry) value carries the proposed full provider list\n and the RPC response quorum for that chain. The chain's stored state is replaced\n once the protocol's signing threshold of participants has voted the same\n `(providers, quorum)` pair. [`NonEmptyBTreeMap`](near_mpc_bounded_collections::NonEmptyBTreeMap) enforces a non-empty batch and\n at-most-one entry per chain at deserialize time.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "votes", - "type_schema": { - "$ref": "#/definitions/NonEmptyBTreeMap_ForeignChain_ChainEntry" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ForeignChain" - } - } - } - }, - { - "name": "withdraw_tee_verifier_vote", - "doc": " Withdraw the caller's current vote on any pending verifier-change\n proposal. No-op if the caller has not voted.", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - } - ], - "root_schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "String", - "type": "string", - "definitions": { - "AddDomainsVotes": { - "description": "Votes for adding new domains.", - "type": "object", - "required": [ - "proposal_by_account" - ], - "properties": { - "proposal_by_account": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig" - } - } - } - } - }, - "AllowedMpcDockerImageHash": { - "type": "object", - "required": [ - "image_hash" - ], - "properties": { - "expiry_timestamp_seconds": { - "description": "block-time at which this hash is evicted from the allowlist. None if expiration date is not yet known.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "image_hash": { - "$ref": "#/definitions/DockerImageHash" - } - } - }, - "AptosExtractor": { - "oneOf": [ - { - "type": "object", - "required": [ - "Event" - ], - "properties": { - "Event": { - "type": "object", - "required": [ - "event_index" - ], - "properties": { - "event_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "AptosFinality": { - "type": "string", - "enum": [ - "Committed" - ] - }, - "AptosRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "$ref": "#/definitions/BoundedVec_AptosExtractor_Min0_Max32" - }, - "finality": { - "$ref": "#/definitions/AptosFinality" - }, - "tx_id": { - "$ref": "#/definitions/AptosTxId" - } - } - }, - "AptosTxId": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "AttemptId": { - "description": "Attempt identifier within a key event. Incremented for each attempt within the same epoch and domain.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "Attestation": { - "oneOf": [ - { - "type": "object", - "required": [ - "Dstack" - ], - "properties": { - "Dstack": { - "$ref": "#/definitions/DstackAttestation" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Mock" - ], - "properties": { - "Mock": { - "$ref": "#/definitions/MockAttestation" - } - }, - "additionalProperties": false - } - ] - }, - "AuthScheme": { - "description": "Where the operator's API key/token gets injected into the assembled RPC URL. Lives on the contract (not in operator yaml) so the operator can't pick a custom auth shape that lets them inject extra path or query components.", - "oneOf": [ - { - "description": "Token sent in an HTTP header (e.g. `Authorization: Bearer `).", - "type": "object", - "required": [ - "Header" - ], - "properties": { - "Header": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string" - }, - "scheme": { - "type": [ - "string", - "null" - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Token substituted into a `{placeholder}` in the URL path.", - "type": "object", - "required": [ - "Path" - ], - "properties": { - "Path": { - "type": "object", - "required": [ - "placeholder" - ], - "properties": { - "placeholder": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Token sent as a query parameter (`?=`).", - "type": "object", - "required": [ - "Query" - ], - "properties": { - "Query": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Public endpoint, no auth.", - "type": "string", - "enum": [ - "None" - ] - } - ] - }, - "AuthenticatedAccountId": { - "description": "An account ID that has been authenticated (i.e., the caller is this account).", - "type": "string" - }, - "AuthenticatedParticipantId": { - "description": "A participant ID that has been authenticated (i.e., the caller is this participant).", - "allOf": [ - { - "$ref": "#/definitions/ParticipantId" - } - ] - }, - "AvailableForeignChains": { - "description": "The set of foreign chains available across the threshold of active participants. Returned by `get_available_foreign_chains`; computed from the per-node [`ForeignChainsConfig`] reports.", - "type": "array", - "items": { - "$ref": "#/definitions/ForeignChain" - }, - "uniqueItems": true - }, - "BackupServiceInfo": { - "type": "object", - "required": [ - "public_key" - ], - "properties": { - "public_key": { - "$ref": "#/definitions/Ed25519PublicKey" - } - } - }, - "BitcoinExtractor": { - "type": "string", - "enum": [ - "BlockHash" - ] - }, - "BitcoinRpcRequest": { - "type": "object", - "required": [ - "confirmations", - "extractors", - "tx_id" - ], - "properties": { - "confirmations": { - "$ref": "#/definitions/BlockConfirmations" - }, - "extractors": { - "$ref": "#/definitions/BoundedVec_BitcoinExtractor_Min0_Max32" - }, - "tx_id": { - "$ref": "#/definitions/BitcoinTxId" - } - } - }, - "BitcoinTxId": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "BlockConfirmations": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "Bls12381G1PublicKey": { - "type": "string" - }, - "Bls12381G2PublicKey": { - "type": "string" - }, - "BoundedString_256": { - "type": "string" - }, - "BoundedVec_AptosExtractor_Min0_Max32": { - "type": "array", - "items": { - "$ref": "#/definitions/AptosExtractor" - }, - "maxItems": 32, - "minItems": 0 - }, - "BoundedVec_BitcoinExtractor_Min0_Max32": { - "type": "array", - "items": { - "$ref": "#/definitions/BitcoinExtractor" - }, - "maxItems": 32, - "minItems": 0 - }, - "BoundedVec_EvmExtractor_Min0_Max32": { - "type": "array", - "items": { - "$ref": "#/definitions/EvmExtractor" - }, - "maxItems": 32, - "minItems": 0 - }, - "BoundedVec_StarknetExtractor_Min0_Max32": { - "type": "array", - "items": { - "$ref": "#/definitions/StarknetExtractor" - }, - "maxItems": 32, - "minItems": 0 - }, - "BoundedVec_SuiExtractor_Min0_Max32": { - "type": "array", - "items": { - "$ref": "#/definitions/SuiExtractor" - }, - "maxItems": 32, - "minItems": 0 - }, - "BoundedVec_SvmExtractor_Min0_Max32": { - "type": "array", - "items": { - "$ref": "#/definitions/SvmExtractor" - }, - "maxItems": 32, - "minItems": 0 - }, - "BoundedVec_TonExtractor_Min0_Max32": { - "type": "array", - "items": { - "$ref": "#/definitions/TonExtractor" - }, - "maxItems": 32, - "minItems": 0 - }, - "CKDAppPublicKey": { - "oneOf": [ - { - "type": "object", - "required": [ - "AppPublicKey" - ], - "properties": { - "AppPublicKey": { - "$ref": "#/definitions/Bls12381G1PublicKey" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "AppPublicKeyPV" - ], - "properties": { - "AppPublicKeyPV": { - "$ref": "#/definitions/CKDAppPublicKeyPV" - } - }, - "additionalProperties": false - } - ] - }, - "CKDAppPublicKeyPV": { - "type": "object", - "required": [ - "pk1", - "pk2" - ], - "properties": { - "pk1": { - "$ref": "#/definitions/Bls12381G1PublicKey" - }, - "pk2": { - "$ref": "#/definitions/Bls12381G2PublicKey" - } - } - }, - "CKDRequest": { - "description": "A CKD request as tracked by the contract, with the app id already derived from the caller's account id and derivation path via [`derive_app_id`](crate::kdf::derive_app_id).", - "type": "object", - "required": [ - "app_id", - "app_public_key", - "domain_id" - ], - "properties": { - "app_id": { - "$ref": "#/definitions/CkdAppId" - }, - "app_public_key": { - "$ref": "#/definitions/CKDAppPublicKey" - }, - "domain_id": { - "$ref": "#/definitions/DomainId" - } - } - }, - "CKDRequestArgs": { - "type": "object", - "required": [ - "app_public_key", - "derivation_path", - "domain_id" - ], - "properties": { - "app_public_key": { - "description": "Public key used to encrypt the response. Can be chosen independently for each request and does not affect the derived key.", - "allOf": [ - { - "$ref": "#/definitions/CKDAppPublicKey" - } - ] - }, - "derivation_path": { - "description": "Identifies the derived key. The key is determined by the caller's account ID and this derivation path. Different paths produce different keys.", - "type": "string" - }, - "domain_id": { - "description": "Identifies the CKD domain used to derive the key.", - "allOf": [ - { - "$ref": "#/definitions/DomainId" - } - ] - } - } - }, - "CKDResponse": { - "description": "Response to a CKD request: the derived key, ElGamal-encrypted to the request's app public key (`pk1` in the publicly-verifiable variant).\n\nFor an app key pair `(a, A = a·G1)` and an ephemeral scalar `y` chosen by the MPC network, `big_y` holds `Y = y·G1` and `big_c` holds `C = derived_key + y·A`; decrypt with `derived_key = C - a·Y`. The derived key is a BLS signature on the app id under the domain's public key; verify it as such before use. Neither field is a public key: the field type is reused for its 48-byte compressed G1 point encoding.", - "type": "object", - "required": [ - "big_c", - "big_y" - ], - "properties": { - "big_c": { - "$ref": "#/definitions/Bls12381G1PublicKey" - }, - "big_y": { - "$ref": "#/definitions/Bls12381G1PublicKey" - } - } - }, - "ChainEntry": { - "description": "Stored state for one chain in the on-chain whitelist: a non-empty map from [`ProviderId`] to that provider's per-chain configuration, plus the voted RPC response quorum. Returned by the `allowed_foreign_chain_providers` view fn. [`NonEmptyBTreeMap`] enforces a non-empty provider set and at-most-one entry per [`ProviderId`] at deserialize time, and the map iterates in [`ProviderId`] order — so the canonical hash matches across voters without an explicit sort step.", - "type": "object", - "required": [ - "providers", - "quorum" - ], - "properties": { - "providers": { - "$ref": "#/definitions/NonEmptyBTreeMap_ProviderId_ProviderConfig" - }, - "quorum": { - "description": "Voted RPC response quorum. Stored for a deferred quorum policy and not yet consumed: nodes currently require every provider that reaches a verdict to agree on it.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "ChainRouting": { - "description": "How chain identity is encoded in the RPC URL. Exactly one of the three encodings, modelled as an enum so a vote can't accidentally produce an \"all three\" shape.", - "oneOf": [ - { - "description": "Chain identity already encoded in `base_url` (subdomain or path prefix). E.g. Alchemy's `eth-mainnet.g.alchemy.com`, Infura's `mainnet.infura.io`, or any chain-dedicated endpoint.", - "type": "string", - "enum": [ - "Embedded" - ] - }, - { - "description": "Append `segment` after `base_url`'s path. E.g. Ankr Ethereum: `\"eth\"`. `segment` MUST NOT contain `/` (validated when a vote applies).", - "type": "object", - "required": [ - "PathSegment" - ], - "properties": { - "PathSegment": { - "type": "object", - "required": [ - "segment" - ], - "properties": { - "segment": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Merge a single chain-identifying query param into the URL. E.g. dRPC Ethereum: `{ name: \"network\", value: \"ethereum\" }`. When `AuthScheme::Query { name: auth_name }` is used, `name` here MUST differ from `auth_name` (validated when a vote applies).", - "type": "object", - "required": [ - "QueryParam" - ], - "properties": { - "QueryParam": { - "type": "object", - "required": [ - "name", - "value" - ], - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "CkdAppId": { - "description": "AppId for CKD", - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "Collateral": { - "type": "object", - "required": [ - "pck_crl", - "pck_crl_issuer_chain", - "qe_identity", - "qe_identity_issuer_chain", - "qe_identity_signature", - "root_ca_crl", - "tcb_info", - "tcb_info_issuer_chain", - "tcb_info_signature" - ], - "properties": { - "pck_certificate_chain": { - "type": [ - "string", - "null" - ] - }, - "pck_crl": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "pck_crl_issuer_chain": { - "type": "string" - }, - "qe_identity": { - "type": "string" - }, - "qe_identity_issuer_chain": { - "type": "string" - }, - "qe_identity_signature": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "root_ca_crl": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "tcb_info": { - "type": "string" - }, - "tcb_info_issuer_chain": { - "type": "string" - }, - "tcb_info_signature": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - }, - "Config": { - "description": "Configuration parameters of the contract.", - "type": "object", - "required": [ - "apply_contract_update_tera_gas", - "attestation_storage_fee_millinear", - "ckd_call_gas_attachment_requirement_tera_gas", - "clean_foreign_chain_data_tera_gas", - "clean_invalid_attestations_tera_gas", - "clean_tee_status_tera_gas", - "cleanup_orphaned_node_migrations_tera_gas", - "fail_attestation_submission_tera_gas", - "fail_on_timeout_tera_gas", - "key_event_timeout_blocks", - "launcher_hash_unused_ttl_seconds", - "remove_non_participant_tee_verifier_votes_tera_gas", - "remove_non_participant_update_votes_tera_gas", - "resolve_verification_tera_gas", - "return_ck_and_clean_state_on_success_call_tera_gas", - "return_signature_and_clean_state_on_success_call_tera_gas", - "sign_call_gas_attachment_requirement_tera_gas", - "tee_upgrade_deadline_duration_seconds", - "verifier_tera_gas" - ], - "properties": { - "apply_contract_update_tera_gas": { - "description": "Prepaid gas for applying contract and config updates.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "attestation_storage_fee_millinear": { - "description": "Fee, in milliNEAR, for one attestation-storage grant.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "ckd_call_gas_attachment_requirement_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "clean_foreign_chain_data_tera_gas": { - "description": "Prepaid gas for a `clean_foreign_chain_data` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "clean_invalid_attestations_tera_gas": { - "description": "Prepaid gas for the reshare-time `clean_invalid_attestations` promise.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "clean_tee_status_tera_gas": { - "description": "Prepaid gas for a `clean_tee_status` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "cleanup_orphaned_node_migrations_tera_gas": { - "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "fail_attestation_submission_tera_gas": { - "description": "Prepaid gas for a `fail_attestation_submission` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "fail_on_timeout_tera_gas": { - "description": "Prepaid gas for a `fail_on_timeout` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "key_event_timeout_blocks": { - "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "launcher_hash_unused_ttl_seconds": { - "description": "How long a launcher hash that no current participant uses stays allowed after its last vote or the last `verify_tee` that saw it in use. Removal happens only in `verify_tee`, so it can lag this TTL; a hash in use is never removed automatically.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "remove_non_participant_tee_verifier_votes_tera_gas": { - "description": "Prepaid gas for a `remove_non_participant_tee_verifier_votes` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "remove_non_participant_update_votes_tera_gas": { - "description": "Prepaid gas for a `remove_non_participant_contract_update_votes` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "resolve_verification_tera_gas": { - "description": "Prepaid gas for the `resolve_verification` callback.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "return_ck_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "return_signature_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "sign_call_gas_attachment_requirement_tera_gas": { - "description": "Gas required for a sign request.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "tee_upgrade_deadline_duration_seconds": { - "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "verifier_tera_gas": { - "description": "Gas attached to the cross-contract `verify_quote` call on the verifier.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "Curve": { - "description": "Elliptic curve used by a domain.", - "type": "string", - "enum": [ - "Secp256k1", - "Edwards25519", - "Bls12381" - ] - }, - "DestinationNodeInfo": { - "type": "object", - "required": [ - "destination_node_info", - "signer_account_pk" - ], - "properties": { - "destination_node_info": { - "$ref": "#/definitions/ParticipantInfo" - }, - "signer_account_pk": { - "description": "The public key used by the node to sign transactions to the contract. This key is different from the TLS key stored in [`ParticipantInfo::tls_public_key`].", - "allOf": [ - { - "$ref": "#/definitions/Ed25519PublicKey" - } - ] - } - } - }, - "DockerImageHash": { - "type": "string", - "maxLength": 64, - "minLength": 64, - "pattern": "^[0-9a-fA-F]+$" - }, - "DomainConfig": { - "description": "Configuration for a signature domain.", - "type": "object", - "required": [ - "id", - "protocol", - "purpose", - "reconstruction_threshold" - ], - "properties": { - "id": { - "$ref": "#/definitions/DomainId" - }, - "protocol": { - "$ref": "#/definitions/Protocol" - }, - "purpose": { - "$ref": "#/definitions/DomainPurpose" - }, - "reconstruction_threshold": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "DomainId": { - "description": "Each domain corresponds to a specific root key on a specific elliptic curve. There may be multiple domains per curve. The domain ID uniquely identifies a domain.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "DomainPurpose": { - "description": "The purpose that a domain serves.", - "oneOf": [ - { - "description": "Domain is used by `sign()`.", - "type": "string", - "enum": [ - "Sign" - ] - }, - { - "description": "Domain is used by `verify_foreign_transaction()`.", - "type": "string", - "enum": [ - "ForeignTx" - ] - }, - { - "description": "Domain is used by `request_app_private_key()` (Confidential Key Derivation).", - "type": "string", - "enum": [ - "CKD" - ] - } - ] - }, - "DomainRegistry": { - "description": "Registry of all signature domains.", - "type": "object", - "required": [ - "domains", - "next_domain_id" - ], - "properties": { - "domains": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig" - } - }, - "next_domain_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "DstackAttestation": { - "type": "object", - "required": [ - "collateral", - "quote", - "tcb_info" - ], - "properties": { - "collateral": { - "$ref": "#/definitions/Collateral" - }, - "quote": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "tcb_info": { - "$ref": "#/definitions/TcbInfo" - } - } - }, - "Ed25519PublicKey": { - "type": "string" - }, - "Ed25519Signature": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - } - }, - "EpochId": { - "description": "An EpochId uniquely identifies a GovernanceThresholdParameters (but not vice-versa). Every time we change the GovernanceThresholdParameters (participants and threshold), we increment EpochId. Locally on each node, each keyshare is uniquely identified by the tuple (EpochId, DomainId, AttemptId).", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "EventLog": { - "description": "Represents an event log entry in the system", - "type": "object", - "required": [ - "digest", - "event", - "event_payload", - "event_type", - "imr" - ], - "properties": { - "digest": { - "description": "The cryptographic digest of the event", - "type": "string" - }, - "event": { - "description": "The type of event as a string", - "type": "string" - }, - "event_payload": { - "description": "The payload data associated with the event", - "type": "string" - }, - "event_type": { - "description": "The type of event being logged", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "imr": { - "description": "The index of the IMR (Integrity Measurement Register)", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - }, - "EvmExtractor": { - "oneOf": [ - { - "type": "string", - "enum": [ - "BlockHash" - ] - }, - { - "type": "object", - "required": [ - "Log" - ], - "properties": { - "Log": { - "type": "object", - "required": [ - "log_index" - ], - "properties": { - "log_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "EvmFinality": { - "type": "string", - "enum": [ - "Latest", - "Safe", - "Finalized" - ] - }, - "EvmRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "$ref": "#/definitions/BoundedVec_EvmExtractor_Min0_Max32" - }, - "finality": { - "$ref": "#/definitions/EvmFinality" - }, - "tx_id": { - "$ref": "#/definitions/EvmTxId" - } - } - }, - "EvmTxId": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "ExpectedMeasurements": { - "description": "The TDX measurements an attestation is required to match.", - "type": "object", - "required": [ - "key_provider_event_digest", - "mrtd", - "rtmr0", - "rtmr1", - "rtmr2" - ], - "properties": { - "key_provider_event_digest": { - "$ref": "#/definitions/KeyProviderEventDigest" - }, - "mrtd": { - "$ref": "#/definitions/MrtdHash" - }, - "rtmr0": { - "$ref": "#/definitions/Rtmr0Hash" - }, - "rtmr1": { - "$ref": "#/definitions/Rtmr1Hash" - }, - "rtmr2": { - "$ref": "#/definitions/Rtmr2Hash" - } - } - }, - "ForeignChain": { - "type": "string", - "enum": [ - "Solana", - "Bitcoin", - "Ethereum", - "Base", - "Bnb", - "Arbitrum", - "Abstract", - "Starknet", - "Polygon", - "HyperEvm", - "Ton", - "Aptos", - "Sui", - "Avalanche", - "Adi", - "Fogo" - ] - }, - "ForeignChainRpcRequest": { - "oneOf": [ - { - "type": "object", - "required": [ - "Abstract" - ], - "properties": { - "Abstract": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Ethereum" - ], - "properties": { - "Ethereum": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Solana" - ], - "properties": { - "Solana": { - "$ref": "#/definitions/SvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Bitcoin" - ], - "properties": { - "Bitcoin": { - "$ref": "#/definitions/BitcoinRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Starknet" - ], - "properties": { - "Starknet": { - "$ref": "#/definitions/StarknetRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Bnb" - ], - "properties": { - "Bnb": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Base" - ], - "properties": { - "Base": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Arbitrum" - ], - "properties": { - "Arbitrum": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Polygon" - ], - "properties": { - "Polygon": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "HyperEvm" - ], - "properties": { - "HyperEvm": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Ton" - ], - "properties": { - "Ton": { - "$ref": "#/definitions/TonRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Aptos" - ], - "properties": { - "Aptos": { - "$ref": "#/definitions/AptosRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Sui" - ], - "properties": { - "Sui": { - "$ref": "#/definitions/SuiRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Avalanche" - ], - "properties": { - "Avalanche": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Adi" - ], - "properties": { - "Adi": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Fogo" - ], - "properties": { - "Fogo": { - "$ref": "#/definitions/SvmRpcRequest" - } - }, - "additionalProperties": false - } - ] - }, - "ForeignChainsConfig": { - "description": "Set of foreign chains a node reports it can serve; aggregated into [`AvailableForeignChains`] by the contract.", - "type": "array", - "items": { - "$ref": "#/definitions/ForeignChain" - }, - "uniqueItems": true - }, - "ForeignChainsConfigs": { - "description": "Per-node foreign-chain configs, keyed by each node's TLS public key.", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ForeignChainsConfig" - } - }, - "GovernanceThreshold": { - "description": "Network-wide governance threshold (`k`): the minimum number of participants that must agree to approve a governance action (participant set changes, resharing, parameter updates). Distinct from a domain's [`ReconstructionThreshold`], the per-domain `t` needed to reconstruct a key.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "GovernanceThresholdParameters": { - "description": "GovernanceThreshold parameters for distributed key operations: the current participant set and the governance threshold. This is the stored, always-current shape; per-domain reconstruction-threshold *proposals* live on [`ProposedGovernanceThresholdParameters`].", - "type": "object", - "required": [ - "participants", - "threshold" - ], - "properties": { - "participants": { - "$ref": "#/definitions/Participants" - }, - "threshold": { - "$ref": "#/definitions/GovernanceThreshold" - } - } - }, - "Hash256": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "HexString_Min0_Max1232": { - "type": "string", - "maxLength": 2464, - "minLength": 0, - "pattern": "^[0-9a-fA-F]*$" - }, - "HexString_Min32_Max32": { - "type": "string", - "maxLength": 64, - "minLength": 64, - "pattern": "^[0-9a-fA-F]*$" - }, - "InitConfig": { - "description": "The initial configuration parameters for when initializing the contract. All fields are optional, as the contract can fill in defaults for any missing fields.", - "type": "object", - "properties": { - "apply_contract_update_tera_gas": { - "description": "Prepaid gas for applying contract and config updates.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "attestation_storage_fee_millinear": { - "description": "Fee, in milliNEAR, for one attestation-storage grant.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "ckd_call_gas_attachment_requirement_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "clean_foreign_chain_data_tera_gas": { - "description": "Prepaid gas for a `clean_foreign_chain_data` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "clean_invalid_attestations_tera_gas": { - "description": "Prepaid gas for the reshare-time `clean_invalid_attestations` promise.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "clean_tee_status_tera_gas": { - "description": "Prepaid gas for a `clean_tee_status` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "cleanup_orphaned_node_migrations_tera_gas": { - "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "fail_attestation_submission_tera_gas": { - "description": "Prepaid gas for a `fail_attestation_submission` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "fail_on_timeout_tera_gas": { - "description": "Prepaid gas for a `fail_on_timeout` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "key_event_timeout_blocks": { - "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "launcher_hash_unused_ttl_seconds": { - "description": "TTL for launcher hashes no current participant uses; see [`Config::launcher_hash_unused_ttl_seconds`].", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "remove_non_participant_tee_verifier_votes_tera_gas": { - "description": "Prepaid gas for a `remove_non_participant_tee_verifier_votes` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "remove_non_participant_update_votes_tera_gas": { - "description": "Prepaid gas for a `remove_non_participant_contract_update_votes` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "resolve_verification_tera_gas": { - "description": "Prepaid gas for the `resolve_verification` callback.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "return_ck_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "return_signature_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "sign_call_gas_attachment_requirement_tera_gas": { - "description": "Gas required for a sign request.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "tee_upgrade_deadline_duration_seconds": { - "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "verifier_tera_gas": { - "description": "Gas attached to the cross-contract `verify_quote` call on the verifier.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - } - } - }, - "InitializingContractState": { - "description": "State when the contract is generating keys for new domains.", - "type": "object", - "required": [ - "cancel_votes", - "domains", - "epoch_id", - "generated_keys", - "generating_key" - ], - "properties": { - "cancel_votes": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedParticipantId" - }, - "uniqueItems": true - }, - "domains": { - "$ref": "#/definitions/DomainRegistry" - }, - "epoch_id": { - "$ref": "#/definitions/EpochId" - }, - "generated_keys": { - "type": "array", - "items": { - "$ref": "#/definitions/KeyForDomain" - } - }, - "generating_key": { - "$ref": "#/definitions/KeyEvent" - } - } - }, - "K256AffinePoint": { - "description": "AffinePoint on the Secp256k1 curve", - "type": "object", - "required": [ - "affine_point" - ], - "properties": { - "affine_point": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - }, - "K256Scalar": { - "type": "object", - "required": [ - "scalar" - ], - "properties": { - "scalar": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - }, - "KeyEvent": { - "description": "Key generation or resharing event state.", - "type": "object", - "required": [ - "domain", - "epoch_id", - "next_attempt_id", - "parameters" - ], - "properties": { - "domain": { - "$ref": "#/definitions/DomainConfig" - }, - "epoch_id": { - "$ref": "#/definitions/EpochId" - }, - "instance": { - "anyOf": [ - { - "$ref": "#/definitions/KeyEventInstance" - }, - { - "type": "null" - } - ] - }, - "next_attempt_id": { - "$ref": "#/definitions/AttemptId" - }, - "parameters": { - "$ref": "#/definitions/GovernanceThresholdParameters" - } - } - }, - "KeyEventId": { - "description": "A unique identifier for a key event (generation or resharing): `epoch_id`: identifies the GovernanceThresholdParameters that this key is intended to function in. `domain_id`: the domain this key is intended for. `attempt_id`: identifies a particular attempt for this key event, in case multiple attempts yielded partially valid results. This is incremented for each attempt within the same epoch and domain.", - "type": "object", - "required": [ - "attempt_id", - "domain_id", - "epoch_id" - ], - "properties": { - "attempt_id": { - "$ref": "#/definitions/AttemptId" - }, - "domain_id": { - "$ref": "#/definitions/DomainId" - }, - "epoch_id": { - "$ref": "#/definitions/EpochId" - } - } - }, - "KeyEventInstance": { - "description": "State of a key generation/resharing instance.", - "type": "object", - "required": [ - "attempt_id", - "completed", - "expires_on", - "started_in" - ], - "properties": { - "attempt_id": { - "$ref": "#/definitions/AttemptId" - }, - "completed": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedParticipantId" - }, - "uniqueItems": true - }, - "expires_on": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "public_key": { - "anyOf": [ - { - "$ref": "#/definitions/PublicKeyExtended" - }, - { - "type": "null" - } - ] - }, - "started_in": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "KeyForDomain": { - "description": "The identification of a specific distributed key, based on which a node would know exactly what keyshare it has corresponds to this distributed key. (A distributed key refers to a specific set of keyshares that nodes have which can be pieced together to form the secret key.)", - "type": "object", - "required": [ - "attempt", - "domain_id", - "key" - ], - "properties": { - "attempt": { - "description": "The attempt ID that generated (initially or as a result of resharing) this distributed key. Nodes may have made multiple attempts to generate the distributed key, and this uniquely identifies which one should ultimately be used.", - "allOf": [ - { - "$ref": "#/definitions/AttemptId" - } - ] - }, - "domain_id": { - "description": "Identifies the domain this key is intended for.", - "allOf": [ - { - "$ref": "#/definitions/DomainId" - } - ] - }, - "key": { - "description": "Identifies the public key. Although technically redundant given that we have the AttemptId, we keep it here in the contract so that it can be verified against and queried.", - "allOf": [ - { - "$ref": "#/definitions/PublicKeyExtended" - } - ] - } - } - }, - "KeyProviderEventDigest": { - "type": "string", - "maxLength": 96, - "minLength": 96, - "pattern": "^[0-9a-fA-F]+$" - }, - "Keyset": { - "description": "Represents a key for every domain in a specific epoch.", - "type": "object", - "required": [ - "domains", - "epoch_id" - ], - "properties": { - "domains": { - "type": "array", - "items": { - "$ref": "#/definitions/KeyForDomain" - } - }, - "epoch_id": { - "$ref": "#/definitions/EpochId" - } - } - }, - "LauncherDockerComposeHash": { - "type": "string", - "maxLength": 64, - "minLength": 64, - "pattern": "^[0-9a-fA-F]+$" - }, - "LauncherImageHash": { - "type": "string", - "maxLength": 64, - "minLength": 64, - "pattern": "^[0-9a-fA-F]+$" - }, - "MigrationInfo": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": [ - { - "anyOf": [ - { - "$ref": "#/definitions/BackupServiceInfo" - }, - { - "type": "null" - } - ] - }, - { - "anyOf": [ - { - "$ref": "#/definitions/DestinationNodeInfo" - }, - { - "type": "null" - } - ] - } - ], - "maxItems": 2, - "minItems": 2 - } - }, - "MockAttestation": { - "oneOf": [ - { - "description": "Always pass validation", - "type": "string", - "enum": [ - "Valid" - ] - }, - { - "description": "Always fails validation", - "type": "string", - "enum": [ - "Invalid" - ] - }, - { - "description": "Pass validation depending on the set constraints", - "type": "object", - "required": [ - "WithConstraints" - ], - "properties": { - "WithConstraints": { - "type": "object", - "properties": { - "expected_measurements": { - "anyOf": [ - { - "$ref": "#/definitions/ExpectedMeasurements" - }, - { - "type": "null" - } - ] - }, - "expiry_timestamp_seconds": { - "description": "Unix time stamp for when this attestation expires.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "launcher_docker_compose_hash": { - "anyOf": [ - { - "$ref": "#/definitions/LauncherDockerComposeHash" - }, - { - "type": "null" - } - ] - }, - "mpc_docker_image_hash": { - "anyOf": [ - { - "$ref": "#/definitions/DockerImageHash" - }, - { - "type": "null" - } - ] - } - } - } - }, - "additionalProperties": false - } - ] - }, - "MrtdHash": { - "type": "string", - "maxLength": 96, - "minLength": 96, - "pattern": "^[0-9a-fA-F]+$" - }, - "NodeId": { - "type": "object", - "required": [ - "account_id", - "account_public_key", - "tls_public_key" - ], - "properties": { - "account_id": { - "description": "Operator account.", - "type": "string" - }, - "account_public_key": { - "description": "Full-access Ed25519 public key of the operator account.", - "allOf": [ - { - "$ref": "#/definitions/Ed25519PublicKey" - } - ] - }, - "tls_public_key": { - "description": "TLS public key used by the node for peer-to-peer communication.", - "allOf": [ - { - "$ref": "#/definitions/Ed25519PublicKey" - } - ] - } - } - }, - "NonEmptyBTreeMap_ForeignChain_ChainEntry": { - "type": "object", - "minProperties": 1, - "additionalProperties": { - "$ref": "#/definitions/ChainEntry" - } - }, - "NonEmptyBTreeMap_ProviderId_ProviderConfig": { - "type": "object", - "minProperties": 1, - "additionalProperties": { - "$ref": "#/definitions/ProviderConfig" - } - }, - "ParticipantId": { - "description": "Stable identifier for a participant within the MPC protocol's participant set.", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "ParticipantInfo": { - "type": "object", - "required": [ - "tls_public_key", - "url" - ], - "properties": { - "tls_public_key": { - "$ref": "#/definitions/Ed25519PublicKey" - }, - "url": { - "$ref": "#/definitions/BoundedString_256" - } - } - }, - "Participants": { - "description": "DTO representation of the contract-internal [`Participants`] type.\n\nIt decouples the JSON wire format (used in view methods like `state()` via [`GovernanceThresholdParameters`](crate::types::state::GovernanceThresholdParameters) from the internal [`Participants`] representation, allowing internal changes (e.g., migrating to [`BTreeMap`](std::collections::BTreeMap) in [#1861](https://github.com/near/mpc/pull/1861)) without breaking the public API.", - "type": "object", - "required": [ - "next_id", - "participants" - ], - "properties": { - "next_id": { - "$ref": "#/definitions/ParticipantId" - }, - "participants": { - "type": "array", - "items": { - "type": "array", - "items": [ - { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - }, - { - "$ref": "#/definitions/ParticipantId" - }, - { - "$ref": "#/definitions/ParticipantInfo" - } - ], - "maxItems": 3, - "minItems": 3 - } - } - } - }, - "Payload": { - "description": "A signature payload; the right payload must be passed in for the curve. The json encoding for this payload converts the bytes to hex string.", - "oneOf": [ - { - "type": "object", - "required": [ - "Ecdsa" - ], - "properties": { - "Ecdsa": { - "$ref": "#/definitions/HexString_Min32_Max32" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Eddsa" - ], - "properties": { - "Eddsa": { - "$ref": "#/definitions/HexString_Min0_Max1232" - } - }, - "additionalProperties": false - } - ] - }, - "PromiseOrValueCKDResponse": { - "description": "Response to a CKD request: the derived key, ElGamal-encrypted to the request's app public key (`pk1` in the publicly-verifiable variant).\n\nFor an app key pair `(a, A = a·G1)` and an ephemeral scalar `y` chosen by the MPC network, `big_y` holds `Y = y·G1` and `big_c` holds `C = derived_key + y·A`; decrypt with `derived_key = C - a·Y`. The derived key is a BLS signature on the app id under the domain's public key; verify it as such before use. Neither field is a public key: the field type is reused for its 48-byte compressed G1 point encoding.", - "type": "object", - "required": [ - "big_c", - "big_y" - ], - "properties": { - "big_c": { - "$ref": "#/definitions/Bls12381G1PublicKey" - }, - "big_y": { - "$ref": "#/definitions/Bls12381G1PublicKey" - } - } - }, - "PromiseOrValueNull": { - "type": "null" - }, - "PromiseOrValueSignatureResponse": { - "oneOf": [ - { - "type": "object", - "required": [ - "big_r", - "recovery_id", - "s", - "scheme" - ], - "properties": { - "big_r": { - "$ref": "#/definitions/K256AffinePoint" - }, - "recovery_id": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "s": { - "$ref": "#/definitions/K256Scalar" - }, - "scheme": { - "type": "string", - "enum": [ - "Secp256k1" - ] - } - } - }, - { - "type": "object", - "required": [ - "scheme", - "signature" - ], - "properties": { - "scheme": { - "type": "string", - "enum": [ - "Ed25519" - ] - }, - "signature": { - "$ref": "#/definitions/Ed25519Signature" - } - } - } - ] - }, - "PromiseOrValueVerifyForeignTransactionResponse": { - "type": "object", - "required": [ - "payload_hash", - "signature" - ], - "properties": { - "payload_hash": { - "$ref": "#/definitions/Hash256" - }, - "signature": { - "$ref": "#/definitions/SignatureResponse" - } - } - }, - "ProposedGovernanceThresholdParameters": { - "description": "A proposed set of threshold parameters submitted to `vote_new_parameters`: the proposed [`GovernanceThresholdParameters`] plus per-domain [`ReconstructionThreshold`] updates for the resharing it would trigger. An empty `per_domain_thresholds` keeps the current ones; a populated map must reference only existing domains (contract-validated), is applied to the [`DomainRegistry`] on resharing, and never persists onto the stored [`GovernanceThresholdParameters`].", - "type": "object", - "required": [ - "parameters" - ], - "properties": { - "parameters": { - "$ref": "#/definitions/GovernanceThresholdParameters" - }, - "per_domain_thresholds": { - "default": {}, - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "Protocol": { - "description": "MPC protocol run for a domain.", - "type": "string", - "enum": [ - "CaitSith", - "Frost", - "ConfidentialKeyDerivation", - "RobustEcdsa" - ] - }, - "ProtocolContractState": { - "description": "The main protocol contract state enum.", - "oneOf": [ - { - "type": "string", - "enum": [ - "NotInitialized" - ] - }, - { - "type": "object", - "required": [ - "Initializing" - ], - "properties": { - "Initializing": { - "$ref": "#/definitions/InitializingContractState" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Running" - ], - "properties": { - "Running": { - "$ref": "#/definitions/RunningContractState" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Resharing" - ], - "properties": { - "Resharing": { - "$ref": "#/definitions/ResharingContractState" - } - }, - "additionalProperties": false - } - ] - }, - "ProviderConfig": { - "description": "One provider's per-chain configuration, stored as a value in `ChainEntry.providers` (keyed by [`ProviderId`]). Read by nodes at startup to assemble the actual RPC URL (`base_url` + `chain_routing` + operator-supplied token via `auth_scheme`).", - "type": "object", - "required": [ - "auth_scheme", - "base_url", - "chain_routing" - ], - "properties": { - "auth_scheme": { - "$ref": "#/definitions/AuthScheme" - }, - "base_url": { - "description": "Provider's stable base. When `chain_routing == Embedded`, the chain identifier is already inside `base_url` (subdomain or path prefix). Otherwise `base_url` is chain-agnostic and `chain_routing` carries the chain marker.\n\nA single `{}` allows per-operator slug (e.g. QuickNode's `https://{}.sui-testnet.quiknode.pro`); nodes match it against exactly one label of the local URL, keeping the rest of the host pinned.", - "type": "string" - }, - "chain_routing": { - "$ref": "#/definitions/ChainRouting" - } - } - }, - "PublicKey": { - "oneOf": [ - { - "type": "object", - "required": [ - "Secp256k1" - ], - "properties": { - "Secp256k1": { - "$ref": "#/definitions/Secp256k1PublicKey" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Ed25519" - ], - "properties": { - "Ed25519": { - "$ref": "#/definitions/Ed25519PublicKey" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Bls12381" - ], - "properties": { - "Bls12381": { - "$ref": "#/definitions/Bls12381G2PublicKey" - } - }, - "additionalProperties": false - } - ] - }, - "PublicKeyExtended": { - "description": "Extended public key representation for different signature schemes.", - "oneOf": [ - { - "description": "Secp256k1 public key (ECDSA).", - "type": "object", - "required": [ - "Secp256k1" - ], - "properties": { - "Secp256k1": { - "type": "object", - "required": [ - "near_public_key" - ], - "properties": { - "near_public_key": { - "description": "The public key in NEAR SDK format (string representation).", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Ed25519 public key.", - "type": "object", - "required": [ - "Ed25519" - ], - "properties": { - "Ed25519": { - "type": "object", - "required": [ - "edwards_point", - "near_public_key_compressed" - ], - "properties": { - "edwards_point": { - "description": "The Edwards point (32 bytes).", - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "near_public_key_compressed": { - "description": "The compressed public key in NEAR SDK format.", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "BLS12-381 public key.", - "type": "object", - "required": [ - "Bls12381" - ], - "properties": { - "Bls12381": { - "type": "object", - "required": [ - "public_key" - ], - "properties": { - "public_key": { - "description": "The public key.", - "allOf": [ - { - "$ref": "#/definitions/PublicKey" - } - ] - } - } - } - }, - "additionalProperties": false - } - ] - }, - "ResharingContractState": { - "description": "State when the contract is resharing keys to new participants.", - "type": "object", - "required": [ - "cancellation_requests", - "previous_running_state", - "reshared_keys", - "resharing_key" - ], - "properties": { - "cancellation_requests": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedAccountId" - }, - "uniqueItems": true - }, - "per_domain_thresholds": { - "description": "Per-domain [`ReconstructionThreshold`] updates carried from the accepted proposal. Applied to the [`DomainRegistry`] when resharing completes.", - "default": {}, - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "previous_running_state": { - "description": "The state being reshared from; while resharing, its `parameters_votes` hold the re-proposal votes for the prospective epoch.", - "allOf": [ - { - "$ref": "#/definitions/RunningContractState" - } - ] - }, - "reshared_keys": { - "type": "array", - "items": { - "$ref": "#/definitions/KeyForDomain" - } - }, - "resharing_key": { - "$ref": "#/definitions/KeyEvent" - } - } - }, - "Rtmr0Hash": { - "type": "string", - "maxLength": 96, - "minLength": 96, - "pattern": "^[0-9a-fA-F]+$" - }, - "Rtmr1Hash": { - "type": "string", - "maxLength": 96, - "minLength": 96, - "pattern": "^[0-9a-fA-F]+$" - }, - "Rtmr2Hash": { - "type": "string", - "maxLength": 96, - "minLength": 96, - "pattern": "^[0-9a-fA-F]+$" - }, - "RunningContractState": { - "description": "State when the contract is ready for signature operations.", - "type": "object", - "required": [ - "add_domains_votes", - "domains", - "keyset", - "parameters", - "parameters_votes" - ], - "properties": { - "add_domains_votes": { - "$ref": "#/definitions/AddDomainsVotes" - }, - "domains": { - "$ref": "#/definitions/DomainRegistry" - }, - "keyset": { - "$ref": "#/definitions/Keyset" - }, - "parameters": { - "$ref": "#/definitions/GovernanceThresholdParameters" - }, - "parameters_votes": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedAccountId" - }, - "uniqueItems": true - } - }, - "previously_cancelled_resharing_epoch_id": { - "anyOf": [ - { - "$ref": "#/definitions/EpochId" - }, - { - "type": "null" - } - ] - } - } - }, - "Secp256k1PublicKey": { - "type": "string" - }, - "SignRequestArgs": { - "description": "Sign request args with backward-compatible deserialization.\n\nThe struct field is `payload` but serializes as `payload_v2` on the wire for compatibility with existing consumers. Deserialization accepts both `payload_v2` and the deprecated `payload` (as raw `[u8; 32]`) plus `key_version` as an alias for `domain_id`.", - "type": "object", - "required": [ - "domain_id", - "path", - "payload_v2" - ], - "properties": { - "domain_id": { - "description": "Identifies the domain whose distributed key is used to derive the signing key.", - "allOf": [ - { - "$ref": "#/definitions/DomainId" - } - ] - }, - "path": { - "description": "Identifies the derived key. The key is determined by the caller's account ID and this derivation path. Different paths produce different keys.", - "type": "string" - }, - "payload_v2": { - "$ref": "#/definitions/Payload" - } - } - }, - "SignatureRequest": { - "description": "A signature request after computing the tweak from the caller's account and derivation path. This is what gets stored in the contract state and sent back to the respond function.", - "type": "object", - "required": [ - "domain_id", - "payload", - "tweak" - ], - "properties": { - "domain_id": { - "$ref": "#/definitions/DomainId" - }, - "payload": { - "$ref": "#/definitions/Payload" - }, - "tweak": { - "$ref": "#/definitions/Tweak" - } - } - }, - "SignatureResponse": { - "oneOf": [ - { - "type": "object", - "required": [ - "big_r", - "recovery_id", - "s", - "scheme" - ], - "properties": { - "big_r": { - "$ref": "#/definitions/K256AffinePoint" - }, - "recovery_id": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "s": { - "$ref": "#/definitions/K256Scalar" - }, - "scheme": { - "type": "string", - "enum": [ - "Secp256k1" - ] - } - } - }, - { - "type": "object", - "required": [ - "scheme", - "signature" - ], - "properties": { - "scheme": { - "type": "string", - "enum": [ - "Ed25519" - ] - }, - "signature": { - "$ref": "#/definitions/Ed25519Signature" - } - } - } - ] - }, - "StarknetExtractor": { - "oneOf": [ - { - "type": "string", - "enum": [ - "BlockHash" - ] - }, - { - "type": "object", - "required": [ - "Log" - ], - "properties": { - "Log": { - "type": "object", - "required": [ - "log_index" - ], - "properties": { - "log_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "StarknetFelt": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "StarknetFinality": { - "type": "string", - "enum": [ - "AcceptedOnL2", - "AcceptedOnL1" - ] - }, - "StarknetRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "$ref": "#/definitions/BoundedVec_StarknetExtractor_Min0_Max32" - }, - "finality": { - "$ref": "#/definitions/StarknetFinality" - }, - "tx_id": { - "$ref": "#/definitions/StarknetTxId" - } - } - }, - "StarknetTxId": { - "$ref": "#/definitions/StarknetFelt" - }, - "StoredAttestation": { - "description": "An attestation as the contract stores it.", - "type": "object", - "required": [ - "attestation" - ], - "properties": { - "accepted_at_seconds": { - "description": "Block time at which the contract accepted this attestation. Every accepted submission restamps it, so a submitter can tell whether its own submission landed. `None` for an entry stored before the contract recorded it.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "attestation": { - "$ref": "#/definitions/VerifiedAttestation" - } - } - }, - "SuiExtractor": { - "oneOf": [ - { - "type": "object", - "required": [ - "Event" - ], - "properties": { - "Event": { - "type": "object", - "required": [ - "event_index" - ], - "properties": { - "event_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "SuiFinality": { - "description": "Sui has no reorgs; a transaction is final once it is included in a committee-certified checkpoint.", - "type": "string", - "enum": [ - "Checkpointed" - ] - }, - "SuiRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "$ref": "#/definitions/BoundedVec_SuiExtractor_Min0_Max32" - }, - "finality": { - "$ref": "#/definitions/SuiFinality" - }, - "tx_id": { - "$ref": "#/definitions/SuiTxId" - } - } - }, - "SuiTxId": { - "description": "32-byte Sui transaction digest (Blake2b-256 of the signed transaction data). Sui APIs display it base58-encoded; here it is carried as raw bytes (hex in JSON).", - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "SvmAddress": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "SvmExtractor": { - "oneOf": [ - { - "type": "object", - "required": [ - "InnerInstruction" - ], - "properties": { - "InnerInstruction": { - "type": "object", - "required": [ - "inner_instruction_index", - "instruction_index" - ], - "properties": { - "inner_instruction_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "instruction_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "AccountState" - ], - "properties": { - "AccountState": { - "type": "object", - "required": [ - "pubkey" - ], - "properties": { - "pubkey": { - "$ref": "#/definitions/SvmAddress" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "SvmFinality": { - "type": "string", - "enum": [ - "Confirmed", - "Finalized" - ] - }, - "SvmRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "$ref": "#/definitions/BoundedVec_SvmExtractor_Min0_Max32" - }, - "finality": { - "$ref": "#/definitions/SvmFinality" - }, - "tx_id": { - "$ref": "#/definitions/SvmTxId" - } - } - }, - "SvmTxId": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2}){64}$" - }, - "TcbInfo": { - "description": "Trusted Computing Base information structure", - "type": "object", - "required": [ - "app_compose", - "compose_hash", - "device_id", - "event_log", - "mrtd", - "rtmr0", - "rtmr1", - "rtmr2", - "rtmr3" - ], - "properties": { - "app_compose": { - "description": "The app compose", - "type": "string" - }, - "compose_hash": { - "description": "The hash of the compose configuration", - "type": "string" - }, - "device_id": { - "description": "The device identifier", - "type": "string" - }, - "event_log": { - "description": "The event log entries", - "type": "array", - "items": { - "$ref": "#/definitions/EventLog" - } - }, - "mrtd": { - "description": "The measurement root of trust", - "type": "string" - }, - "os_image_hash": { - "description": "The hash of the OS image. This is empty if the OS image is not measured by KMS.", - "default": "", - "type": "string" - }, - "rtmr0": { - "description": "The value of RTMR0 (Runtime Measurement Register 0)", - "type": "string" - }, - "rtmr1": { - "description": "The value of RTMR1 (Runtime Measurement Register 1)", - "type": "string" - }, - "rtmr2": { - "description": "The value of RTMR2 (Runtime Measurement Register 2)", - "type": "string" - }, - "rtmr3": { - "description": "The value of RTMR3 (Runtime Measurement Register 3)", - "type": "string" - } - } - }, - "TeeVerifierCodeHash": { - "type": "string", - "maxLength": 64, - "minLength": 64, - "pattern": "^[0-9a-fA-F]+$" - }, - "TonAddress": { - "type": "object", - "required": [ - "hash", - "workchain" - ], - "properties": { - "hash": { - "$ref": "#/definitions/Hash256" - }, - "workchain": { - "type": "integer", - "format": "int32" - } - } - }, - "TonExtractor": { - "oneOf": [ - { - "type": "object", - "required": [ - "Log" - ], - "properties": { - "Log": { - "type": "object", - "required": [ - "message_index" - ], - "properties": { - "message_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "TonFinality": { - "type": "string", - "enum": [ - "MasterchainIncluded" - ] - }, - "TonRpcRequest": { - "type": "object", - "required": [ - "account", - "extractors", - "finality", - "tx_id" - ], - "properties": { - "account": { - "$ref": "#/definitions/TonAddress" - }, - "extractors": { - "$ref": "#/definitions/BoundedVec_TonExtractor_Min0_Max32" - }, - "finality": { - "$ref": "#/definitions/TonFinality" - }, - "tx_id": { - "$ref": "#/definitions/TonTxId" - } - } - }, - "TonTxId": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "Tweak": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "UpdateHash": { - "description": "Identifies an [`Update`] by content.", - "oneOf": [ - { - "type": "object", - "required": [ - "Code" - ], - "properties": { - "Code": { - "$ref": "#/definitions/Hash256" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Config" - ], - "properties": { - "Config": { - "$ref": "#/definitions/Hash256" - } - }, - "additionalProperties": false - } - ] - }, - "VerifiedAttestation": { - "oneOf": [ - { - "type": "object", - "required": [ - "Dstack" - ], - "properties": { - "Dstack": { - "$ref": "#/definitions/VerifiedDstackAttestation" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Mock" - ], - "properties": { - "Mock": { - "$ref": "#/definitions/MockAttestation" - } - }, - "additionalProperties": false - } - ] - }, - "VerifiedDstackAttestation": { - "type": "object", - "required": [ - "expiry_timestamp_seconds", - "launcher_compose_hash", - "measurements", - "mpc_image_hash" - ], - "properties": { - "expiry_timestamp_seconds": { - "description": "Unix time stamp for when this attestation expires.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "launcher_compose_hash": { - "description": "The digest of the launcher compose file running.", - "allOf": [ - { - "$ref": "#/definitions/LauncherDockerComposeHash" - } - ] - }, - "measurements": { - "description": "The OS measurements that were verified during initial attestation.", - "allOf": [ - { - "$ref": "#/definitions/VerifiedMeasurements" - } - ] - }, - "mpc_image_hash": { - "description": "The digest of the MPC image running.", - "allOf": [ - { - "$ref": "#/definitions/DockerImageHash" - } - ] - } - } - }, - "VerifiedMeasurements": { - "type": "object", - "required": [ - "key_provider_event_digest", - "mrtd", - "rtmr0", - "rtmr1", - "rtmr2" - ], - "properties": { - "key_provider_event_digest": { - "$ref": "#/definitions/KeyProviderEventDigest" - }, - "mrtd": { - "$ref": "#/definitions/MrtdHash" - }, - "rtmr0": { - "$ref": "#/definitions/Rtmr0Hash" - }, - "rtmr1": { - "$ref": "#/definitions/Rtmr1Hash" - }, - "rtmr2": { - "$ref": "#/definitions/Rtmr2Hash" - } - } - }, - "VerifyForeignTransactionRequest": { - "type": "object", - "required": [ - "domain_id", - "payload_version", - "request" - ], - "properties": { - "domain_id": { - "$ref": "#/definitions/DomainId" - }, - "expected_payload_hash": { - "anyOf": [ - { - "$ref": "#/definitions/Hash256" - }, - { - "type": "null" - } - ] - }, - "payload_version": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "request": { - "$ref": "#/definitions/ForeignChainRpcRequest" - } - } - }, - "VerifyForeignTransactionRequestArgs": { - "type": "object", - "required": [ - "domain_id", - "payload_version", - "request" - ], - "properties": { - "domain_id": { - "$ref": "#/definitions/DomainId" - }, - "expected_payload_hash": { - "anyOf": [ - { - "$ref": "#/definitions/Hash256" - }, - { - "type": "null" - } - ] - }, - "payload_version": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "request": { - "$ref": "#/definitions/ForeignChainRpcRequest" - } - } - }, - "VerifyForeignTransactionResponse": { - "type": "object", - "required": [ - "payload_hash", - "signature" - ], - "properties": { - "payload_hash": { - "$ref": "#/definitions/Hash256" - }, - "signature": { - "$ref": "#/definitions/SignatureResponse" - } - } - }, - "YieldIndex": { - "description": "The index into calling the YieldResume feature of NEAR. This will allow to resume a yield call after the contract has been called back via this index.", - "type": "object", - "required": [ - "data_id" - ], - "properties": { - "data_id": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - } - } - } - } - } -} From 8421b40acfe5885a75e3bb4fa607db0cbc72af8b Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Fri, 23 Oct 2026 13:59:40 +0200 Subject: [PATCH 08/20] docs(contract-interface): point the legacy parameter-votes arm at its removal issue --- crates/near-mpc-contract-interface/src/types/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 06b2a66e1e..358dd086bd 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -197,7 +197,7 @@ impl<'de> Deserialize<'de> for GovernanceThresholdParametersVotes { #[serde(untagged)] enum Repr { Tally(BTreeMap>), - // TODO(#2825): drop once no deployed contract reports the pre-tally voter-keyed shape. + // TODO(#XXXX): drop once the 3.18 contract is deployed and nodes are upgraded. Legacy { proposal_by_account: BTreeMap, From 92b7184b4c89be184ec78c256b0808c4d38075eb Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Fri, 23 Oct 2026 14:04:53 +0200 Subject: [PATCH 09/20] docs(contract-interface): note the end state when dropping the legacy parameter-votes arm --- crates/near-mpc-contract-interface/src/types/state.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 358dd086bd..95564ef154 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -197,7 +197,8 @@ impl<'de> Deserialize<'de> for GovernanceThresholdParametersVotes { #[serde(untagged)] enum Repr { Tally(BTreeMap>), - // TODO(#XXXX): drop once the 3.18 contract is deployed and nodes are upgraded. + // TODO(#XXXX): drop once the 3.18 contract is deployed and nodes are upgraded; a plain + // derive(Deserialize) then suffices. Legacy { proposal_by_account: BTreeMap, From ae2479c81b0b2d07677c316b9ce1a962d2648c75 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:43:03 +0100 Subject: [PATCH 10/20] docs(contract-interface): drop the paraphrase from the previous_running_state doc --- crates/contract/tests/snapshots/abi__abi_has_not_changed.snap | 2 +- crates/near-mpc-contract-interface/src/types/state.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index 641b4532e7..c079de30e7 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -4718,7 +4718,7 @@ expression: abi } }, "previous_running_state": { - "description": "The state being reshared from; while resharing, its `parameters_votes` hold the re-proposal votes for the prospective epoch.", + "description": "Its `parameters_votes` are the re-proposal votes for the prospective epoch.", "allOf": [ { "$ref": "#/definitions/RunningContractState" diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 95564ef154..1d66105b9d 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -309,8 +309,7 @@ pub struct RunningContractState { derive(schemars::JsonSchema) )] pub struct ResharingContractState { - /// The state being reshared from; while resharing, its `parameters_votes` hold the - /// re-proposal votes for the prospective epoch. + /// Its `parameters_votes` are the re-proposal votes for the prospective epoch. pub previous_running_state: RunningContractState, pub reshared_keys: Vec, pub resharing_key: KeyEvent, From e6e95bbbb5359fa2aa3647813f4b97b11a9bce29 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:59:14 +0100 Subject: [PATCH 11/20] docs(contract-interface): drop the previous_running_state doc --- .../contract/tests/snapshots/abi__abi_has_not_changed.snap | 7 +------ crates/near-mpc-contract-interface/src/types/state.rs | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index c079de30e7..1955ed1710 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -4718,12 +4718,7 @@ expression: abi } }, "previous_running_state": { - "description": "Its `parameters_votes` are the re-proposal votes for the prospective epoch.", - "allOf": [ - { - "$ref": "#/definitions/RunningContractState" - } - ] + "$ref": "#/definitions/RunningContractState" }, "reshared_keys": { "type": "array", diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 1d66105b9d..e2df7fd920 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -309,7 +309,6 @@ pub struct RunningContractState { derive(schemars::JsonSchema) )] pub struct ResharingContractState { - /// Its `parameters_votes` are the re-proposal votes for the prospective epoch. pub previous_running_state: RunningContractState, pub reshared_keys: Vec, pub resharing_key: KeyEvent, From cf6a6f223674056b3455662f61dcdf4d8d5d4947 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:59:14 +0100 Subject: [PATCH 12/20] test(contract-interface): cover a populated legacy parameter-votes report --- .../src/types/state.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index e2df7fd920..0d950b1e09 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -567,6 +567,38 @@ mod tests { assert_eq!(json[proposal.as_hex()][0], "alice.near"); } + #[test] + #[expect(non_snake_case)] + fn parameters_votes__should_group_a_legacy_report_by_proposal() { + // Given: alice and bob voted the same proposal, carol a different one + let proposal = |threshold| ProposedGovernanceThresholdParameters { + parameters: GovernanceThresholdParameters { + participants: sample_participants(), + threshold: GovernanceThreshold::new(threshold), + }, + per_domain_thresholds: BTreeMap::new(), + }; + let legacy = serde_json::json!({ "proposal_by_account": { + "alice.near": proposal(1), + "bob.near": proposal(1), + "carol.near": proposal(2), + }}); + + // When + let votes: GovernanceThresholdParametersVotes = serde_json::from_value(legacy).unwrap(); + + // Then + let voter = |account: &str| AuthenticatedAccountId(account.parse().unwrap()); + let tallies: BTreeSet> = votes.0.into_values().collect(); + assert_eq!( + tallies, + BTreeSet::from([ + BTreeSet::from([voter("alice.near"), voter("bob.near")]), + BTreeSet::from([voter("carol.near")]), + ]) + ); + } + #[test] fn parameters_votes_deserialize_the_legacy_empty_report() { let votes: super::GovernanceThresholdParametersVotes = From 958f611fb62bc904dd281fc57a915dd5a877c584 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:11:12 +0100 Subject: [PATCH 13/20] refactor(contract): expose pending parameter votes via new_parameters_votes instead of state() --- crates/backup-cli/assets/contract_state.json | 1 - crates/contract/src/api/governance.rs | 22 +++-- crates/contract/src/api/lifecycle.rs | 3 +- crates/contract/src/dto_mapping.rs | 80 ++++-------------- .../near-mpc-contract-interface/src/client.rs | 20 +++-- .../src/method_names.rs | 1 + .../src/types/state.rs | 81 +------------------ 7 files changed, 42 insertions(+), 166 deletions(-) diff --git a/crates/backup-cli/assets/contract_state.json b/crates/backup-cli/assets/contract_state.json index 33d347d3d7..bd1073643c 100644 --- a/crates/backup-cli/assets/contract_state.json +++ b/crates/backup-cli/assets/contract_state.json @@ -164,7 +164,6 @@ }, "threshold": 7 }, - "parameters_votes": {}, "add_domains_votes": { "proposal_by_account": {} } diff --git a/crates/contract/src/api/governance.rs b/crates/contract/src/api/governance.rs index eb060412f2..cd947c6cd7 100644 --- a/crates/contract/src/api/governance.rs +++ b/crates/contract/src/api/governance.rs @@ -1,6 +1,6 @@ //! Governance votes over the participant set and the domain registry. -use crate::dto_mapping::TryIntoContractType; +use crate::dto_mapping::{IntoInterfaceType, TryIntoContractType}; use crate::errors::{Error, InvalidParameters}; use crate::primitives::thresholds::{GovernanceThreshold, ProposedGovernanceThresholdParameters}; use crate::tee::tee_state::TeeValidationResult; @@ -104,6 +104,11 @@ impl MpcContract { } Ok(()) } + + /// Returns the pending `vote_new_parameters` votes, keyed by proposal hash. + pub fn new_parameters_votes(&self) -> dtos::GovernanceThresholdParametersVotes { + (&self.parameters_votes).into_dto_type() + } } impl MpcContract { @@ -121,7 +126,6 @@ mod tests { forwarded_participant_call_contract, make_public_key_for_curve, setup_tee_test_contract, submit_attestation, submit_valid_attestations, }; - use crate::dto_mapping::IntoInterfaceType; use crate::errors::{DomainError, InvalidCandidateSet, InvalidState, InvalidThreshold}; use crate::primitives::key_state::{AttemptId, EpochId, KeyEventId, KeyForDomain, Keyset}; use crate::primitives::participants::Participants; @@ -584,7 +588,7 @@ mod tests { } #[test] - fn state__should_report_pending_parameter_votes_by_proposal_hash() { + fn new_parameters_votes__should_report_pending_votes_by_proposal_hash() { // Given let (mut contract, participants, signer, _) = setup_running_contract_with_domain( 3, @@ -600,17 +604,14 @@ mod tests { vote_params(&mut contract, &signer, &proposal).unwrap(); // Then - let dtos::ProtocolContractState::Running(running) = contract.state() else { - panic!("expected Running state"); - }; assert_eq!( - running.parameters_votes, + contract.new_parameters_votes(), expected_tally(&proposal, &[&signer]) ); } #[test] - fn state__should_report_re_proposal_votes_while_resharing() { + fn new_parameters_votes__should_report_re_proposal_votes_while_resharing() { // Given let (mut contract, participants, _, proposal) = resharing_contract_with_domain(); let (voter, _, _) = &participants.participants()[0]; @@ -622,11 +623,8 @@ mod tests { .unwrap(); // Then - let dtos::ProtocolContractState::Resharing(resharing) = contract.state() else { - panic!("expected Resharing state"); - }; assert_eq!( - resharing.previous_running_state.parameters_votes, + contract.new_parameters_votes(), expected_tally(&proposal, &[voter]) ); } diff --git a/crates/contract/src/api/lifecycle.rs b/crates/contract/src/api/lifecycle.rs index b8499ed119..513f1d60ee 100644 --- a/crates/contract/src/api/lifecycle.rs +++ b/crates/contract/src/api/lifecycle.rs @@ -188,8 +188,7 @@ impl MpcContract { } pub fn state(&self) -> near_mpc_contract_interface::types::ProtocolContractState { - let parameters_votes = (&self.parameters_votes).into_dto_type(); - (&self.protocol_state, parameters_votes).into_dto_type() + (&self.protocol_state).into_dto_type() } pub fn config(&self) -> dtos::Config { diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index 9861ceab97..dacad864be 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -619,8 +619,7 @@ mod test_conversions { impl From for dtos::ProtocolContractState { fn from(state: ProtocolContractState) -> Self { - // Parameter votes live on `MpcContract`, which this path lacks: the tally is empty. - (&state, dtos::GovernanceThresholdParametersVotes::default()).into_dto_type() + (&state).into_dto_type() } } @@ -974,71 +973,50 @@ impl IntoInterfaceType for &InitializingContrac } } -/// Parameter votes live on [`crate::MpcContract`], so the caller supplies the converted tally. -impl IntoInterfaceType - for ( - &RunningContractState, - dtos::GovernanceThresholdParametersVotes, - ) -{ +impl IntoInterfaceType for &RunningContractState { fn into_dto_type(self) -> dtos::RunningContractState { - let (state, parameters_votes) = self; dtos::RunningContractState { - domains: (&state.domains).into_dto_type(), - keyset: (&state.keyset).into_dto_type(), - parameters: (&state.parameters).into_dto_type(), - parameters_votes, - add_domains_votes: (&state.add_domains_votes).into_dto_type(), - previously_cancelled_resharing_epoch_id: state.previously_cancelled_resharing_epoch_id, + domains: (&self.domains).into_dto_type(), + keyset: (&self.keyset).into_dto_type(), + parameters: (&self.parameters).into_dto_type(), + add_domains_votes: (&self.add_domains_votes).into_dto_type(), + previously_cancelled_resharing_epoch_id: self.previously_cancelled_resharing_epoch_id, } } } -impl IntoInterfaceType - for ( - &ResharingContractState, - dtos::GovernanceThresholdParametersVotes, - ) -{ +impl IntoInterfaceType for &ResharingContractState { fn into_dto_type(self) -> dtos::ResharingContractState { - let (state, parameters_votes) = self; dtos::ResharingContractState { - previous_running_state: (&state.previous_running_state, parameters_votes) - .into_dto_type(), - reshared_keys: state + previous_running_state: (&self.previous_running_state).into_dto_type(), + reshared_keys: self .reshared_keys .iter() .map(|k| k.into_dto_type()) .collect(), - resharing_key: (&state.resharing_key).into_dto_type(), - cancellation_requests: state + resharing_key: (&self.resharing_key).into_dto_type(), + cancellation_requests: self .cancellation_requests .iter() .map(|a| a.into_dto_type()) .collect(), - per_domain_thresholds: state.per_domain_thresholds.clone(), + per_domain_thresholds: self.per_domain_thresholds.clone(), } } } -impl IntoInterfaceType - for ( - &ProtocolContractState, - dtos::GovernanceThresholdParametersVotes, - ) -{ +impl IntoInterfaceType for &ProtocolContractState { fn into_dto_type(self) -> dtos::ProtocolContractState { - let (state, parameters_votes) = self; - match state { + match self { ProtocolContractState::NotInitialized => dtos::ProtocolContractState::NotInitialized, ProtocolContractState::Initializing(state) => { dtos::ProtocolContractState::Initializing(state.into_dto_type()) } ProtocolContractState::Running(state) => { - dtos::ProtocolContractState::Running((state, parameters_votes).into_dto_type()) + dtos::ProtocolContractState::Running(state.into_dto_type()) } ProtocolContractState::Resharing(state) => { - dtos::ProtocolContractState::Resharing((state, parameters_votes).into_dto_type()) + dtos::ProtocolContractState::Resharing(state.into_dto_type()) } } } @@ -1170,28 +1148,4 @@ mod tests { )) ); } - - #[test] - fn parameters_votes_dto__should_turn_a_legacy_report_into_the_contract_hashes() { - use crate::primitives::proposal_hash::ToProposalHash; - use crate::primitives::test_utils::gen_proposed_threshold_params; - use std::collections::{BTreeMap, BTreeSet}; - - // Given: the per-voter report of a contract that still stores full proposals - let proposal = gen_proposed_threshold_params(5); - let legacy = serde_json::json!({ - "proposal_by_account": { "alice.near": (&proposal).into_dto_type() } - }); - - // When - let votes: dtos::GovernanceThresholdParametersVotes = - serde_json::from_value(legacy).unwrap(); - - // Then: keyed by the hash the contract computes for the same proposal - let voter = dtos::AuthenticatedAccountId("alice.near".parse().unwrap()); - assert_eq!( - votes.0, - BTreeMap::from([(proposal.to_proposal_hash(), BTreeSet::from([voter]))]) - ); - } } diff --git a/crates/near-mpc-contract-interface/src/client.rs b/crates/near-mpc-contract-interface/src/client.rs index e9712cdd8c..7e782e2906 100644 --- a/crates/near-mpc-contract-interface/src/client.rs +++ b/crates/near-mpc-contract-interface/src/client.rs @@ -34,8 +34,8 @@ use crate::method_names::{ GET_FOREIGN_CHAINS_CONFIGS, GET_PENDING_CKD_REQUEST, GET_PENDING_REQUEST, GET_PENDING_VERIFY_FOREIGN_TX_REQUEST, GET_TEE_ACCOUNTS, INIT, INIT_RUNNING, LAUNCHER_HASH_VOTES, MIGRATE, MIGRATION_INFO, MPC_NODE_MANIFEST_DIGEST_VOTES, - OS_MEASUREMENT_VOTES, PREPAY_ATTESTATION_STORAGE, PUBLIC_KEY, REGISTER_BACKUP_SERVICE, - REGISTER_FOREIGN_CHAINS_CONFIG, REMOVE_CONTRACT_UPDATE_VOTE, + NEW_PARAMETERS_VOTES, OS_MEASUREMENT_VOTES, PREPAY_ATTESTATION_STORAGE, PUBLIC_KEY, + REGISTER_BACKUP_SERVICE, REGISTER_FOREIGN_CHAINS_CONFIG, REMOVE_CONTRACT_UPDATE_VOTE, REMOVE_NON_PARTICIPANT_CONTRACT_UPDATE_VOTES, REQUEST_APP_PRIVATE_KEY, RESPOND, RESPOND_CKD, RESPOND_VERIFY_FOREIGN_TX, SIGN, START_KEYGEN_INSTANCE, START_NODE_MIGRATION, START_RESHARE_INSTANCE, STATE, SUBMIT_CONTRACT_UPDATE, SUBMIT_PARTICIPANT_INFO, @@ -50,12 +50,12 @@ use crate::types::{ AvailableForeignChains, BackupServiceInfo, CKDAppPublicKey, CKDRequest, CKDRequestArgs, CKDResponse, ChainEntry, CodeHashesVotes, Config, DestinationNodeInfo, DomainConfig, DomainId, Ed25519PublicKey, EpochId, ExpectedMeasurements, ForeignChain, ForeignChainsConfig, - ForeignChainsConfigs, GovernanceThresholdParameters, InitConfig, KeyEventId, Keyset, - LauncherDockerComposeHash, LauncherHashVotes, LauncherImageHash, MeasurementVotes, - MigrationInfo, NodeId, NodeImageHash, ParticipantUrl, ProposalHash, - ProposedGovernanceThresholdParameters, ProtocolContractState, PublicKey, SignRequestArgs, - SignatureRequest, SignatureResponse, StoredAttestation, TeeVerifierCodeHash, Update, - UpdateHash, VerifyForeignTransactionRequest, VerifyForeignTransactionRequestArgs, + ForeignChainsConfigs, GovernanceThresholdParameters, GovernanceThresholdParametersVotes, + InitConfig, KeyEventId, Keyset, LauncherDockerComposeHash, LauncherHashVotes, + LauncherImageHash, MeasurementVotes, MigrationInfo, NodeId, NodeImageHash, ParticipantUrl, + ProposalHash, ProposedGovernanceThresholdParameters, ProtocolContractState, PublicKey, + SignRequestArgs, SignatureRequest, SignatureResponse, StoredAttestation, TeeVerifierCodeHash, + Update, UpdateHash, VerifyForeignTransactionRequest, VerifyForeignTransactionRequestArgs, VerifyForeignTransactionResponse, YieldIndex, }; use near_mpc_bounded_collections::NonEmptyBTreeMap; @@ -633,6 +633,10 @@ impl MpcContractHandle { self.view(ViewArgs::no_args(LAUNCHER_HASH_VOTES)) } + pub fn new_parameters_votes(&self) -> ViewCall { + self.view(ViewArgs::no_args(NEW_PARAMETERS_VOTES)) + } + pub fn os_measurement_votes(&self) -> ViewCall { self.view(ViewArgs::no_args(OS_MEASUREMENT_VOTES)) } diff --git a/crates/near-mpc-contract-interface/src/method_names.rs b/crates/near-mpc-contract-interface/src/method_names.rs index 16e292e783..378f281d85 100644 --- a/crates/near-mpc-contract-interface/src/method_names.rs +++ b/crates/near-mpc-contract-interface/src/method_names.rs @@ -77,6 +77,7 @@ pub const GET_TEE_ACCOUNTS: &str = "get_tee_accounts"; pub const AVAILABLE_ATTESTATION_GRANTS: &str = "available_attestation_grants"; pub const TEE_VERIFIER_ACCOUNT_ID: &str = "tee_verifier_account_id"; pub const TEE_VERIFIER_VOTES: &str = "tee_verifier_votes"; +pub const NEW_PARAMETERS_VOTES: &str = "new_parameters_votes"; pub const GET_ATTESTATION: &str = "get_attestation"; pub const GET_AVAILABLE_FOREIGN_CHAINS: &str = "get_available_foreign_chains"; pub const GET_FOREIGN_CHAINS_CONFIGS: &str = "get_foreign_chains_configs"; diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 0d950b1e09..6d798f87b4 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -9,7 +9,6 @@ use crate::types::primitives::AccountId; use borsh::{BorshDeserialize, BorshSerialize}; use mpc_primitives::hash::ProposalHash; use serde::{Deserialize, Serialize}; -use sha2::Digest; use std::collections::{BTreeMap, BTreeSet}; use super::primitives::DomainId; @@ -176,6 +175,7 @@ pub struct ProposedGovernanceThresholdParameters { PartialEq, Eq, Serialize, + Deserialize, BorshSerialize, BorshDeserialize, derive_more::Deref, @@ -189,44 +189,6 @@ pub struct GovernanceThresholdParametersVotes( pub BTreeMap>, ); -/// Also accepts the pre-tally report (`{"proposal_by_account": {...}}`) of contracts that -/// still store full proposals, so a newer reader can follow an older contract across an upgrade. -impl<'de> Deserialize<'de> for GovernanceThresholdParametersVotes { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(untagged)] - enum Repr { - Tally(BTreeMap>), - // TODO(#XXXX): drop once the 3.18 contract is deployed and nodes are upgraded; a plain - // derive(Deserialize) then suffices. - Legacy { - proposal_by_account: - BTreeMap, - }, - } - Ok(Self(match Repr::deserialize(deserializer)? { - Repr::Tally(tally) => tally, - Repr::Legacy { - proposal_by_account, - } => tally_by_proposal_hash(proposal_by_account), - })) - } -} - -/// Groups per-voter proposals by the hash the contract stores for them: SHA-256 of the -/// Borsh encoding, which the DTOs share with the contract types. -pub(crate) fn tally_by_proposal_hash( - proposal_by_voter: BTreeMap, -) -> BTreeMap> { - let mut tally: BTreeMap> = BTreeMap::new(); - for (voter, proposal) in proposal_by_voter { - let bytes = borsh::to_vec(&proposal).expect("borsh serialization must succeed"); - let hash = ProposalHash::new(sha2::Sha256::digest(bytes).into()); - tally.entry(hash).or_default().insert(voter); - } - tally -} - /// Votes for adding new domains. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] #[cfg_attr( @@ -297,7 +259,6 @@ pub struct RunningContractState { pub domains: DomainRegistry, pub keyset: Keyset, pub parameters: GovernanceThresholdParameters, - pub parameters_votes: GovernanceThresholdParametersVotes, pub add_domains_votes: AddDomainsVotes, pub previously_cancelled_resharing_epoch_id: Option, } @@ -567,46 +528,6 @@ mod tests { assert_eq!(json[proposal.as_hex()][0], "alice.near"); } - #[test] - #[expect(non_snake_case)] - fn parameters_votes__should_group_a_legacy_report_by_proposal() { - // Given: alice and bob voted the same proposal, carol a different one - let proposal = |threshold| ProposedGovernanceThresholdParameters { - parameters: GovernanceThresholdParameters { - participants: sample_participants(), - threshold: GovernanceThreshold::new(threshold), - }, - per_domain_thresholds: BTreeMap::new(), - }; - let legacy = serde_json::json!({ "proposal_by_account": { - "alice.near": proposal(1), - "bob.near": proposal(1), - "carol.near": proposal(2), - }}); - - // When - let votes: GovernanceThresholdParametersVotes = serde_json::from_value(legacy).unwrap(); - - // Then - let voter = |account: &str| AuthenticatedAccountId(account.parse().unwrap()); - let tallies: BTreeSet> = votes.0.into_values().collect(); - assert_eq!( - tallies, - BTreeSet::from([ - BTreeSet::from([voter("alice.near"), voter("bob.near")]), - BTreeSet::from([voter("carol.near")]), - ]) - ); - } - - #[test] - fn parameters_votes_deserialize_the_legacy_empty_report() { - let votes: super::GovernanceThresholdParametersVotes = - serde_json::from_str(r#"{"proposal_by_account":{}}"#).unwrap(); - - assert_eq!(votes, super::GovernanceThresholdParametersVotes::default()); - } - #[test] fn parameters_votes_roundtrip_the_tally() { let votes = From 0afd1e86dd4924315ba2953f0453c0a37e2d169c Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:23:23 +0100 Subject: [PATCH 14/20] test(contract): update the ABI snapshot for the new_parameters_votes view --- .../snapshots/abi__abi_has_not_changed.snap | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index 1955ed1710..03efc9d448 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -619,6 +619,24 @@ expression: abi } } }, + { + "name": "new_parameters_votes", + "doc": " Returns the pending `vote_new_parameters` votes, keyed by proposal hash.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + } + } + } + }, { "name": "os_measurement_votes", "doc": " Returns pending OS measurement votes, may include former participants' votes", @@ -4756,8 +4774,7 @@ expression: abi "add_domains_votes", "domains", "keyset", - "parameters", - "parameters_votes" + "parameters" ], "properties": { "add_domains_votes": { @@ -4772,16 +4789,6 @@ expression: abi "parameters": { "$ref": "#/definitions/GovernanceThresholdParameters" }, - "parameters_votes": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedAccountId" - }, - "uniqueItems": true - } - }, "previously_cancelled_resharing_epoch_id": { "anyOf": [ { From d144e7f82ba0f2910554f17322d39cc7b9617cdd Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Tue, 27 Oct 2026 20:18:20 +0100 Subject: [PATCH 15/20] test(contract-interface): pin legacy parameters_votes tolerance and document new_parameters_votes --- crates/contract/README.md | 1 + crates/contract/src/api/governance.rs | 2 +- .../src/types/state.rs | 59 +++++++++++++++---- ...nning-an-mpc-node-in-tdx-external-guide.md | 13 ++++ 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/crates/contract/README.md b/crates/contract/README.md index f3d6d1c0b6..58e0f8f529 100644 --- a/crates/contract/README.md +++ b/crates/contract/README.md @@ -345,6 +345,7 @@ These functions require the caller to be a participant or candidate. | `allowed_os_measurements()` | Returns all currently allowed OS measurement sets. | `Vec` | TBD | TBD | | `os_measurement_votes()` | Returns pending OS measurement votes, keyed by the proposal hash of the action voted for, with the accounts backing each; may include former participants' votes. | `MeasurementVotes` | TBD | TBD | | `contract_update_votes()` | Returns current update votes, keyed by the hash voted for, with the accounts backing each. | `BTreeMap>` | TBD | TBD | +| `new_parameters_votes()` | Returns pending `vote_new_parameters` votes, keyed by the proposal hash of the `ProposedGovernanceThresholdParameters` voted for, with the accounts backing each. | `GovernanceThresholdParametersVotes` | TBD | TBD | | `clean_tee_status()` | Private endpoint. Cleans up TEE information for non-participants after resharing. Only callable by the contract itself via a promise. | `Result<(), Error>` | TBD | TBD | ## Building the contract diff --git a/crates/contract/src/api/governance.rs b/crates/contract/src/api/governance.rs index cd947c6cd7..dde96321f1 100644 --- a/crates/contract/src/api/governance.rs +++ b/crates/contract/src/api/governance.rs @@ -573,7 +573,7 @@ mod tests { (contract, participants, domain_id, proposal) } - /// The `state()` tally for `voters` all voting `proposal`. + /// The tally for `voters` all voting `proposal`. fn expected_tally( proposal: &ProposedGovernanceThresholdParameters, voters: &[&AccountId], diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 6d798f87b4..36068270ae 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -513,7 +513,9 @@ mod tests { } #[test] - fn parameters_votes_serialize_as_a_transparent_map_keyed_by_proposal_hash() { + #[expect(non_snake_case)] + fn governance_threshold_parameters_votes__should_serialize_as_a_transparent_map_keyed_by_proposal_hash() + { // Given let proposal = ProposalHash::new([0xCD; 32]); let votes = GovernanceThresholdParametersVotes(BTreeMap::from([( @@ -529,20 +531,57 @@ mod tests { } #[test] - fn parameters_votes_roundtrip_the_tally() { - let votes = - super::GovernanceThresholdParametersVotes(std::collections::BTreeMap::from([( - mpc_primitives::hash::ProposalHash::new([7u8; 32]), - std::collections::BTreeSet::from([super::AuthenticatedAccountId( - "alice.near".parse().unwrap(), - )]), - )])); + #[expect(non_snake_case)] + fn governance_threshold_parameters_votes__should_roundtrip_through_json() { + // Given + let votes = GovernanceThresholdParametersVotes(BTreeMap::from([( + ProposalHash::new([7u8; 32]), + BTreeSet::from([AuthenticatedAccountId("alice.near".parse().unwrap())]), + )])); + // When let json = serde_json::to_string(&votes).unwrap(); + // Then assert_eq!( - serde_json::from_str::(&json).unwrap(), + serde_json::from_str::(&json).unwrap(), votes ); } + + // TODO(#XXXX): drop once no deployed contract reports the pre-tally voter-keyed shape. + #[test] + #[expect(non_snake_case)] + fn running_contract_state__should_ignore_the_legacy_parameters_votes_report() { + // Given: the `state()` of a 3.17 contract while a vote is pending + let parameters = GovernanceThresholdParameters { + participants: sample_participants(), + threshold: GovernanceThreshold::new(1), + }; + let state = RunningContractState { + domains: DomainRegistry { + domains: Vec::new(), + next_domain_id: 0, + }, + keyset: Keyset::new(EpochId::new(0), Vec::new()), + parameters: parameters.clone(), + add_domains_votes: AddDomainsVotes { + proposal_by_account: BTreeMap::new(), + }, + previously_cancelled_resharing_epoch_id: None, + }; + let mut json = serde_json::to_value(&state).unwrap(); + json["parameters_votes"] = serde_json::json!({ "proposal_by_account": { + "alice.near": ProposedGovernanceThresholdParameters { + parameters, + per_domain_thresholds: BTreeMap::new(), + }, + }}); + + // When + let parsed: RunningContractState = serde_json::from_value(json).unwrap(); + + // Then + assert_eq!(parsed, state); + } } diff --git a/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md b/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md index 9232c292ea..d902e74b82 100644 --- a/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md +++ b/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md @@ -2421,6 +2421,19 @@ ERROR mpc_node::key_events: Key resharing attempt KeyEventId { ... } failed: Date: Tue, 27 Oct 2026 21:03:46 +0100 Subject: [PATCH 16/20] test(contract-interface): use DomainId for next_domain_id in the legacy-report test --- crates/near-mpc-contract-interface/src/types/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 22b2eb53f0..fa7f3c872f 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -563,7 +563,7 @@ mod tests { let state = RunningContractState { domains: DomainRegistry { domains: Vec::new(), - next_domain_id: 0, + next_domain_id: DomainId(0), }, keyset: Keyset::new(EpochId::new(0), Vec::new()), parameters: parameters.clone(), From b2b805b832c8171e2f2e1feabb29255f460f35cc Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 28 Oct 2026 20:38:18 +0100 Subject: [PATCH 17/20] refactor(contract): rename new_parameters_votes to parameters_votes and add it to the view catalog --- crates/contract/README.md | 2 +- crates/contract/src/api/governance.rs | 10 +++++----- .../tests/snapshots/abi__abi_has_not_changed.snap | 8 ++++---- crates/near-mpc-contract-interface/src/client.rs | 7 ++++--- crates/near-mpc-contract-interface/src/method_names.rs | 2 +- ...contract_handle__should_match_the_view_catalog.snap | 4 ++++ .../running-an-mpc-node-in-tdx-external-guide.md | 2 +- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/crates/contract/README.md b/crates/contract/README.md index 73ab62fc09..bddf13bc08 100644 --- a/crates/contract/README.md +++ b/crates/contract/README.md @@ -345,7 +345,7 @@ These functions require the caller to be a participant or candidate. | `allowed_os_measurements()` | Returns all currently allowed OS measurement sets. | `Vec` | TBD | TBD | | `os_measurement_votes()` | Returns pending OS measurement votes, keyed by the proposal hash of the action voted for, with the accounts backing each; may include former participants' votes. | `MeasurementVotes` | TBD | TBD | | `contract_update_votes()` | Returns current update votes, keyed by the hash voted for, with the accounts backing each. | `BTreeMap>` | TBD | TBD | -| `new_parameters_votes()` | Returns pending `vote_new_parameters` votes, keyed by the proposal hash of the `ProposedGovernanceThresholdParameters` voted for, with the accounts backing each. | `GovernanceThresholdParametersVotes` | TBD | TBD | +| `parameters_votes()` | Returns pending `vote_new_parameters` votes, keyed by the proposal hash of the `ProposedGovernanceThresholdParameters` voted for, with the accounts backing each. | `GovernanceThresholdParametersVotes` | TBD | TBD | | `clean_tee_status()` | Private endpoint. Cleans up TEE information for non-participants after resharing. Only callable by the contract itself via a promise. | `Result<(), Error>` | TBD | TBD | ## Building the contract diff --git a/crates/contract/src/api/governance.rs b/crates/contract/src/api/governance.rs index 550cd936f2..f70ffc7042 100644 --- a/crates/contract/src/api/governance.rs +++ b/crates/contract/src/api/governance.rs @@ -106,7 +106,7 @@ impl MpcContract { } /// Returns the pending `vote_new_parameters` votes, keyed by proposal hash. - pub fn new_parameters_votes(&self) -> dtos::GovernanceThresholdParametersVotes { + pub fn parameters_votes(&self) -> dtos::GovernanceThresholdParametersVotes { (&self.parameters_votes).into_dto_type() } } @@ -591,7 +591,7 @@ mod tests { } #[test] - fn new_parameters_votes__should_report_pending_votes_by_proposal_hash() { + fn parameters_votes__should_report_pending_votes_by_proposal_hash() { // Given let (mut contract, participants, signer, _) = setup_running_contract_with_domain( 3, @@ -608,13 +608,13 @@ mod tests { // Then assert_eq!( - contract.new_parameters_votes(), + contract.parameters_votes(), expected_tally(&proposal, &[&signer]) ); } #[test] - fn new_parameters_votes__should_report_re_proposal_votes_while_resharing() { + fn parameters_votes__should_report_re_proposal_votes_while_resharing() { // Given let (mut contract, participants, _, proposal) = resharing_contract_with_domain(); let (voter, _, _) = &participants.participants()[0]; @@ -627,7 +627,7 @@ mod tests { // Then assert_eq!( - contract.new_parameters_votes(), + contract.parameters_votes(), expected_tally(&proposal, &[voter]) ); } diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index 50a3aef018..101de8a474 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -618,8 +618,8 @@ expression: abi } }, { - "name": "new_parameters_votes", - "doc": " Returns the pending `vote_new_parameters` votes, keyed by proposal hash.", + "name": "os_measurement_votes", + "doc": " Returns pending OS measurement votes, may include former participants' votes", "kind": "view", "result": { "serialization_type": "json", @@ -636,8 +636,8 @@ expression: abi } }, { - "name": "os_measurement_votes", - "doc": " Returns pending OS measurement votes, may include former participants' votes", + "name": "parameters_votes", + "doc": " Returns the pending `vote_new_parameters` votes, keyed by proposal hash.", "kind": "view", "result": { "serialization_type": "json", diff --git a/crates/near-mpc-contract-interface/src/client.rs b/crates/near-mpc-contract-interface/src/client.rs index f6bc591831..5da1160641 100644 --- a/crates/near-mpc-contract-interface/src/client.rs +++ b/crates/near-mpc-contract-interface/src/client.rs @@ -34,7 +34,7 @@ use crate::method_names::{ GET_FOREIGN_CHAINS_CONFIGS, GET_PENDING_CKD_REQUEST, GET_PENDING_REQUEST, GET_PENDING_VERIFY_FOREIGN_TX_REQUEST, GET_TEE_ACCOUNTS, INIT, INIT_RUNNING, LAUNCHER_HASH_VOTES, MIGRATE, MIGRATION_INFO, MPC_NODE_MANIFEST_DIGEST_VOTES, - NEW_PARAMETERS_VOTES, OS_MEASUREMENT_VOTES, PREPAY_ATTESTATION_STORAGE, PUBLIC_KEY, + OS_MEASUREMENT_VOTES, PARAMETERS_VOTES, PREPAY_ATTESTATION_STORAGE, PUBLIC_KEY, REGISTER_BACKUP_SERVICE, REGISTER_FOREIGN_CHAINS_CONFIG, REMOVE_CONTRACT_UPDATE_VOTE, REMOVE_NON_PARTICIPANT_CONTRACT_UPDATE_VOTES, REQUEST_APP_PRIVATE_KEY, RESPOND, RESPOND_CKD, RESPOND_VERIFY_FOREIGN_TX, SIGN, START_KEYGEN_INSTANCE, START_NODE_MIGRATION, @@ -633,8 +633,8 @@ impl MpcContractHandle { self.view(ViewArgs::no_args(LAUNCHER_HASH_VOTES)) } - pub fn new_parameters_votes(&self) -> ViewCall { - self.view(ViewArgs::no_args(NEW_PARAMETERS_VOTES)) + pub fn parameters_votes(&self) -> ViewCall { + self.view(ViewArgs::no_args(PARAMETERS_VOTES)) } pub fn os_measurement_votes(&self) -> ViewCall { @@ -1143,6 +1143,7 @@ mod tests { let _ = handle.allowed_os_measurements().await; let _ = handle.mpc_node_manifest_digest_votes().await; let _ = handle.launcher_hash_votes().await; + let _ = handle.parameters_votes().await; let _ = handle.os_measurement_votes().await; let _ = handle.contract_update_votes().await; let _ = handle.state().await; diff --git a/crates/near-mpc-contract-interface/src/method_names.rs b/crates/near-mpc-contract-interface/src/method_names.rs index 378f281d85..3713fb85c1 100644 --- a/crates/near-mpc-contract-interface/src/method_names.rs +++ b/crates/near-mpc-contract-interface/src/method_names.rs @@ -77,7 +77,7 @@ pub const GET_TEE_ACCOUNTS: &str = "get_tee_accounts"; pub const AVAILABLE_ATTESTATION_GRANTS: &str = "available_attestation_grants"; pub const TEE_VERIFIER_ACCOUNT_ID: &str = "tee_verifier_account_id"; pub const TEE_VERIFIER_VOTES: &str = "tee_verifier_votes"; -pub const NEW_PARAMETERS_VOTES: &str = "new_parameters_votes"; +pub const PARAMETERS_VOTES: &str = "parameters_votes"; pub const GET_ATTESTATION: &str = "get_attestation"; pub const GET_AVAILABLE_FOREIGN_CHAINS: &str = "get_available_foreign_chains"; pub const GET_FOREIGN_CHAINS_CONFIGS: &str = "get_foreign_chains_configs"; diff --git a/crates/near-mpc-contract-interface/src/snapshots/near_mpc_contract_interface__client__tests__mpc_contract_handle__should_match_the_view_catalog.snap b/crates/near-mpc-contract-interface/src/snapshots/near_mpc_contract_interface__client__tests__mpc_contract_handle__should_match_the_view_catalog.snap index 79fdf2c393..206a5d6cd0 100644 --- a/crates/near-mpc-contract-interface/src/snapshots/near_mpc_contract_interface__client__tests__mpc_contract_handle__should_match_the_view_catalog.snap +++ b/crates/near-mpc-contract-interface/src/snapshots/near_mpc_contract_interface__client__tests__mpc_contract_handle__should_match_the_view_catalog.snap @@ -26,6 +26,10 @@ contract: mpc.near method: launcher_hash_votes args: {} +contract: mpc.near +method: parameters_votes +args: {} + contract: mpc.near method: os_measurement_votes args: {} diff --git a/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md b/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md index 1f6cceef38..808fcffbf5 100644 --- a/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md +++ b/docs/guide/running-an-mpc-node-in-tdx-external-guide/running-an-mpc-node-in-tdx-external-guide.md @@ -2426,7 +2426,7 @@ The contract will retry with a fresh attempt; repeated failures need investigati ```bash near contract call-function as-read-only \ v1.signer-prod.testnet \ - new_parameters_votes \ + parameters_votes \ json-args '{}' \ network-config testnet \ now From 89482ebb74e3fa0a8c43ec99199969c9e922d1b6 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:04:16 +0100 Subject: [PATCH 18/20] docs(contract): point the 3.17.0 leftover TODOs at #4984 --- crates/near-mpc-contract-interface/src/types/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index fa7f3c872f..9f8a880c20 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -551,7 +551,7 @@ mod tests { ); } - // TODO(#XXXX): drop once no deployed contract reports the pre-tally voter-keyed shape. + // TODO(#4984): drop once no deployed contract reports the pre-tally voter-keyed shape. #[test] #[expect(non_snake_case)] fn running_contract_state__should_ignore_the_legacy_parameters_votes_report() { From 0ccc9b31718b92bfd14ec47740fffa019ed5009a Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:10:08 +0100 Subject: [PATCH 19/20] test(contract-interface): drop the redundant parameters-votes JSON round-trip test --- .../src/types/state.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 9f8a880c20..63e6d1b448 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -532,25 +532,6 @@ mod tests { assert_eq!(json[proposal.as_hex()][0], "alice.near"); } - #[test] - #[expect(non_snake_case)] - fn governance_threshold_parameters_votes__should_roundtrip_through_json() { - // Given - let votes = GovernanceThresholdParametersVotes(BTreeMap::from([( - ProposalHash::new([7u8; 32]), - BTreeSet::from([AuthenticatedAccountId("alice.near".parse().unwrap())]), - )])); - - // When - let json = serde_json::to_string(&votes).unwrap(); - - // Then - assert_eq!( - serde_json::from_str::(&json).unwrap(), - votes - ); - } - // TODO(#4984): drop once no deployed contract reports the pre-tally voter-keyed shape. #[test] #[expect(non_snake_case)] From ca88f0b18b7f54fb18dc20ffa5cce5cf36c7a490 Mon Sep 17 00:00:00 2001 From: Simon Rastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Thu, 29 Oct 2026 13:26:50 +0100 Subject: [PATCH 20/20] test(contract-interface): name the 3.18 contract in the legacy vote test --- crates/near-mpc-contract-interface/src/types/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/near-mpc-contract-interface/src/types/state.rs b/crates/near-mpc-contract-interface/src/types/state.rs index 63e6d1b448..b76a250279 100644 --- a/crates/near-mpc-contract-interface/src/types/state.rs +++ b/crates/near-mpc-contract-interface/src/types/state.rs @@ -536,7 +536,7 @@ mod tests { #[test] #[expect(non_snake_case)] fn running_contract_state__should_ignore_the_legacy_parameters_votes_report() { - // Given: the `state()` of a 3.17 contract while a vote is pending + // Given: the `state()` of a 3.18 contract while a vote is pending let parameters = GovernanceThresholdParameters { participants: sample_participants(), threshold: GovernanceThreshold::new(1),