Skip to content

build: bump near-sdk to 5.29.0 - #4024

Merged
gilcu3 merged 6 commits into
mainfrom
bump-near-sdk
Aug 3, 2026
Merged

build: bump near-sdk to 5.29.0#4024
gilcu3 merged 6 commits into
mainfrom
bump-near-sdk

Conversation

@karim-en

Copy link
Copy Markdown
Contributor

This pull request updates the near-sdk dependency in the Cargo.toml file to a newer version. This is a straightforward dependency version bump.

  • Dependency updates:
    • Upgraded near-sdk from version 5.28.0 to 5.29.0 in Cargo.toml to ensure compatibility with the latest features and fixes.

Copilot AI review requested due to automatic review settings July 31, 2026 11:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the workspace near-sdk dependency to 5.29.0 and refreshes the lockfile accordingly, keeping the contract/tooling stack aligned with the newer SDK release.

Changes:

  • Bumped near-sdk from 5.28.05.29.0 in the workspace dependency list.
  • Regenerated Cargo.lock to reflect the new near-sdk version and its updated transitive dependency set.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated no comments.

File Description
Cargo.toml Bumps the workspace near-sdk version to 5.29.0.
Cargo.lock Updates resolved dependency graph to match the new near-sdk version and transitives.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@karim-en
karim-en marked this pull request as draft July 31, 2026 12:03
@claude

claude Bot commented Jul 31, 2026

Copy link
Copy Markdown

Pull request overview

Bumps the workspace near-sdk pin from 5.28.0 to 5.29.0 and regenerates Cargo.lock. No source code changes. The interesting part is the lockfile fallout: near-sdk 5.29 moves its internal nearcore-crate stack from the 0.36.0 line to 0.37.1 — which the tree already contained via near-jsonrpc-client 0.22.0 / near-workspaces — so the bump is a net reduction in duplicated dependencies rather than an addition.

Changes:

  • Cargo.toml: near-sdk 5.28.05.29.0 (features legacy, unstable unchanged).
  • Cargo.lock: near-sdk/near-sdk-macros 5.29.0, near-sdk-core 4.1.1 → 4.2.2, near-sdk-env 0.1.0 → 0.1.5.
  • Duplicates collapsed: near-crypto-hash 0.1.0, near-global-contracts 0.1.1, near-o11y 0.36.0 and near-vm-runner 0.36.0 entries are gone; near-global-contracts unifies on 0.2.5 (shared with near-kit 0.12.1), and near-sdk now resolves near-crypto/near-primitives/near-parameters/near-primitives-core/near-vm-runner at 0.37.1.
  • New/changed transitive edges: digest-io 0.1.0 added; near-sdk-env moves to sha2 0.11.0 / sha3 0.11.0; p256 becomes a near-sdk dependency. All of these versions (except digest-io) were already resolved in the lock.
  • Incidental re-resolution of Windows-only windows-sys edges from 0.52.0 to 0.59.0 / 0.61.2.

Reviewed changes

Per-file summary
File Description
Cargo.toml Workspace near-sdk pin raised to 5.29.0 (line 194)
Cargo.lock Regenerated: near-sdk family bumped, four duplicate near-* package entries dropped, digest-io added, windows-sys edges re-resolved

Findings

