Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a9970fe
feat(contract): operator-prepaid attestation storage (grant counter)
barakeinav1 Aug 4, 2026
46c17be
Merge branch 'main' into 4015-operator-prepaid-attestation-storage
barakeinav1 Aug 4, 2026
e0b4e8c
test(contract): cover the callback path's grant handling
barakeinav1 Aug 4, 2026
1eac945
refactor(e2e): read the attestation storage fee from the contract
barakeinav1 Aug 4, 2026
a952562
test(contract): exempt the new PromiseOrValue assertions from the ass…
barakeinav1 Aug 4, 2026
df09c2a
docs(design): align the funding design doc with what shipped
barakeinav1 Aug 4, 2026
22ac89d
docs(contract): drop the doc comment on available_attestation_grants
barakeinav1 Aug 4, 2026
db0e152
Merge branch 'main' into 4015-operator-prepaid-attestation-storage
barakeinav1 Aug 5, 2026
fb7297e
refactor(contract): address review feedback on the grant helpers
barakeinav1 Aug 5, 2026
b639938
Merge branch 'main' into 4015-operator-prepaid-attestation-storage
barakeinav1 Aug 6, 2026
6627a35
refactor(contract): address review feedback from gilcu3
barakeinav1 Aug 6, 2026
ce0420b
refactor(e2e): review follow-ups on the prepayment helper
barakeinav1 Aug 6, 2026
bb0251e
test(contract): make sandbox prepayment explicit
barakeinav1 Aug 6, 2026
9e63d0c
test(contract): make in-process prepayment explicit
barakeinav1 Aug 6, 2026
73b93cd
test(contract): move the prepay validation tests to unit tests
barakeinav1 Aug 6, 2026
7083108
chore: trigger CI
barakeinav1 Aug 6, 2026
7392953
fix: address comments
gilcu3 Aug 7, 2026
eacb4d3
fix: forgot borsh schema
gilcu3 Aug 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/contract/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ stateDiagram-v2
| `verify_foreign_transaction(request: VerifyForeignTransactionRequestArgs)` | Submits a foreign-chain transaction verification request to the contract. Requires a deposit of 1 yoctonear and that the requested foreign chain is in the contract's supported set. Duplicate submissions of the same request (same caller, domain, chain, and payload) while an earlier one is still pending are queued and all receive the same response when the MPC nodes reply; the queue is bounded — concurrent duplicates beyond that bound are rejected with `PendingRequestQueueFull`. | deferred to promise | `10 Tgas` | `~7 Tgas` |
| `public_key(domain: Option<DomainId>)` | Read-only function; returns the public key used for the given domain (defaulting to first). | `Result<PublicKey, Error>` | | |
| `derived_public_key(path: String, predecessor: Option<AccountId>, domain: Option<DomainId>)` | Generates a derived public key for a given path and account, for the given domain (defaulting to first). | `Result<PublicKey, Error>` | | |
| `prepay_attestation_storage(account_id: AccountId, grants: u32)` | Prepays attestation-entry storage for `account_id`. One grant permits one stored attestation. Payable and permissionless — anyone may prepay for any account, which is how an operator funds a node whose function-call access key cannot attach a deposit. Requires an attached deposit of exactly `attestation_storage_fee_millinear × grants` (see `config`) and rejects anything else. Nothing is refunded and there is no withdrawal. | `Result<(), Error>` | 30Tgas | ~4Tgas |
| `available_attestation_grants(account_id: AccountId)` | Read-only function; returns the grants `account_id` has available — bought, minus those currently backing a stored attestation. `0` therefore means either "never prepaid" or "prepaid, and the grant is backing an entry"; cross-reference `get_tee_accounts` to distinguish them. | `u32` | | |

#### SignRequestArgs (Latest version)

Expand Down Expand Up @@ -310,7 +312,7 @@ These functions require the caller to be a participant or candidate.
| `vote_cancel_keygen(next_domain_id: u64)` | For Initializing state only. Votes to cancel the key generation (identified by the next_domain_id) and revert to the Running state. | `Result<(), Error>` | TBD | TBD |
| `propose_update(args: ProposeUpdateArgs)` | Proposes an update to the contract, requiring an attached deposit. | `Result<UpdateId, Error>` | TBD | TBD |
| `vote_update(id: UpdateId)` | Votes on a proposed update. If the threshold is met, the update is executed. | `Result<bool, Error>` | TBD | TBD |
| `submit_participant_info(proposed_participant_attestation: Attestation, tls_public_key: Ed25519PublicKey)` | Submits the tee participant info for a potential candidate. c.f. TEE section | `Result<(), Error>` | TBD | TBD |
| `submit_participant_info(proposed_participant_attestation: Attestation, tls_public_key: Ed25519PublicKey)` | Submits the tee participant info for a potential candidate. c.f. TEE section. Storing a new attestation entry consumes one attestation-storage grant, so the account must have one prepaid via `prepay_attestation_storage`; re-submitting for a TLS key the account already owns does not. | `Result<(), Error>` | TBD | TBD |

