From 8e7a4a5727fc7007f72f134259dcebdd8966d70a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 2 Jul 2026 16:00:08 +0000 Subject: [PATCH 1/2] chore: prepare 0.12.0 release Bump version to 0.12.0 and finalize CHANGELOG with all changes since 0.11.0, including v2 subpackage, breaking changes, and new APIs. Co-authored-by: Greg Nazario --- CHANGELOG.md | 36 +++++++++++++++++++++++++++--------- pyproject.toml | 2 +- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca56dd6..2f63e51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,35 @@ All notable changes to the Aptos Python SDK will be captured in this file. This changelog is written by hand for now. ## Unreleased -- **[Breaking Change]**: Minimum supported Python is now 3.10 (required for patched dev tooling and alignment with Python 3.9 end-of-life). + +## 0.12.0 (2026-07-02) + +### Breaking changes + +- **[Breaking Change]**: Minimum supported Python is now **3.12** (was 3.10+). - **[Breaking Change]**: Replace `python-ecdsa` (CVE-2024-23342, pure-Python) with `cryptography` (OpenSSL-backed) for secp256k1 ECDSA operations. The public API is unchanged. Note: signing now uses OpenSSL's randomized nonce instead of RFC 6979 deterministic nonce — identical (key, message) pairs will produce different valid signatures on each call. `verify()` now rejects high-S signatures to match Aptos on-chain behaviour. -- **[Breaking Change — v2 only, key derivation]**: `aptos_sdk_v2.crypto.mnemonic.derive_ed25519_private_key` and `derive_secp256k1_private_key` now require the full BIP-44 path `m/purpose'/coin'/account'/change'/address'` and read the address index from segment 5 (`parts[5]`). The previous implementation read the *change* segment (`parts[4]`) as the address index and never called `.AddressIndex(...)`, so any non-zero address index was silently ignored and **every** mnemonic-derived account collapsed onto the index-0 key. After this fix, paths with a non-zero address index will derive a different private key (and therefore a different account address) than the old, broken code did. Users with on-chain state derived from a non-zero address index under the old code must migrate; users on the canonical `m/44'/637'/0'/0'/0'` path are unaffected. -- Update dependencies for vulnerability fixes (`aiohttp`, `urllib3`, `PyNaCl`, `black`). -- Apply Black 26 formatting across `aptos_sdk`, `examples`, and `features` stubs (required by CI `make fmt` gate). -- CI: pin Python 3.12 in the composite setup action; use `actions/checkout@v5` and `actions/setup-python@v5`. -- Increase default `max_gas_amount` from 100,000 to 1,000,000 -- Add `aptos_sdk_v2.types.TypeTag.from_str` parser supporting primitives (`bool`, `u8`–`u256`, `address`, `signer`), `vector`, and structs. `GeneralApi.view_bcs` now uses it, so view functions with non-struct generics (e.g. `0x1::coin::balance`) work correctly. -- Stricter `aptos_sdk_v2.transactions.payload.ModuleId.from_str` — rejects malformed inputs (wrong number of `::` separators, empty address, or empty module name) at parse time instead of failing later during BCS serialization. +- **[Breaking Change — v2 only, key derivation]**: `aptos_sdk.v2.crypto.mnemonic.derive_ed25519_private_key` and `derive_secp256k1_private_key` now require the full BIP-44 path `m/purpose'/coin'/account'/change'/address'` and read the address index from segment 5 (`parts[5]`). The previous implementation read the *change* segment (`parts[4]`) as the address index and never called `.AddressIndex(...)`, so any non-zero address index was silently ignored and **every** mnemonic-derived account collapsed onto the index-0 key. After this fix, paths with a non-zero address index will derive a different private key (and therefore a different account address) than the old, broken code did. Users with on-chain state derived from a non-zero address index under the old code must migrate; users on the canonical `m/44'/637'/0'/0'/0'` path are unaffected. + +### Added + +- Add **`aptos_sdk.v2`** — an async-first v2 SDK subpackage with a modern API surface (`Aptos`, `AptosConfig`, `Network`, typed APIs for accounts, coins, fungible assets, transactions, and BCS). See [`MIGRATION.md`](MIGRATION.md) for a v1→v2 guide. +- Add `SignedTransaction.hash()` to v1 and v2 — compute the committed transaction hash locally without submitting to the network. +- Add `aptos_sdk.v2.types.TypeTag.from_str` parser supporting primitives (`bool`, `u8`–`u256`, `address`, `signer`), `vector`, and structs. `GeneralApi.view_bcs` now uses it, so view functions with non-struct generics (e.g. `0x1::coin::balance`) work correctly. +- Add devnet E2E smoke example (`make smoke`) covering node, faucet, transaction submission, simulation, balance reads, and indexer. +- Add automated PyPI publishing on GitHub Release via OIDC trusted publishing (see [`CONTRIBUTING.md`](CONTRIBUTING.md)). + +### Changed + +- Increase default `max_gas_amount` from 100,000 to 1,000,000. +- Stricter `aptos_sdk.v2.transactions.payload.ModuleId.from_str` — rejects malformed inputs (wrong number of `::` separators, empty address, or empty module name) at parse time instead of failing later during BCS serialization. - Stricter `aptos_sdk.async_client.IndexerClient.query` exception scope — only wraps known transport / decoding errors (`aiohttp.ClientError`, `asyncio.TimeoutError`, `json.JSONDecodeError`, `UnicodeDecodeError`) into `IndexerError`. Caller bugs (`TypeError`, `AttributeError`, etc.) propagate unchanged. +- `aptos_sdk.v2` balance queries use the REST API to support both legacy coins and fungible assets. +- BCS serialization, transaction signing, and type-tag parsing performance optimizations. +- Migrate build tooling from Poetry to **uv** + **hatchling**; lint/format with **ruff** and **mypy**. +- Apply ruff formatting across `aptos_sdk`, `examples`, and `features` stubs (enforced by CI `make fmt` gate). +- Update dependencies for vulnerability fixes (`aiohttp`, `urllib3`, `PyNaCl`, `cryptography`, `requests`). +- Adopt the Innovation-Enabling Source Code License from aptos-core. +- CI: test against Python 3.12 and 3.13; pin GitHub Actions; add Codecov v1/v2 coverage flags and v2-mirror sync enforcement; replace devnet examples CI with comprehensive localnet testing. ## 0.11.0 @@ -91,4 +110,3 @@ All notable changes to the Aptos Python SDK will be captured in this file. This - Add support for generating account addresses. - Add support for http2 - Add async client - diff --git a/pyproject.toml b/pyproject.toml index d8ba7d0..8b15c7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "aptos-sdk" -version = "0.11.0" +version = "0.12.0" description = "Aptos SDK" authors = [{ name = "Aptos Labs", email = "opensource@aptoslabs.com" }] license = {file = "LICENSE"} From 47e92276e813755d49be65c6417b0ab0755466a6 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 2 Jul 2026 16:02:30 +0000 Subject: [PATCH 2/2] chore: update uv.lock for 0.12.0 version bump Co-authored-by: Greg Nazario --- uv.lock | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/uv.lock b/uv.lock index 4ef102e..424cdb2 100644 --- a/uv.lock +++ b/uv.lock @@ -143,7 +143,7 @@ wheels = [ [[package]] name = "aptos-sdk" -version = "0.11.0" +version = "0.12.0" source = { editable = "." } dependencies = [ { name = "aiohttp" }, @@ -237,14 +237,14 @@ resolution-markers = [ "python_full_version >= '3.13'", ] dependencies = [ - { name = "cbor2", marker = "python_full_version >= '3.13'" }, - { name = "coincurve", marker = "python_full_version >= '3.13'" }, - { name = "crcmod", marker = "python_full_version >= '3.13'" }, - { name = "ecdsa", marker = "python_full_version >= '3.13'" }, - { name = "ed25519-blake2b", marker = "python_full_version >= '3.13'" }, - { name = "py-sr25519-bindings", marker = "python_full_version >= '3.13'" }, - { name = "pycryptodome", marker = "python_full_version >= '3.13'" }, - { name = "pynacl", marker = "python_full_version >= '3.13'" }, + { name = "cbor2" }, + { name = "coincurve" }, + { name = "crcmod" }, + { name = "ecdsa" }, + { name = "ed25519-blake2b" }, + { name = "py-sr25519-bindings" }, + { name = "pycryptodome" }, + { name = "pynacl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/0b/c112ca753e8454d8f0ac3ddae2337f37b60c36056f9a89184f07bbed1a0c/bip_utils-2.9.3.tar.gz", hash = "sha256:72a8c95484b57e92311b0b2a3d5195b0ce4395c19a0b157d4a289e8b1300f48a", size = 335672, upload-time = "2024-04-15T19:30:46.31Z" } wheels = [ @@ -259,16 +259,16 @@ resolution-markers = [ "python_full_version < '3.13'", ] dependencies = [ - { name = "cbor2", marker = "python_full_version < '3.13'" }, - { name = "coincurve", marker = "python_full_version < '3.13'" }, - { name = "crcmod", marker = "python_full_version < '3.13'" }, - { name = "ecdsa", marker = "python_full_version < '3.13'" }, - { name = "ed25519-blake2b-fork", marker = "python_full_version < '3.13'" }, - { name = "py-sr25519-bindings", marker = "python_full_version < '3.13'" }, - { name = "pycryptodome", marker = "python_full_version < '3.13'" }, - { name = "pynacl", marker = "python_full_version < '3.13'" }, - { name = "pytoniq-core-fork", marker = "python_full_version < '3.13'" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "cbor2" }, + { name = "coincurve" }, + { name = "crcmod" }, + { name = "ecdsa" }, + { name = "ed25519-blake2b-fork" }, + { name = "py-sr25519-bindings" }, + { name = "pycryptodome" }, + { name = "pynacl" }, + { name = "pytoniq-core-fork" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7c/1b/417d040f1f31a9438eef1f874655db126662e7293c9bbaf28d056616cedd/bip_utils-2.12.1.tar.gz", hash = "sha256:23a88779620a981237227c7482bc316f8ce877a543c736fb00b1e4a7762d1978", size = 608036, upload-time = "2026-03-02T11:43:02.998Z" } wheels = [ @@ -1430,12 +1430,12 @@ name = "pytoniq-core-fork" version = "0.1.48" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "bitarray", marker = "python_full_version < '3.13'" }, - { name = "pycryptodomex", marker = "python_full_version < '3.13'" }, - { name = "pynacl", marker = "python_full_version < '3.13'" }, - { name = "requests", marker = "python_full_version < '3.13'" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, - { name = "x25519", marker = "python_full_version < '3.13'" }, + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "typing-extensions" }, + { name = "x25519" }, ] sdist = { url = "https://files.pythonhosted.org/packages/73/aa/f345c0bdb04dc7f323fdf0708129e54ca95c0435ff57a4b404f8d628c9fd/pytoniq_core_fork-0.1.48.tar.gz", hash = "sha256:eeb22d5f3d9fb15daccc48df5b2faf53e45426503c51bf665b56138a6955ae4a", size = 115892, upload-time = "2026-02-27T10:38:53.432Z" } wheels = [