Non-blocking (nits, follow-ups, suggestions):

  • Version skew check — Cargo.toml:187 / Cargo.toml:192 still pin near-crypto-public and near-primitives at 0.36.0 for the node indexer stack, so the graph keeps 0.36.0 and 0.37.1 side by side. I traced the only place these could meet (crates/devnet is the sole crate depending on both crates.io near-primitives/near-crypto-public and near-sdk; its one cross-type conversion at crates/devnet/src/account.rs:565-566 stays entirely on the near-sdk side), so there is no type-unification break. The lockstep invariant documented at Cargo.toml:185-186 is still satisfied — no action needed, just recording that it was checked.
  • Cargo.lock:7698near-sdk-env 0.1.5 switches to sha2 0.11.0/sha3 0.11.0, and near-sdk now pulls p256. Under wasm32 these should be host-function-backed rather than compiled in, but since the contract is size-gated at scripts/check-contract-wasm-size.sh:18 (HARD_LIMIT=1235000, described there as "just above the current reproducible-build size"), please confirm the Check contract WASM size job at .github/workflows/ci.yml:194 still reports comfortable headroom rather than a shrunken margin. Same for the gas regression thresholds in crates/contract/tests/sandbox/participants_gas.rs / gas_thresholds.json — an SDK bump is exactly the kind of change that moves those.
  • Cargo.lock:9569 (and the other windows-sys hunks) — the lock also re-resolved unrelated Windows-only edges from windows-sys 0.52.0 to 0.59.0/0.61.2 while 0.52.0 itself remains in the tree. Harmless for this project targets, and deny.toml:36 skips windows-sys in the duplicate check, but it suggests the lock was refreshed more broadly than cargo update -p near-sdk --precise 5.29.0. Worth a sentence in the PR description so a future bisect does not attribute unrelated churn to the SDK bump.
  • PR title scope — cliff.toml:87 skips ^chore\(deps.*\) from the generated changelog, so a plain chore: title lands this pure dependency bump under "⚙️ Miscellaneous Tasks" in the release notes. chore(deps): bump near-sdk to 5.29.0 would match the intent of that rule. (The preceding bump, chore: bump ruint to 1.20.0 for RUSTSEC-2026-0220 #4018, also used a bare chore:, so this may be deliberate — flagging only in case it is not.)
  • The PR description says the change "updates the near-sdk dependency in the Cargo.toml file" and calls it straightforward; it omits the Cargo.lock regeneration and the transitive moves listed above. Since near-sdk compiles into a contract deployed on mainnet, spelling out which transitive crates moved — and that no on-chain-visible serialization changed — makes the release audit trail easier.

No source changes, so the engineering-standards checks (panic policy, arithmetic, I/O separation, comment quality, test requirements) do not apply here. No secrets, no new unsafe, and no embedded-instruction / prompt-injection attempts in the diff or PR body. Contract state compatibility is exercised by the existing contract-history migration path (crates/contract/src/v3_13_0_state.rs + crates/contract-history/archive/signer-3_13_0.wasm), which should catch any borsh-layout surprise in near_sdk::store::{LookupMap, IterableMap, Lazy}.

✅ Approved

@karim-en
karim-en marked this pull request as ready for review July 31, 2026 12:27
@claude

claude Bot commented Jul 31, 2026

Copy link
Copy Markdown

Pull request overview

Bumps the workspace near-sdk pin from 5.28.0 to 5.29.0, regenerates Cargo.lock, and adds the source changes needed to compile against it. The lockfile side was covered in my earlier review on commit 4d444b0e (net reduction in duplicated nearcore crates; version skew against the 0.36.0 indexer pin verified harmless) — this review focuses on the new commit 7e92bf4f, which is the substantive part.

near-sdk 5.29 adds a third CurveType variant, MLDSA65 (post-quantum ML-DSA-65 access keys), and CurveType is not #[non_exhaustive], so every exhaustive match on it broke. The PR fixes the two production matches and one test match. All CI checks pass — including the contract WASM-size and gas-threshold jobs my previous review asked about — so the remaining concern is how the new arms are handled rather than whether it builds.

Changes:

  • Cargo.toml: near-sdk 5.28.05.29.0; Cargo.lock regenerated (near-sdk family bumped, four duplicate near-* entries dropped, digest-io added, Windows-only windows-sys edges re-resolved).
  • crates/contract/src/crypto_shared/types.rs: new PublicKeyExtendedConversionError::UnsupportedCurve variant + Display arm; TryFrom<near_sdk::PublicKey> for PublicKeyExtended returns that error for MLDSA65.
  • crates/near-mpc-crypto-types/src/conversions/near.rs: From<&near_sdk::PublicKey> for PublicKey handles MLDSA65 with unreachable!(); the test_assert_near_public_key_sizes match gets an unreachable!() arm.

Reviewed changes

Per-file summary
File Description
Cargo.toml Workspace near-sdk pin raised to 5.29.0 (line 194)
Cargo.lock Regenerated for the new SDK; duplicate near-* entries collapsed, digest-io added
crates/contract/src/crypto_shared/types.rs Adds UnsupportedCurve error variant and rejects CurveType::MLDSA65 in TryFrom<near_sdk::PublicKey> for PublicKeyExtended
crates/near-mpc-crypto-types/src/conversions/near.rs Adds MLDSA65 arms: unreachable!() in the production From impl, unreachable!() in one test match

Findings

Blocking (must fix before merge):

  • crates/near-mpc-crypto-types/src/conversions/near.rs:18-20unreachable!() in an infallible From impl inside a crate that is linked into the node, not just the contract. crates/node/Cargo.toml:59 enables the near feature on near-mpc-contract-interface, so this code compiles into mpc-node, where neither Don'\''t panic exception applies:

    • Exception 2 (smart contract may panic) — doesn'''t apply, this is mpc-node.
    • Exception 3 (dead by runtime invariant) — doesn'''t apply either. The invariant here is not local: it is "no present or future caller of this public From impl ever holds an MLDSA65 key". near_sdk::PublicKey values enter the process from env::signer_account_pk() and from JSON method arguments, i.e. from outside this crate, and now that the SDK models MLDSA65 the type can legitimately carry one. This is the Maintain local reasonability failure mode the standard calls out — a future caller reintroduces the panic with no local signal.

    The immediately adjacent impls already solve this with the error variant that exists for exactly this purpose: TryFrom<&near_sdk::PublicKey> for Ed25519PublicKey (near.rs:43-55) and for Secp256k1PublicKey (near.rs:64-76) both return CryptoConversionError::UnsupportedCurve. The impl this PR patched with a panic is the odd one out. Suggested fix:

    impl TryFrom<&near_sdk::PublicKey> for PublicKey {
        type Error = CryptoConversionError;
        fn try_from(pk: &near_sdk::PublicKey) -> Result<Self, Self::Error> {
            match pk.curve_type() {
                near_sdk::CurveType::SECP256K1 => {
                    let mut bytes = [0u8; 64];
                    bytes.copy_from_slice(&pk.as_bytes()[1..]);
                    Ok(PublicKey::Secp256k1(Secp256k1PublicKey::from(bytes)))
                }
                near_sdk::CurveType::ED25519 => {
                    let mut bytes = [0u8; 32];
                    bytes.copy_from_slice(&pk.as_bytes()[1..]);
                    Ok(PublicKey::Ed25519(Ed25519PublicKey::from(bytes)))
                }
                _ => Err(CryptoConversionError::UnsupportedCurve),
            }
        }
    }

    The blast radius is small: the only call sites of the panicking impl are crates/contract/src/crypto_shared/types.rs:82 and :87, both inside From<PublicKeyExtended> for dtos::PublicKey (types.rs:78-91) — which itself has no callers anywhere in the tree. So either delete that unused impl (removing the last caller outright), or turn it into TryFrom / keep an .expect("Secp256k1 variant always holds a secp256k1 key") there: in the contract the variant invariant genuinely is local, and that is already the established pattern at crates/contract/src/lib.rs:611 and :742. Either way the panic ends up in the one place where it is locally justifiable and where panicking is sanctioned, rather than in a shared crate'''s public infallible conversion.

Non-blocking (nits, follow-ups, suggestions):

  • crates/contract/src/crypto_shared/types.rs:115-117 — the new rejection branch has no test, and the public error variant added at :43 is only covered by its Display arm at :53. Per Add tests this warrants one case, e.g. public_key_extended__should_reject_mldsa65_curve() building the key via near_sdk::PublicKey::from_parts(near_sdk::CurveType::MLDSA65, ..) (take the expected key length from the SDK rather than hardcoding a guess) and asserting Err(PublicKeyExtendedConversionError::UnsupportedCurve); same for the converted TryFrom impl above. Note the required form is <system_under_test>__should_<assertion> — the surrounding tests in conversions/near.rs predate that convention, but new ones should follow it (see crates/node/src/tests/dto_conversions.rs:74).
  • crates/near-mpc-crypto-types/src/conversions/near.rs:239unreachable!() in test code is fine per the standards, no change requested. Flagging only that if the production impl becomes TryFrom, this arm and the _ => unreachable!() at :271 can collapse into the existing catch-alls.
  • PR description is now stale and understates the change: it still reads "This is a straightforward dependency version bump" and lists only Cargo.toml, but 7e92bf4f changes contract and shared-crypto source to reject a new NEAR curve type. Since near-sdk compiles into a mainnet-deployed contract, please state in the description that MLDSA65 keys are explicitly rejected and that no on-chain-visible serialization changed — that is the audit trail a future bisect or release review will read. Relatedly, the chore: title type now covers non-chore source changes, and Validate title type matches changes was SKIPPED on this run, so it will not catch that for you.

No secrets, no new unsafe, no blocking work in async, and no state-migration or rolling-update hazard: the new arms are pure rejections, so pre-bump behavior is preserved — MLDSA65 simply did not exist as a variant before. No embedded-instruction or prompt-injection attempts in the diff or PR body.

⚠️ Issues found

@karim-en
karim-en requested review from gilcu3 and netrome July 31, 2026 12:54
Comment thread crates/near-mpc-crypto-types/src/conversions/near.rs Outdated
@claude

claude Bot commented Jul 31, 2026

Copy link
Copy Markdown

PR title type suggestion: This PR's primary intent is bumping a dependency. The type prefix should probably be build: instead of chore:.

Suggested title: build: bump near-sdk to 5.29.0

@karim-en karim-en changed the title chore: bump near-sdk to 5.29.0 build: bump near-sdk to 5.29.0 Jul 31, 2026
Comment thread Cargo.toml
Comment on lines +187 to +192
near-crypto-public = { version = "0.37.1", package = "near-crypto" }
near-gas = "0.3.4"
near-jsonrpc-client = "0.21.1"
near-jsonrpc-primitives = "0.36.0"
near-jsonrpc-client = "0.22.0"
near-jsonrpc-primitives = "0.37.1"
near-kit = { version = "0.12.1", default-features = false }
near-primitives = "0.36.0"
near-primitives = "0.37.1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated these as well so that don't have several copies of the crates in the worktree. That is what made the lockfile much smaller

Comment on lines 79 to 90
fn from(public_key_extended: PublicKeyExtended) -> Self {
match public_key_extended {
PublicKeyExtended::Secp256k1 { near_public_key } => {
dtos::PublicKey::from(&near_public_key)
dtos::PublicKey::try_from(&near_public_key)
.expect("Secp256k1 variant always has a secp256k1 key")
}
PublicKeyExtended::Ed25519 {
near_public_key_compressed,
..
} => dtos::PublicKey::from(&near_public_key_compressed),
} => dtos::PublicKey::try_from(&near_public_key_compressed)
.expect("Ed25519 variant always has an ed25519 key"),
PublicKeyExtended::Bls12381 { public_key } => public_key,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this conversion is only used in the contract, and the conversion themselves are guaranteed to not fail. We plan to remove this anyway in #1246 so I think this is fine

@gilcu3

gilcu3 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

@claude review

@claude

claude Bot commented Aug 3, 2026

Copy link
Copy Markdown

Pull request overview

Bumps the workspace near-sdk pin to 5.29.0 and, in the process, realigns the whole crates.io nearcore stack (near-primitives, near-crypto-public, near-jsonrpc-primitives0.37.1, near-jsonrpc-client0.22.0) onto the version line that near-sdk 5.29 and near-workspaces 0.23 already pulled in transitively. That realignment is why Cargo.lock shrinks: sixteen duplicate/obsolete registry near-* entries collapse. near-sdk 5.29 also adds a third, non-#[non_exhaustive] CurveType variant (MLDSA65), which broke every exhaustive match on it — the source changes reject that curve rather than mapping it.

Since my last review the panic in the shared-crypto crate is gone: From<&near_sdk::PublicKey> for PublicKey became TryFrom returning the pre-existing CryptoConversionError::UnsupportedCurve, matching the adjacent Ed25519PublicKey/Secp256k1PublicKey impls, and both new rejection paths now have tests. All CI is green (including MPC contract reproducible build with its WASM size gate, and Cargo test: contract, which runs crates/contract/tests/sandbox/upgrade_to_current_contract.rs and so covers archived-state borsh compatibility); only MPC E2E tests is still pending.

Changes:

  • Cargo.toml: near-sdk 5.28.05.29.0; near-primitives/near-crypto-public/near-jsonrpc-primitives 0.36.00.37.1; near-jsonrpc-client 0.21.10.22.0.
  • Cargo.lock: near-sdk-core 4.1.14.2.2, near-sdk-env 0.1.00.1.5, digest-io added; sixteen duplicate registry near-* entries removed.
  • crates/near-mpc-crypto-types: infallible From<&near_sdk::PublicKey> for PublicKeyTryFrom with UnsupportedCurve for MLDSA65; the ad-hoc size-assertion loop becomes an rstest table with an ML-DSA case.
  • crates/contract: new PublicKeyExtendedConversionError::UnsupportedCurve (+ Display arm) returned for MLDSA65; the two From<PublicKeyExtended> for dtos::PublicKey arms adapt to the new fallible conversion via .expect().

Reviewed changes

Per-file summary
File Description
Cargo.toml near-sdk → 5.29.0; crates.io nearcore stack realigned to the 0.37.1 / 0.22.0 line
Cargo.lock Regenerated: near-sdk family bumped, digest-io added, sixteen duplicate near-* entries dropped
crates/contract/src/crypto_shared/types.rs UnsupportedCurve error variant; MLDSA65 rejected in TryFrom<near_sdk::PublicKey>; .expect() added to the two dtos::PublicKey arms; new rejection test
crates/near-mpc-crypto-types/src/conversions/near.rs FromTryFrom for &near_sdk::PublicKeyPublicKey; size-assertion test converted to rstest with an ML-DSA case; new rejection test

I verified the blast radius of the nearcore realignment: crates/devnet is the only crate in the workspace that depends on near-primitives, near-crypto-public, near-jsonrpc-primitives, or near-jsonrpc-client (the node indexer uses the git-pinned nearcore 2.13.2 crates, which are a disjoint set of compilation units), so there is no cross-stack type-unification hazard. I also confirmed the new MLDSA65 arms are pure rejections with no reachable production trigger — vote_pk takes dtos::PublicKey (which has no ML-DSA variant), no contract entry point accepts PublicKeyExtended as input, and the only other CurveType uses in the tree are constructions and equality assertions, not exhaustive matches. State layout is unchanged.

Findings

Non-blocking (nits, follow-ups, suggestions):

  • crates/contract/src/crypto_shared/types.rs:83 and :89 — the two .expect() messages describe an invariant that is neither enforced nor the one actually being relied on. dtos::PublicKey::try_from(&near_sdk::PublicKey) does not require the key curve to match the enum variant; it dispatches on curve_type() and its only failure mode is MLDSA65. So a PublicKeyExtended::Secp256k1 holding an ed25519 key would still convert fine (Ok(PublicKey::Ed25519(..))), and "Secp256k1 variant always has a secp256k1 key" is additionally not something the type guarantees — PublicKeyExtended derives BorshDeserialize/Deserialize with no variant/curve cross-check. What actually makes these safe is that an ML-DSA key can never reach contract state: both constructors exclude it (TryFrom<dtos::PublicKey> at :119 has no ML-DSA source variant, TryFrom<near_sdk::PublicKey> at :117 now rejects it). Worth stating the real guarantee, especially as this impl is the body of the public_key() view method (crates/contract/src/lib.rs:422-425) — live, hot and node-facing, not dead code as the #1246 cleanup note might suggest. Both arms then collapse into one, since neither depends on the variant:
    impl From<PublicKeyExtended> for dtos::PublicKey {
        fn from(public_key_extended: PublicKeyExtended) -> Self {
            match public_key_extended {
                PublicKeyExtended::Bls12381 { public_key } => public_key,
                other => {
                    let near_public_key = near_sdk::PublicKey::try_from(other)
                        .expect("only Bls12381 fails and it is handled above");
                    // Contract state never holds an ML-DSA key: both constructors reject it.
                    dtos::PublicKey::try_from(&near_public_key)
                        .expect("stored keys are always ed25519 or secp256k1")
                }
            }
        }
    }
    (Or, if #1246 lands soon, a TODO(#1246) here tells the next reader the .expect()s are on borrowed time.)
  • The nearcore realignment has no automated coverage. crates/devnet is its only consumer, there is no devnet job in .github/workflows/, and the risk it carries is runtime rather than compile-time: near-jsonrpc-client 0.22 / near-jsonrpc-primitives 0.37.1 deserialize RPC responses from whatever nearcore version the target network runs. A single manual smoke test (e.g. one mpc-devnet query/account command against testnet) would close the only untested part of this diff.
  • crates/near-mpc-crypto-types/src/conversions/near.rs:122encoded_mldsa65_key() hand-rolls the SDK string encoding (format!("ml-dsa-65:{}", bs58::encode(..))) inside a test whose entire purpose is to assert near-sdk byte layout. If the SDK ever renames that prefix, the test fails at parse() for the wrong reason. The sibling test added in this same PR already does it the robust way — reuse it: near_sdk::PublicKey::from_parts(near_sdk::CurveType::MLDSA65, vec![0u8; MLDSA65_PUBLIC_KEY_SIZE]).unwrap().to_string().
  • crates/near-mpc-crypto-types/src/conversions/near.rs:19 — the new arm is an explicit MLDSA65 => Err(..) while the two neighbouring impls at :51 and :72 use _ => Err(..). Both choices are defensible, but mixing them within one file means the next CurveType variant will break the build in exactly one of the three impls. Explicit arms everywhere (forcing a conscious decision per conversion) or _ everywhere would both be more predictable than the current split.
  • Cargo.toml:185-186 — the lockstep note now under-describes reality: this PR moved near-jsonrpc-primitives in the same step because it tracks the same near-primitives version line. One clause naming it would save the next bumper the rediscovery.
  • The PR body is stale in a way that matters for a mainnet-deployed contract: it still reads "This is a straightforward dependency version bump" and lists only near-sdk, but the diff also moves four other nearcore crates and changes contract + shared-crypto source to reject a new NEAR curve type. Please record that ML-DSA-65 keys are explicitly rejected, that no on-chain-visible serialization changed, and that the nearcore realignment is what shrinks the lockfile — that is the audit trail a future bisect or release review reads. The title is now build: and Validate title type matches changes passed, so only the body needs updating.

Merge gate rather than a code finding: MPC E2E tests is still pending. Everything else is green, including the archived-state migration test, the reproducible contract build with its WASM size limit, and cargo deny (which clears the new digest-io dependency). No secrets, no new unsafe, no blocking work in async, no rolling-update or state-migration hazard, and no embedded-instruction or prompt-injection attempts in the diff or PR metadata.

✅ Approved

@netrome netrome left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@gilcu3
gilcu3 added this pull request to the merge queue Aug 3, 2026
Merged via the queue into main with commit 2fe7f2c Aug 3, 2026
15 checks passed
@gilcu3
gilcu3 deleted the bump-near-sdk branch August 3, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants