Skip to content

docs: external-signer flow reference + ABI + python smoke test (V2-311)#97

Merged
Nic-dorman merged 2 commits into
mainfrom
nic/v2-311-external-signer-flow-doc
May 19, 2026
Merged

docs: external-signer flow reference + ABI + python smoke test (V2-311)#97
Nic-dorman merged 2 commits into
mainfrom
nic/v2-311-external-signer-flow-doc

Conversation

@Nic-dorman
Copy link
Copy Markdown
Collaborator

Closes V2-311 — unblocks V2-312 (15-SDK fan-out).

What this adds

  • docs/external-signer-flow.md — reference doc covering the contract surface, selectors, annotated calldata, daemon REST contract, wave-batch step-by-step, single-chunk variant, errors + events. Designed so non-Rust SDK authors can write 07_external_signer examples without reading evmlib source.
  • docs/abi/IPaymentVault.json — language-agnostic ABI bundled in-repo. Lifted byte-identical from evmlib 0.8.1 (SHA-256 8c73043056387530bbe721171c950d22af27b2d02fd76309a2d19cea879f8110, also matches 0.8.0). SDKs that prefer loading a JSON ABI over hand-writing the function signature pick it up here.
  • docs/external-signer-flow.py — runnable python round-trip (web3.py + anvil deterministic account #0) mirroring the snippet embedded in the doc. Serves as a smoke test for ant dev start --enable-evm and a copy-pasteable reference for V2-312's antd-py example.

Scope decisions

  • Wave-batch only. Merkle-batch path is documented as out-of-scope and parked for a follow-up — small-file examples (V2-312's target) never trip the merkle threshold. The merkle selectors + flow are mentioned in the doc for completeness so future ticket work has a starting point.
  • Single tx_hash per quote is intentional (every quote in a wave is paid in one payForQuotes call). The doc and snippet both make this explicit because it's a subtle but load-bearing detail for SDK authors.
  • Anvil account #0 as the canonical signer. Pre-funded with ETH and antToken via devnet genesis.

Validation

Source verification:

  • ABI SHA-256 matches between evmlib 0.8.0 and 0.8.1
  • Function selectors computed from the ABI signatures (keccak truncate)
  • Tx-flow sequencing cross-referenced against evmlib/src/wallet.rs:145 (the canonical pay_for_quotes) and ant-core/src/data/client/batch.rs:255

Python snippet:

  • python -m py_compile docs/external-signer-flow.py passes
  • Not yet executed against a live ant dev start --enable-evm — see open question below

Open question

Should we run the python snippet against the dev2 devnet before merge as the V2-311 acceptance specifies ("runs successfully against ant dev start --enable-evm end-to-end"), or merge as docs-only and defer validation to when V2-312 starts (since the antd-py example will exercise the same flow)?

Captures everything an SDK author needs to wire the external-signer flow
without reading the Rust source. Closes the V2-311 archaeology prereq
and unblocks V2-312 (15-language fan-out).

- docs/external-signer-flow.md - reference doc: contract overview,
  function selectors, annotated calldata, daemon REST contract,
  wave-batch step-by-step, single-chunk variant, errors + events.
- docs/abi/IPaymentVault.json - language-agnostic ABI bundled in-repo
  (lifted byte-identical from evmlib 0.8.1, SHA-256 8c730430...).
- docs/external-signer-flow.py - runnable python round-trip (web3.py +
  anvil account #0) mirroring the snippet in the doc; smoke test for
  'ant dev start --enable-evm'.

Merkle-batch path is documented as out-of-scope and parked for a
follow-up; V2-312 only needs the wave_batch flow for small-file
examples.
…2 validation

Validated end-to-end against ant dev start --enable-evm on dev2:
  - 352-byte file uploaded via external-signer flow
  - data_map_address = 280cca01b194fd1b402457990fc497f5a7f6fe84b09015a36346fcc86bba421e
  - payForQuotes tx = 470b1de38f80e2fa5b1c0750c36c56fe1f9da55a3fb8e1b2fc953a407bb504a7
  - byte-equal round-trip confirmed

Fixes:
  - default ANTD port 8000 -> 8082 (the actual antd REST port per antd-py)
  - /v1/files/prepare_upload_public -> /v1/upload/prepare with visibility=public
  - /v1/files/finalize_upload -> /v1/upload/finalize
  - /v1/files/download_public -> /v1/files/download/public
  - download body key 'path' -> 'dest_path'

Paths cross-checked against antd-py/src/antd/_rest.py — the same conventions
all 15 SDKs use, so the doc accurately reflects what V2-312 needs to follow.
@Nic-dorman
Copy link
Copy Markdown
Collaborator Author

Validated end-to-end against ant dev start --enable-evm on dev2:

OK  uploaded + downloaded 352 bytes via external signer
    data_map_address = 280cca01b194fd1b402457990fc497f5a7f6fe84b09015a36346fcc86bba421e
    payForQuotes tx  = 470b1de38f80e2fa5b1c0750c36c56fe1f9da55a3fb8e1b2fc953a407bb504a7

Validation surfaced four bugs in the initial draft (all now fixed in the latest commit):

  • Default ANTD port 80008082 (the actual antd REST port per antd-py)
  • /v1/files/prepare_upload_public/v1/upload/prepare with visibility=public in the body
  • /v1/files/finalize_upload/v1/upload/finalize
  • /v1/files/download_public/v1/files/download/public, body key pathdest_path

Worth the validation round — these would have been per-SDK papercuts in V2-312 had the doc shipped unverified.

@Nic-dorman Nic-dorman merged commit 6c859bb into main May 19, 2026
Nic-dorman added a commit that referenced this pull request May 21, 2026
Cuts v0.8.0 atop v0.7.1. Substantial breaking-change roll-up of the
put/get rename, the private-file PUT/GET gap close, and several minor
surface cleanups -- bundled here so the v1.0 cut can ship stable on top.

## Breaking (antd daemon)

- feat(antd)!: bind to 127.0.0.1 by default on REST and gRPC (#107).
  Previously bound 0.0.0.0; use --bind-rest / --bind-grpc to override.
- chore: remove dead graph_entry surface from antd proto + 5 SDKs (#92).
  GraphService and its 4 RPCs are gone; REST mounts dropped.
- chore: remove dir_upload_public / dir_download_public surface (#95).
  Use file_put_public on a directory path instead; the daemon recurses.
- feat(antd)!: normalize put/get convention + close private-file PUT and
  GET gaps (#115). Method renames across proto + REST + SDKs:
    data_put_private    -> data_put
    data_get_private    -> data_get
    file_upload_public  -> file_put_public
    file_download_public -> file_get_public
  New: file_put / file_get for the private file path (previously only
  the public variant existed). New typed results: DataPutResult,
  DataPutPublicResult, FilePutResult, FilePutPublicResult; PutResult
  is now annotated as chunk_put only.

## Additive

- feat(antd): honor payment_mode on gRPC put/cost paths and REST cost
  endpoints (#114). Optional kwarg threaded through every put/cost
  signature; empty/omitted maps to "auto" so older clients keep working.
- feat: external-signer public uploads + single-chunk prepare/finalize
  across 15 SDKs (#90).
- docs+spec: openapi.yaml refreshed for the v1.0 surface, including
  POST /v1/chunks/prepare and /v1/chunks/finalize for single-chunk
  external-signer publish (#126).

## SDK fan-out (PaymentMode + put/get convention, all 15)

#116 antd-go, #117 antd-py/ruby/elixir, #118 antd-rust, #119 antd-csharp,
#120 antd-java, #121 antd-swift, #122 antd-dart, #123 antd-kotlin,
#124 antd-cpp, #125 antd-js/php/zig/lua, #127 antd-mcp.

## SDK example + build fixes

- fix(antd-go): make 03-files example self-contained and runnable (#91)
- fix(examples): make 04-files runnable across cpp/rust/elixir/lua/php/ruby/zig (#93)
- fix(examples): runnable dart 04_files + java Example03Files; add java Example03Chunks (#94)
- feat: gRPC transport example for antd-py and antd-rust (#113)
- feat(antd-py): 07_external_signer example + ant-dev dispatcher entry (#98)
- feat(antd-js): 07-external-signer example + antd-py empty-payments fix (#99)
- feat(rust/go): 07-external-signer examples (#100)
- feat(antd-csharp): 07_external_signer example (#101)
- feat(antd-java): 07_external_signer example (#102)
- feat(antd-kotlin): 07_external_signer example (#103)
- feat(antd-dart): 07_external_signer example (#104)
- feat(antd-ruby): 07_external_signer example (#105)
- feat(antd-php): 07_external_signer example (#106)
- chore(antd-kotlin): drop stale GraphDescendant from local proto copy (#108)

## Docs / infra

- docs: external-signer flow reference + ABI + python smoke test (#97)
- docs: add SECURITY.md with threat model and disclosure policy (#109)
- docs!: refresh per-SDK READMEs + llms-full.txt + openapi.yaml for v1.0 surface (#126)
- ci: add Go lint + test + vuln scanning for antd-go (#112)
- ci: extend antd-rust to sibling-repo parity (fmt + clippy + audit + doc) (#111)
- ci: skip antd/openapi.yaml and llms-full.txt from triggering CI (#128)
- chore(scripts): add full-stack + integration sweep helpers (#96)
- fix(antd-rust): regenerate Cargo.lock to unbreak --locked CI (#110)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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