Skip to content

3.20.0

Latest

Choose a tag to compare

@github-actions github-actions released this 17 Sep 16:16
61a18fb

3.20.0 - 2026-09-17

Added

  • Tezos X (Michelson runtime on a sequencer) support: send() and wait() work on nodes without a mempool (wait_operations tracks inclusion by blocks alone when pending_operations answers 404/401/403); pytezos.using(fee_thresholds='node') quotes fees from the node's /chains/main/mempool/filter instead of the built-in mainnet thresholds (FeeThresholds in pytezos.operation.fees, also accepted explicitly); scripts/tezosx_sandbox.py boots a local Tezos X Michelson sequencer for integration tests.

Changed

  • Default IPFS gateway is now https://ipfs.filebase.io/ipfs: the ipfs.io path gateway retires on 2026-09-21. Metadata fetch failures raise requests.RequestException naming the gateway and the content hash and pointing at pytezos.using(ipfs_gateway=...), instead of a bare JSONDecodeError.
  • autofill no longer bumps the counter by pending mempool operations: the mempool admits one manager operation per source per block, so a bumped counter was rejected at injection; use bulk() for several operations per block. get_counter_offset (informational) reads validated (with applied fallback), filters by source, and yields 0 on nodes that hide (401/403) or lack (404) the mempool via the new typed RpcForbiddenError / RpcNotFoundError; RpcError.from_response no longer asserts on a JSON-object error body.
  • SandboxedNodeTestCase and the at-exit cleanup no longer stop every sandboxed node on the machine; only containers started by the current process are stopped. Starting a node on a host port already published by a foreign container fails fast with SandboxPortConflict naming the port and the container.
  • Dropped the unused cryptography dependency; jupyterlab 4.6.3, tornado 6.5.8, mistune 3.3.4 close 14 advisories; .github/dependabot.yml added (uv + github-actions, weekly).
  • Dependencies refreshed (uv lock --upgrade); ruff rules are now selected explicitly (lint.select) so the lint gate no longer moves with ruff's default rule set (ruff 0.16 would otherwise have enabled ~1.8k UP/I/TRY findings).

Fixed

  • wait_blocks no longer skips levels on chains whose head advances several blocks between two polls (1-second blocks on Tezos X): every block between two polled heads is yielded, so wait_operations cannot miss the block that included the operation.
  • pytezos sandbox starts a working chain again: --protocol lists the supported protocols (default: the latest), get_protocol_parameters honours its argument, the CLI retries a failed bake, and the node settles for a moment after protocol activation so the first mempool request cannot wedge the prevalidator.
  • ipfs_gateway passed to using() is now inherited by contracts and spawned objects; previously it was silently reset to the default.
  • Local forging of transactions whose entrypoint is stake, unstake, finalize_unstake or set_delegate_parameters (the staking pseudo-entrypoints introduced in Oxford, or a contract entrypoint of the same name) now emits the protocol's one-byte tags (0x06–0x09) instead of a named entrypoint, matching helpers/forge/operations and the bytes hardware wallets expect. Previously OperationGroup.forge(validate=True) failed with "Local forge result differs from remote one" for these operations, sign() produced non-canonical bytes, and hash() was wrong for such operations.
  • delegation(delegate=None) now removes the current delegate: the delegate key is omitted from the operation content instead of being sent as JSON null, which the node rejected with Unexpected null instead of string. The default '' still registers the signer as a delegate. Code that built an undelegation by calling delegation(delegate=None) and then deleting the delegate key by hand should drop that step (the key is no longer there).
  • forge_protocol_data encoded every liquidity_baking_toggle_vote as off and ignored adaptive_issuance_vote. Votes are now typed (pytezos.block.forge.PerBlockVote) and forged per the protocol's per-block-votes encoding: a single on/off/pass byte since Jakarta, with the adaptive issuance vote packed into the same byte for Oxford..Seoul headers. Values outside on/off/pass raise ValueError.
  • Contracts with an entrypoint or view named like a ContractInterface attribute (storage, metadata, token_metadata, call, ...), or with an entrypoint and a view sharing a name (e.g. FA2.1 balance_of), load again; every proxy is reachable via contract.entrypoint.<name> / contract.view.<name>, and a shadowed top-level shortcut emits a UserWarning instead of raising (#314).
  • TZIP-21 token metadata: ContractTokenMetadata.rightsUri is now populated from either the spec key rightsUri or the legacy rightUri (previously the bundled schema only knew rightUri, so the field was always None). Unknown top-level keys no longer fail validation, matching additionalProperties: true in the TZIP-21 schema; they are kept in .raw, which holds the document exactly as given (a legacy rightUri stays there under its own name). Nested formats[], attributes[], dimensions and dataRate objects stay strict as in the spec.