Skip to content

feat: UploadCostEstimate rich breakdown across all SDKs + /v1/files/cost#28

Merged
Nic-dorman merged 27 commits intomainfrom
local-test/cost-estimate-rollout
Apr 22, 2026
Merged

feat: UploadCostEstimate rich breakdown across all SDKs + /v1/files/cost#28
Nic-dorman merged 27 commits intomainfrom
local-test/cost-estimate-rollout

Conversation

@Nic-dorman
Copy link
Copy Markdown
Collaborator

@Nic-dorman Nic-dorman commented Apr 21, 2026

Summary

Upgrades the cost-estimation endpoints to return a full breakdown and ports the change across every SDK. Also renames the asymmetric /v1/cost/file route.

Server (antd)

  • POST /v1/data/cost and POST /v1/files/cost now back onto ant_core::Client::estimate_upload_cost, which samples up to 5 chunk addresses instead of quoting every chunk — dramatically faster on home-NAT / high-latency networks.
  • CostResponse shape extended to { cost, file_size, chunk_count, estimated_gas_cost_wei, payment_mode } (was just { cost }). gRPC Cost message gets the matching additions.
  • /v1/cost/file/v1/files/cost so file cost sits next to /v1/files/upload/public and /v1/files/download/public instead of an orphan /v1/cost/* namespace. Breaking wire change, safe because no external consumers yet.

SDKs (16 total)

Each SDK's dataCost / fileCost (and async variants) now returns the rich UploadCostEstimate struct natively — legacy string-return helpers removed since there are no consumers:

antd-go, antd-rust, antd-py, antd-js, antd-java, antd-csharp, antd-kotlin, antd-swift, antd-dart, antd-cpp, antd-ruby, antd-php, antd-elixir, antd-lua, antd-zig, antd-mcp.

Docs + scripts

  • llms.txt, llms-full.txt, antd/README.md, antd/openapi.yaml, all 15 docs/quickstart-*.md + skill.md refreshed for the new shape + route.
  • scripts/test-api.sh and test-api.ps1 now exercise real curl round-trips for public data, chunks, files, private data, and both cost endpoints — four previously-skipped sections lit up.

Upstream dependency pins

Server uses APIs that depend on changes merged upstream but not yet released:

  1. ant-client PR #44 (feat/file-cost-estimate) — ✅ merged to WithAutonomi/ant-client main on 2026-04-22. antd/Cargo.toml now pulls ant-core via git = "https://github.com/WithAutonomi/ant-client".
  2. saorsa-core PRs #91/#92 — merged to saorsa-labs/saorsa-core main but post-dated the latest v0.23.1 release. antd/Cargo.toml pins via [patch.crates-io] to the PR #92 merge commit 50734d04. Drop the pin once saorsa-core cuts a release > v0.23.1 that includes both PRs (critical for Windows operation — IPv6 split-stack + mapped-v4 normalization).

Test plan

  • CI Check (antd) — green (clippy, fmt, docs, tests)
  • CI API contract tests (antd-rust) — green
  • CI Security audit — green
  • antd-rust — 53/53 tests pass locally
  • antd-go — green
  • antd-py — 17/17 tests pass
  • antd-js — 46/46 tests pass
  • antd-java, antd-csharp, antd-kotlin, antd-dart, antd-ruby, antd-php — tests green
  • Rebuild antd binary against devnet and run the new scripts/test-api.sh end-to-end
  • antd-swift / antd-cpp / antd-zig / antd-elixir — no toolchain on current dev host; confirm in CI if those SDKs have CI jobs
  • antd-lua blocked on unrelated luasocket.dll env issue on this Windows host

🤖 Generated with Claude Code

Nic-dorman and others added 26 commits April 21, 2026 18:16
Replaces antd's per-chunk sequential get_store_quotes loop with a single
Client::estimate_upload_cost call (ant-client PR #44). That call samples
up to 5 chunk addresses and extrapolates median * 3, matching
SingleNodePayment::from_quotes.

Measured improvement on Arbitrum One mainnet from home NAT (4KB payload,
3 chunks):
- old handler: >15 min, timed out, 0 successful quotes
- new handler (warm cache): 63 s — 272 s across 4 samples, cost
  identical at 35156250000000000 atto

Preserves CostResponse { cost } contract for wire-compat; later work
will extend the response shape with chunk_count / gas / payment_mode
and roll out across SDKs (antd-go first for Indelible).

Also adds the local-test stack to Cargo.toml:
- ant-core as path dep to ../../ant-client/ant-core
- [patch.crates-io] saorsa-core = path to ../../saorsa-core (for
  PRs #91/#92 pre-release)

Local-test branch only — DO NOT merge upstream.
Phase 1 of the multi-SDK cost-estimate rollout. Previously antd only
exposed the storage cost as a single string; estimate_upload_cost
returns a richer shape. This change surfaces all four new fields on
both REST and gRPC while preserving wire-compat with existing clients:

proto/antd/v1/common.proto
  Cost: added file_size (u64), chunk_count (u32),
        estimated_gas_cost_wei (string), payment_mode (string).
        New fields default to zero/empty for put/upload wrapping uses
        of Cost, which are harmless noise for existing clients.

src/types.rs
  CostResponse: added four Option<..> fields with
  skip_serializing_if = "Option::is_none" so legacy REST clients see
  the same JSON shape they do today.

src/rest/data.rs, src/rest/files.rs
  Populate the new fields from the UploadCostEstimate.

src/grpc/service.rs
  - Port get_cost and get_file_cost to estimate_upload_cost (same
    shape as the REST handlers; get_cost stages bytes to a temp file).
  - Add ..Default::default() on the three put/upload Cost wrapping
    sites so they compile against the widened message.
  - Import format_payment_mode from types.

Existing SDK wrappers that only read `cost` / `atto_tokens` keep
working. SDKs that want the rich view will be updated next (antd-go
first for Indelible).
…kdown

Phase 2 of the multi-SDK cost-estimate rollout. Surfaces the new
file_size / chunk_count / estimated_gas_cost_wei / payment_mode
fields added to the Cost message in Phase 1.

Prioritised first because Indelible consumes antd-go directly, and
the sampling-based estimator is the difference between a sub-minute
quote and a multi-minute timeout on slow real networks.

models.go
  New UploadCostEstimate struct with all five fields.

client.go, grpc_client.go
  Keep DataCost / FileCost returning a plain string for back-compat.
  Add EstimateDataCost / EstimateFileCost returning *UploadCostEstimate.
  Both REST and gRPC transports supported with identical signatures.

proto/antd/v1/{common,files}.pb.go
  Regenerated from the updated proto. Cost message now has the four
  new getters (FileSize, ChunkCount, EstimatedGasCostWei, PaymentMode).

client_test.go, grpc_client_test.go
  Mock responses extended with the new fields.
  New tests: TestEstimateDataCost, TestEstimateFileCost,
  TestGrpcEstimateDataCost, TestGrpcEstimateFileCost.
  Legacy TestDataCost / TestFileCost still pass — contract is
  additive.

examples/03-files/main.go
  Demonstrates the richer estimate output.

README.md
  Method table updated with both legacy and new methods.

Regen command for future updates (same as README):
  protoc --proto_path=antd/proto --go_out=antd-go/proto \
         --go_opt=paths=source_relative \
         --go_opt=Mantd/v1/common.proto=github.com/WithAutonomi/ant-sdk/antd-go/proto/antd/v1 \
         ... (see README "Generating Proto Stubs")
Phase 3 rollout — antd-rust. Mirrors the Go SDK additions.

models.rs
  New UploadCostEstimate struct with cost, file_size, chunk_count,
  estimated_gas_cost_wei, payment_mode.

client.rs, grpc_client.rs
  Existing data_cost / file_cost keep their String return for
  back-compat. New estimate_data_cost / estimate_file_cost return
  UploadCostEstimate. REST reads the new JSON fields; gRPC reads
  the new Cost message fields.

tests.rs, grpc_tests.rs
  Mock responses extended with the new fields.
  4 new tests: test_estimate_data_cost, test_estimate_file_cost,
  test_grpc_estimate_data_cost, test_grpc_estimate_file_cost.
  Add ..Default::default() on the three v1::Cost wrapping sites
  (put_public, put_private, chunk_put) so they compile against
  the widened message.

README.md
  Method table updated.

Also adds target-dev/ to .gitignore — used when the main target/ is
locked by a running antd binary.
Phase 3 rollout — antd-py. Mirrors the Go and Rust SDK additions.

models.py
  New UploadCostEstimate dataclass with cost, file_size, chunk_count,
  estimated_gas_cost_wei, payment_mode.

_rest.py, _grpc.py
  Existing data_cost / file_cost keep their str return for
  back-compat. New estimate_data_cost / estimate_file_cost return
  UploadCostEstimate. Both sync and async transport variants.

_proto/antd/v1/common_pb2.{py,pyi}
  Regenerated via scripts/generate_proto.py — Cost message now has
  the four new fields.

__init__.py
  UploadCostEstimate exported from the top-level antd package.

tests/test_rest_client.py
  /v1/data/cost mock response extended with the new fields.
  New test class TestEstimateDataCost verifies the full breakdown.

README.md
  Method table updated.
Phase 3 rollout — antd-js. Mirrors the Go/Rust/Py SDK additions.

models.ts
  New UploadCostEstimate interface with cost, fileSize, chunkCount,
  estimatedGasCostWei, paymentMode.

rest-client.ts
  Existing dataCost / fileCost keep their string return for
  back-compat. New estimateDataCost / estimateFileCost return
  UploadCostEstimate.

index.ts
  UploadCostEstimate exported from the package root.

rest-client.test.ts
  /v1/data/cost mock extended with the new fields.
  New test estimateDataCost() verifies the full breakdown.

README.md
  Method table updated.
Follows the policy decision that there are no legacy consumers — no
need to preserve a reduced-shape response for compat.

proto/antd/v1/common.proto
  Drop the "only set for estimates" comment on the 4 rich fields;
  they are always populated now.

src/types.rs
  CostResponse: file_size, chunk_count, estimated_gas_cost_wei,
  payment_mode are now plain scalars (no Option, no
  skip_serializing_if). REST clients always see all 5 fields.

src/rest/{data,files}.rs
  Drop the `Some(..)` wrapping when constructing CostResponse.

Wire-level: the Cost proto3 message already always serialised all
fields (proto3 scalars have no optional distinction from zero). JSON
consumers gain four always-present fields.
No consumers yet of the added Estimate* methods. Collapse back to
single DataCost/FileCost methods that return *UploadCostEstimate.

client.go, grpc_client.go
  DataCost and FileCost now return (*UploadCostEstimate, error).
  Estimate* variants deleted.

client_test.go, grpc_client_test.go
  Tests rewritten to verify the new shape. 2 net tests kept
  (DataCost, FileCost) instead of 4 (DataCost + EstimateDataCost etc).

examples/03-files/main.go
  Updated to the single-method form.

README.md
  Method table collapsed.
Mirrors the antd-go change. No consumers yet, so collapse the two-method
pair (data_cost/estimate_data_cost) into a single method returning
UploadCostEstimate.

src/client.rs, src/grpc_client.rs
  data_cost/file_cost now return Result<UploadCostEstimate, _>.
  estimate_* methods removed.

src/tests.rs, src/grpc_tests.rs
  Tests rewritten; 4 duplicate tests removed (net -4).

examples/02-data.rs, examples/04-files.rs
  Updated to print the rich estimate.

README.md
  Method table collapsed.
Mirrors antd-go and antd-rust retrofits. Single-method API returning
UploadCostEstimate instead of a data_cost/estimate_data_cost pair.

src/antd/_rest.py, src/antd/_grpc.py
  Sync + async data_cost/file_cost now return UploadCostEstimate.
  estimate_* methods removed.

tests/test_rest_client.py
  TestDataCost verifies the full breakdown; TestEstimateDataCost
  deleted.

examples/02_data.py, examples/04_files.py
  Updated to print size/chunks/gas/mode.

README.md
  Method table collapsed.
Mirrors antd-go / antd-rust / antd-py retrofits. Single-method API
returning UploadCostEstimate.

src/rest-client.ts
  dataCost and fileCost return Promise<UploadCostEstimate>.
  estimate* variants removed.
  JSON shape is destructured as required (not optional) fields — the
  antd Cost message always populates them.

src/rest-client.test.ts
  Merged tests into a single dataCost describe block.

examples/02-data.ts, examples/04-files.ts
  Print the rich estimate.

README.md
  Method table collapsed.
Phase 3 rollout — antd-java. Follows the simplified contract: a
single method returning the rich estimate, no legacy string-only
variant.

src/main/java/com/autonomi/antd/models/UploadCostEstimate.java
  New record with cost, fileSize, chunkCount, estimatedGasCostWei,
  paymentMode.

src/main/java/com/autonomi/antd/AntdClient.java
  src/main/java/com/autonomi/antd/AsyncAntdClient.java
  dataCost/fileCost (sync + CompletableFuture async) now return
  UploadCostEstimate.

src/main/java/com/autonomi/antd/GrpcAntdClient.java
  Same for gRPC transport — reads the new Cost proto fields.

src/test/java/com/autonomi/antd/AntdClientTest.java
  src/test/java/com/autonomi/antd/GrpcAntdClientTest.java
  Mock responses extended, tests verify full breakdown.

README.md
  Method table updated.
…imate

Phase 3 rollout — antd-csharp. Follows the simplified contract.

Antd.Sdk/Models.cs
  New UploadCostEstimate record (Cost, FileSize, ChunkCount,
  EstimatedGasCostWei, PaymentMode).

Antd.Sdk/AntdRestClient.cs, Antd.Sdk/AntdGrpcClient.cs
  DataCostAsync/FileCostAsync now return Task<UploadCostEstimate>.
  Internal CostDto extended with the 4 new fields (defaulted so
  old responses still deserialise).

Antd.Sdk/IAntdClient.cs
  Interface updated.

Antd.Sdk.Tests/UnitTests.cs
  DataCostAsync test verifies full breakdown.

Antd.Sdk.Tests/TestRunner.cs
  Integration harness prints rich estimate.

README.md
  Method table updated.
Phase 3 rollout — antd-kotlin.

lib/src/main/kotlin/com/autonomi/sdk/Models.kt
  New UploadCostEstimate data class (cost, fileSize, chunkCount,
  estimatedGasCostWei, paymentMode).
  Internal CostDto gains the 4 new fields with kotlinx-serialization
  @SerialName + defaults so old responses still parse.

lib/src/main/kotlin/com/autonomi/sdk/{AntdRestClient,AntdGrpcClient,IAntdClient}.kt
  dataCost/fileCost now return UploadCostEstimate.

lib/src/test/kotlin/com/autonomi/sdk/RestClientTest.kt
  Mock responses extended; tests verify full breakdown.

examples/src/main/kotlin/com/autonomi/examples/Main.kt
  Prints rich estimate.
Phase 3 rollout — antd-swift.

Sources/AntdSdk/Models.swift
  New UploadCostEstimate struct (cost, fileSize, chunkCount,
  estimatedGasCostWei, paymentMode).

Sources/AntdSdk/AntdRestClient.swift
  CostDTO extended with 4 new optional fields; dataCost/fileCost
  now return UploadCostEstimate.

Sources/AntdSdk/AntdGrpcClient.swift
  Stub signatures updated (gRPC transport still not implemented).

Sources/AntdSdk/AntdClientProtocol.swift
  Protocol updated.

Sources/AntdExamples/Main.swift
  Prints rich estimate.

Note: not build-verified locally (no swift toolchain on the dev host).
The edits are structurally identical to the other SDKs.
Phase 3 rollout — antd-dart.

lib/src/models.dart
  New UploadCostEstimate class with fromJson (cost, fileSize,
  chunkCount, estimatedGasCostWei, paymentMode).

lib/src/client.dart, lib/src/grpc_client.dart
  dataCost/fileCost now return Future<UploadCostEstimate>.

lib/src/generated/
  Regenerated via tool/generate_proto.sh. Cost message has 4 new
  fields (fileSize: Int64, chunkCount: int, estimatedGasCostWei,
  paymentMode).

Not build-verified locally beyond protoc regen.
Phase 3 rollout — antd-cpp.

include/antd/models.hpp
  New UploadCostEstimate struct (cost, file_size, chunk_count,
  estimated_gas_cost_wei, payment_mode).

include/antd/client.hpp, include/antd/async_client.hpp
  data_cost/file_cost now return UploadCostEstimate (sync) and
  std::future<UploadCostEstimate> (async).

src/client.cpp, src/async_client.cpp
  Implementations updated; JSON helpers populate the new fields.

examples/02-data.cpp, examples/04-files.cpp
  Prints rich estimate.

Not build-verified locally (no C++ toolchain preconfigured on host).
The edits are structurally identical to the other SDKs.
Phase 3 rollout — antd-ruby.

lib/antd/models.rb
  New UploadCostEstimate Struct (cost, file_size, chunk_count,
  estimated_gas_cost_wei, payment_mode).

lib/antd/client.rb, lib/antd/grpc_client.rb
  data_cost/file_cost now return UploadCostEstimate.

Ruby pb stubs are generated by the consumer (per README), so no
committed pb files to regen here.
Phase 3 rollout — antd-php.

src/Models/UploadCostEstimate.php
  New readonly class (cost, fileSize, chunkCount,
  estimatedGasCostWei, paymentMode).

src/AntdClient.php
  dataCost/fileCost (sync + PromiseInterface async) now return
  UploadCostEstimate.
Phase 3 rollout — antd-elixir.

lib/antd/models.ex
  New Antd.UploadCostEstimate struct (cost, file_size, chunk_count,
  estimated_gas_cost_wei, payment_mode).

lib/antd/client.ex, lib/antd/grpc_client.ex
  data_cost/file_cost (and the !-raising variants) now return
  {:ok, Antd.UploadCostEstimate.t()}.
Phase 3 rollout — antd-lua.

src/antd/client.lua
  data_cost/file_cost now return a table with cost, file_size,
  chunk_count, estimated_gas_cost_wei, payment_mode (rather than
  a bare cost string).

spec/client_spec.lua
  Mock responses extended; tests verify the full breakdown.
Phase 3 rollout — antd-zig.

src/models.zig
  New UploadCostEstimate struct with deinit helper.

src/json_helpers.zig
  parseCost renamed and reshaped to parseCostEstimate returning
  UploadCostEstimate. New dupeU64 helper for the numeric fields.

src/antd.zig
  dataCost/fileCost now return !models.UploadCostEstimate.
  UploadCostEstimate re-exported alongside the other model aliases.

examples/02-data.zig, examples/04-files.zig
  Print the rich estimate; call the deinit helper correctly.

Not build-verified locally (no zig toolchain preconfigured on host).
Phase 3 rollout — antd-mcp.

src/antd_mcp/server.py
  The estimate_cost tool now unpacks the UploadCostEstimate returned
  by antd-py's data_cost/file_cost into the MCP JSON response: cost,
  file_size, chunk_count, estimated_gas_cost_wei, payment_mode.

Tool callers (agents) can now surface meaningful upload previews
(size/chunks/gas/mode) to the user rather than just a cost number.
Updates every doc site surface so they match the simplified contract
(single method returning UploadCostEstimate, no string-only variant).

Top-level:
  skill.md
    The *_cost entries now mention UploadCostEstimate with its five
    fields.
  llms-full.txt
    Cost message listing, Model Types table, and every per-SDK method
    signature snippet updated (TS, Py, C#, Kotlin, Swift, Go, Java,
    Rust, C++, Ruby, PHP, Dart, Lua, Elixir, Zig).

antd/README.md, antd-mcp/README.md
  REST endpoint / MCP tool descriptions note the richer response
  shape.

Per-SDK READMEs (cpp, ruby, php, elixir, lua, zig, dart):
  Method tables now include "— returns UploadCostEstimate with size,
  chunks, gas, payment mode" (or equivalent language-specific form).
  Zig's ownership notes updated — UploadCostEstimate has a deinit,
  dataCost/fileCost no longer return raw byte slices.

docs/architecture.md, docs/tutorial-store-retrieve.md,
  docs/quickstart-*.md (15 files):
  Every cost-estimation code sample captures the result as `est` and
  prints size/chunks/cost/gas/mode instead of just a bare cost string.

No source code changes in this commit — purely documentation.
Follow-up to the Phase 3 rollout — these three SDKs had test files
that still expected the legacy string return. Found when running the
full local test sweep:

antd-dart/test/client_test.dart
  Mock responses extended; assertions verify est.cost, fileSize,
  chunkCount, estimatedGasCostWei, paymentMode. 40/40 tests pass.

antd-ruby/test/test_client.rb
  Same for test_data_cost and test_file_cost. Ruby Struct fields
  checked instead of a bare string. 24/24 client tests pass; 24/24
  grpc tests pass.

antd-php/tests/AntdClientTest.php
  testDataCost and testFileCost rewritten against UploadCostEstimate
  properties. Also removed a stale extra `false` argument from the
  fileCost call site. 21/21 tests pass.
File cost now sits alongside /v1/files/upload/public and
/v1/files/download/public instead of an orphan /v1/cost/* namespace.
Breaking wire change, but no external consumers yet.

Also sweeps:
- llms-full.txt: correct stale response shapes for data/files put + cost
- scripts/test-api.sh, .ps1: replace four skipped sections with real curl
  round-trip tests (public data, files, private data, cost estimation)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Nic-dorman Nic-dorman changed the base branch from fix/evm-defaults-and-peer-fallback to main April 21, 2026 20:37
@Nic-dorman Nic-dorman marked this pull request as draft April 21, 2026 20:45
Replaces the `ant-core = { path = ... }` and `saorsa-core = { path = ... }`
overrides with remote git refs so CI runners can resolve them:

- ant-core → git dep on WithAutonomi/ant-client main. Now that ant-client
  PR #44 (feat/file-cost-estimate) has merged, `Client::estimate_upload_cost`
  is available from the git URL directly.
- saorsa-core [patch.crates-io] → git pin to 50734d04, the merge commit of
  saorsa-labs/saorsa-core PR #92 on upstream main. Preserves PRs #91/#92
  (Windows IPv6 split-stack + mapped-v4 normalization) which ship after
  v0.23.1. Drop the block once saorsa-core cuts a release that includes
  both PRs.

Local behaviour unchanged; resolves the `unable to update .../ant-core`
and `.../saorsa-core` failures on CI clippy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Nic-dorman Nic-dorman marked this pull request as ready for review April 22, 2026 08:51
@Nic-dorman Nic-dorman merged commit 2ed9b14 into main Apr 22, 2026
3 checks passed
@Nic-dorman Nic-dorman deleted the local-test/cost-estimate-rollout branch April 22, 2026 09:06
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.

1 participant