### Developer API

Expand Down
6 changes: 6 additions & 0 deletions crates/contract/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const DEFAULT_RESOLVE_VERIFICATION_TERA_GAS: u64 = 60;
/// Default TTL after which a launcher image hash unused by any participant is evicted.
pub(crate) const DEFAULT_LAUNCHER_HASH_UNUSED_TTL_SECONDS: u64 = 14 * 24 * 60 * 60; // 14 days

/// One attestation-storage grant, in milliNEAR.
const DEFAULT_ATTESTATION_STORAGE_FEE_MILLINEAR: u64 = 20;

/// Config for V2 of the contract.
#[near(serializers=[borsh, json])]
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -87,6 +90,8 @@ pub(crate) struct Config {
/// Applied when an entry's expiry is next stamped (vote-in, re-vote, or a refresh on
/// use), not retroactively — changing it does not re-date existing entries.
pub(crate) launcher_hash_unused_ttl_seconds: u64,
/// Fee, in milliNEAR, charged for one attestation-storage grant.
pub(crate) attestation_storage_fee_millinear: u64,
}

impl Default for Config {
Expand Down Expand Up @@ -117,6 +122,7 @@ impl Default for Config {
verifier_tera_gas: DEFAULT_VERIFIER_TERA_GAS,
resolve_verification_tera_gas: DEFAULT_RESOLVE_VERIFICATION_TERA_GAS,
launcher_hash_unused_ttl_seconds: DEFAULT_LAUNCHER_HASH_UNUSED_TTL_SECONDS,
attestation_storage_fee_millinear: DEFAULT_ATTESTATION_STORAGE_FEE_MILLINEAR,
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions crates/contract/src/dto_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,9 @@ impl TryFrom<near_mpc_contract_interface::types::InitConfig> for Config {
if let Some(v) = config_ext.resolve_verification_tera_gas {
config.resolve_verification_tera_gas = v;
}
if let Some(v) = config_ext.attestation_storage_fee_millinear {
config.attestation_storage_fee_millinear = v;
}
if let Some(v) = config_ext.launcher_hash_unused_ttl_seconds {
config.launcher_hash_unused_ttl_seconds = v;
}
Expand Down Expand Up @@ -545,6 +548,7 @@ impl From<&Config> for near_mpc_contract_interface::types::Config {
.remove_non_participant_tee_verifier_votes_tera_gas,
verifier_tera_gas: value.verifier_tera_gas,
resolve_verification_tera_gas: value.resolve_verification_tera_gas,
attestation_storage_fee_millinear: value.attestation_storage_fee_millinear,
launcher_hash_unused_ttl_seconds: value.launcher_hash_unused_ttl_seconds,
}
}
Expand Down Expand Up @@ -579,6 +583,7 @@ impl TryFrom<near_mpc_contract_interface::types::Config> for Config {
.remove_non_participant_tee_verifier_votes_tera_gas,
verifier_tera_gas: value.verifier_tera_gas,
resolve_verification_tera_gas: value.resolve_verification_tera_gas,
attestation_storage_fee_millinear: value.attestation_storage_fee_millinear,
launcher_hash_unused_ttl_seconds: value.launcher_hash_unused_ttl_seconds,
};

Expand Down
8 changes: 8 additions & 0 deletions crates/contract/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ pub enum InvalidParameters {
MalformedPayload { reason: String },
#[error("Attached deposit is lower than required. Attached: {attached}, required: {required}")]
InsufficientDeposit { attached: u128, required: u128 },
#[error(
"attached deposit {attached} must be exactly the attestation storage fee times the requested grants, {required}"
)]
UnexpectedDeposit { attached: u128, required: u128 },
#[error(
"no attestation storage grant available for {account_id}; prepay one with prepay_attestation_storage"
)]
NoAttestationStorageGrant { account_id: String },
#[error("Provided gas is lower than required. Provided: {provided}, required: {required}")]
InsufficientGas { provided: u64, required: u64 },
#[error("This sign request has timed out, was completed, or never existed.")]
Expand Down
Loading