Skip to content

fix(examples): run every example as shipped against Devnet, and run them daily in CI - #39

Merged
isaacdoidge merged 9 commits into
masterfrom
fix/examples
Nov 4, 2026
Merged

isaacdoidge merged 9 commits into
masterfrom
fix/examples

Conversation

@isaacdoidge

@isaacdoidge isaacdoidge commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

What

The examples now run as shipped:

  • They default to Devnet.
  • They take the network and an optional funded key from the environment.
  • Without a key, each example except faucet.py funds one account from the faucet, and retries a TryLater answer
    a bounded number of times. With a key, only faucet.py calls the faucet.
  • They need no sibling aptos-core checkout or Move toolchain.

A scheduled workflow runs all of them against Devnet.

Changes

  • examples/common.py:
    • SUPRA_RPC_NODE_URL defaults to https://rpc-devnet.supra.com. SUPRA_FAUCET_URL defaults to the RPC URL.
    • SUPRA_EXAMPLES_PRIVATE_KEY (hex) is optional; an empty or whitespace-only value counts as unset.
    • fund_accounts with a key funds each account by transfer from the key's account. It first checks that the
      balance covers the amounts plus gas, and names the shortfall in SUPRA.
    • Without a key it funds a generated funder from the faucet and transfers from it. A TryLater answer is retried:
      at most 5 requests, with pauses of 5, 10, 20 and 40 s, failing after the fifth TryLater. Only the request is
      retried; after the faucet accepts one, the example waits once for its transaction and fails unless it ends in
      Success, so an accepted request is never repeated.
    • The balance check reserves 2,000 gas units per transfer. A transfer to a new account uses about 1,000 units on
      Devnet today and the SDK's max gas estimate is 1.5 times that; the check is made before sending.
    • It refuses chain ID 8 (Mainnet). It prints addresses, never keys.
  • Compiled Move packages:
    • examples/move/packages.json holds the metadata and bytecode of hello_blockchain, moon_coin and
      upgrade_and_govern (genesis and upgrade). They are compiled from the Apache-2.0 sources at
      Entropy-Foundation/aptos-core tag aptosvm-v1.16_supra-v1.8.9.
    • compiled_package replaces the placeholder publisher address (32 random bytes, matched exactly) with the
      publisher's address.
    • your_coin.py, multisig.py and hello_blockchain.py publish these instead of shelling out to
      supra move tool compile.
  • Per example:
    • transfer_coin.py funds the second account by transfer rather than with a second faucet call.
    • aiofiles is dropped: transfer_two_by_two.py reads its script with pathlib.
    • rotate_key.py no longer prints part of the private key.
    • simulate_transfer_coin.py sets an explicit max gas, so the estimate does not simulate a transfer that is
      expected to fail. It asserts that the first simulation reports a Fail status whose vm_status names
      ECOIN_STORE_NOT_PUBLISHED, which is how rc7 and v11.7.2 nodes report the abort.
    • fungible_asset.py (added by feat(client): add fungible asset balance, transfer, migration and transaction helpers #31) funds its account with the shared helper and runs in make examples.
    • automation.py uses a 3600 s duration, because a v11.7.2 localnet caps task duration at 7200 s. It retries
      registration and stop on ECYCLE_TRANSITION_IN_PROGRESS.
    • Every main is annotated, and mypy now covers examples/.
  • pyproject.toml and uv.lock: aiofiles and the unreleased examples extra are removed. The lock was
    regenerated with uv 0.13.7, so its revision stays 5; the only change is aiofiles.
  • Makefile: make examples refuses to start when SUPRA_RPC_NODE_URL is unset, empty or whitespace. It runs
    all 14 examples and fails at the end, listing the failed ones.
  • .github/workflows/examples.yaml:
    • Runs daily and on workflow_dispatch only, so fork pull requests cannot start it.
    • contents: read; concurrency group examples-devnet, so two runs never send from the same account at once.
    • A first step receives the secret through env and writes only whether it is present (whitespace counts as
      absent). Without it the job skips with a notice.
    • setup-uv installs uv 0.13.7, and uv sync --frozen runs before the secret is in the environment. The step with
      the secret sets UV_FROZEN=1 and UV_NO_SYNC=1, so nothing is resolved, downloaded or installed while the key
      is present.
    • Actions are pinned as in checks.yaml.
  • examples/README.md: networks, environment variables, funding and TryLater, how to run one or all examples,
    what each shows, and how packages.json was built.

Maintainers: create the repository secret SUPRA_EXAMPLES_PRIVATE_KEY, holding the hex Ed25519 private key of an
account funded on Devnet. A full run moves about 325 SUPRA from it.

Checks

  • make fmt-check, make lint, make typecheck (44 files, examples included), make test-unit (332 tests, OK, 26
    node-backed skipped), make test-spec (248 scenarios), make build: pass. actionlint: clean.
  • After merging master and the review fixes: make examples passed all 14 examples on a fresh
    supra_node_v12.0.0.rc7 localnet without a key. A whitespace-only SUPRA_RPC_NODE_URL makes make examples refuse
    (checked with make -n).
  • Before the merge, all 13 examples then in the PR passed on a supra_node_v12.0.0.rc7 localnet and on a supra_node_v11.7.2 localnet, each with
    faucet funding and with a funded key: 52 runs. make examples passed on rc7 without and with a key, and on v11.7.2
    without one. The output of the keyed runs does not contain the key.
  • packages.json is byte-identical to a fresh compile of the four packages from tag aptosvm-v1.16_supra-v1.8.9
    (and from the fork's later tags, whose sources are unchanged), compiled with the supra CLI of
    supra_node_v11.7.2.
  • The workflow was not run, because it transacts on Devnet.

🤖 Generated with Claude Code

isaacdoidge and others added 9 commits November 4, 2026 02:02
…ithout CoinStore

Nodes whose genesis enables the fungible-asset migration keep SUPRA in primary
fungible stores: accounts have no CoinStore<SupraCoin>, transfers emit
0x1::fungible_asset::Deposit and Withdraw, and account_coin_transactions lists
no SUPRA movement. The coin-transaction and events-by-type tests now pick their
expectations by whether the account holds the CoinStore.

The automation registration in the tests and in examples/automation.py used a
gas price cap of 100, below the node's minimum gas price, which the node refuses
at validation. The cap now comes from estimate_gas_price()'s
min_configured_gas_price. The cancel and stop tests expect the V2 events the
framework emits. The example no longer suggests passing a task type and priority
together, and treats task index 0 as valid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he automation example

The type of a SUPRA deposit event follows the receiver's layout (CoinStore or
primary fungible store), not the sender's. The coin-transaction and
events-by-type tests now choose it from the receiver. Where the receiver uses a
primary fungible store, the test checks that the Deposit event's store is the
receiver's primary store (from the primary_store_address view) and that its
amount is the transferred amount, and that an empty coin-transaction listing
carries no cursor. The event extraction helper is shared by the tests.

examples/automation.py takes its gas price cap from the recent median price,
bounded by the node's minimum and maximum, because a task is skipped in blocks
priced above its cap. The comment on task type and priority states which
combinations the registry accepts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The examples read the RPC node from SUPRA_RPC_NODE_URL (default Devnet,
https://rpc-devnet.supra.com) and the faucet node from SUPRA_FAUCET_URL
(default the RPC node). `common.fund_accounts` funds the accounts an example
generates: by transfers from the account of SUPRA_EXAMPLES_PRIVATE_KEY when it
is set, otherwise from one account funded by a single faucet request. No
example except `faucet.py` calls the faucet more than once, and `faucet.py`
makes one request. `fund_accounts` refuses Mainnet.

The Move packages that `your_coin.py`, `multisig.py` and `hello_blockchain.py`
publish are committed in compiled form in `examples/move/packages.json`,
compiled for a placeholder address that `common.compiled_package` replaces
with the publisher's. The examples no longer run `supra move tool compile`
on a sibling aptos-core checkout. `hello_blockchain.py` publishes its package
when no address is given.

`aiofiles` is dropped: the examples read files with `pathlib`. The unreleased
`examples` extra and the dev dependency are removed.

Other changes:
- `rotate_key.py` no longer prints part of each private key.
- `simulate_transfer_coin.py` sets max gas, since the estimate's simulation
  fails while the receiver has no coin store.
- `automation.py` registers a task of one hour, within the 7200-second cap
  of a localnet, sends the registration and the stop again while the
  registry reports a cycle transition, and uses the estimated max gas.
- `main` functions are annotated, so that mypy checks their bodies, and mypy
  now checks `examples/` (`make typecheck` and CI).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`.github/workflows/examples.yaml` runs `make examples` against Devnet on a
daily schedule and on `workflow_dispatch`, funding the examples' accounts from
the repository secret SUPRA_EXAMPLES_PRIVATE_KEY. Without the secret the job
runs no example and reports a notice. Runs share one concurrency group, so two
runs never send from the account at once.

`make examples` now runs all thirteen examples, including `faucet` and
`hello_blockchain`, stops at the first failure, and refuses to run unless
SUPRA_RPC_NODE_URL is set, so that the network it transacts on is explicit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The examples README lists the networks, the environment variables and how the
examples fund their accounts, how to run one example or all of them, what each
example shows, and how the compiled Move packages in `move/packages.json`
were built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… run every example in CI

- The faucet request is sent at most five times, after pauses of 5, 10, 20
  and 40 seconds, while the faucet answers "TryLater". The retry catches
  FaucetRequestNotAcceptedError and the AttributeError that SDK versions
  without "TryLater" handling raise for that answer.
- Before funding, `fund_accounts` checks that the funding account holds the
  amount it sends plus 2,000 gas units per transfer at the node's minimum
  gas price, and otherwise stops with the shortfall in SUPRA.
- A whitespace-only SUPRA_EXAMPLES_PRIVATE_KEY, SUPRA_RPC_NODE_URL or
  SUPRA_FAUCET_URL counts as unset.
- `simulate_transfer_coin.py` asserts that the first simulation reports the
  ECOIN_STORE_NOT_PUBLISHED abort, and reads the simulation output with
  `.get`.
- `make examples` runs every example, then fails and lists the failed ones
  if any failed.
- The Devnet workflow installs with `uv sync --frozen` before the step that
  sees the key, and that step runs with UV_FROZEN=1.
- uv.lock keeps lock revision 5 (written with uv 0.13.7).
- The examples README names the public source tag
  aptosvm-v1.16_supra-v1.8.9, from which the compiled packages are
  byte-identical, states that the sources are Apache-2.0, and describes the
  faucet retry, the balance check and the sequence-number race between two
  runs that share a key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e examples workflow

The faucet retry loop sends only the request (`wait_for_faucet=False`) and treats
as TryLater a missing transaction hash, `FaucetRequestNotAcceptedError`, or the
`AttributeError` that SDK versions without TryLater handling raise from the
request. It sends at most five requests, with pauses of 5, 10, 20 and 40
seconds. After an accepted request it waits for the faucet transaction once,
outside the retry, and fails if the transaction does not end in `Success`.

`make examples` refuses a whitespace-only SUPRA_RPC_NODE_URL, which the
examples treat as unset.

The Examples workflow decides whether a funded key is present in a first step
that receives the secret through `env`, strips whitespace and writes only
`present=true|false`; a whitespace-only secret skips the job like a missing one.
setup-uv installs uv 0.13.7, and the step that holds the key sets UV_NO_SYNC
next to UV_FROZEN so nothing is resolved or installed while the key is present.

The gas reserve comment states what the 2,000-unit reservation assumes, and
examples/README.md states which examples retry TryLater.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fungible_asset.py funds Alice with `fund_accounts`, so it uses the Devnet default,
the optional funded key, the bounded TryLater retry and the Mainnet refusal. Bob
is not funded; the fungible asset transfer creates his primary store. `make
examples` runs it, and examples/README.md describes it and counts its 10 SUPRA.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@isaacdoidge
isaacdoidge changed the base branch from test/rc7-node-backed to master November 4, 2026 00:53
@isaacdoidge
isaacdoidge merged commit 86b5479 into master Nov 4, 2026
5 checks passed
@isaacdoidge
isaacdoidge deleted the fix/examples branch November 4, 2026 01:46
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