Skip to content

feat: add register_import! for testing import_contract! callers - #77

Merged
pselle merged 24 commits into
mainfrom
feat/register-import
Nov 5, 2026
Merged

pselle merged 24 commits into
mainfrom
feat/register-import

Conversation

@pselle

@pselle pselle commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Part of #65

import_contract! bakes the imported contract's on-chain address in at build time, so a unit test's Env has nothing there. This adds register_import!, behind a new testutils feature on stellar-registry, which resolves the name the same way and registers the imported Wasm, or a native mock, at that address. Constructor args are passed by name and type-checked against the contract's constructor: register_import!(&env, our_dao, args = { admin, quorum: 7u32 }).

Tests run with STELLAR_NETWORK=testnet cargo test, which caches the id and Wasm so later runs can go offline with STELLAR_NO_REGISTRY=1. The hello_caller fixture is excluded from the workspace because it needs seeded cache files, and just test-register-import runs it offline in CI.

This also changes one CLI error. On a local network with no registry deployed, every stellar registry command (and so import_contract!'s lookup) failed with a bare "not found"; the CLI now checks for the root registry on local first and says what to do. Other networks skip the check.

Before:

error: Contract not found: CA55VGAFPIZHOY2X26KANRJYFBWPEXGNLIEHR7Q5TR2576HKHOFPLBTX

After:

error: no Stellar Registry is deployed on the local network (looked for one at CA55VGAFPIZHOY2X26KANRJYFBWPEXGNLIEHR7Q5TR2576HKHOFPLBTX). Deploy the registry contract on local and set STELLAR_REGISTRY_CONTRACT_ID to its id, or set up local development with Stellar Scaffold.

`import_contract!` bakes a real on-chain address into a contract, and
nothing lives at that address in a sandboxed test `Env`. Add
`stellar_registry::testutils::register_import!` (behind a new `testutils`
feature), which resolves a name through the same code as
`import_contract!` and registers the imported Wasm, or a native mock, at
that address with `Env::register_at`.

Stellar Asset Contracts are a compile error for now.

The new `hello_caller` fixture imports `hello_v1` and tests itself with
`register_import!`. It is excluded from the workspace, since it needs
seeded cache files to compile; `just test-register-import` seeds them and
runs it offline, and CI runs that recipe.

Part of #65

Co-Authored-By: Claude <noreply@anthropic.com>
@pselle pselle self-assigned this Oct 13, 2026
pselle and others added 2 commits October 13, 2026 14:10
Co-Authored-By: Claude <noreply@anthropic.com>
The fixture sits outside the workspace, so it does not pick up the
workspace's soroban-sdk bump.

Co-Authored-By: Claude <noreply@anthropic.com>
@pselle
pselle marked this pull request as ready for review October 14, 2026 01:18
@pselle
pselle requested a review from chadoh October 14, 2026 01:21
chadoh
chadoh previously requested changes Oct 15, 2026

@chadoh chadoh left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been thinking about this for hours and I still haven't finished reading it all but it's time to give you my first wall of thoughts!!! 😂 😖 🙇🏼 🙇🏼 🙇🏼

(Take this as a good thing! You came up with an interesting solution to a problem I hadn't yet really thought through and it spurred some ideas!!)

Also, as always, I'm open to pushback on any of this! We don't have to do it the ways I'm contemplating, or we do not need to do them right now. Maybe it's fine to do an initial fast release with a cleanup update later.

Comment thread crates/stellar-registry/README.md Resolved
Comment thread crates/stellar-registry/README.md Resolved
Comment thread justfile Resolved
Comment thread Cargo.toml Resolved
pselle and others added 7 commits October 16, 2026 09:09
Co-authored-by: Chad Ostrowski <221614+chadoh@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
`args = { admin, quorum: 7u32 }` passes constructor arguments by name.
The macro reads the constructor's parameters from the imported Wasm's
spec, orders the values to match, and calls the typed
`Args::__constructor` that `contractimport!` generates, so names and
types are checked at compile time. Leaving out `args` when the
constructor takes parameters is a compile error listing them. The tuple
form still works and is type-checked too.

Co-Authored-By: Claude <noreply@anthropic.com>
Resolve the Cargo.lock conflict from main's dependency bumps. main moved
stellar-xdr to 30 while soroban-spec 28 uses stellar-xdr 28, so read only
the raw spec section with soroban-spec and parse it with this crate's
stellar-xdr.

Co-Authored-By: Claude <noreply@anthropic.com>
The new `unverified_caller` fixture imports `unverified`, the root
registry's subregistry on testnet, and tests itself with
`register_import!` and named constructor args. `just
test-register-import-testnet` runs it with `STELLAR_NETWORK=testnet`, so
the id and Wasm are really fetched. It needs network access, so CI
doesn't run it.

Co-Authored-By: Claude <noreply@anthropic.com>
Drop its committed Cargo.lock (it only runs manually, online) and trim
its comments.

Co-Authored-By: Claude <noreply@anthropic.com>
`unverified` is the subregistry itself; `unverified/my-token` is an
ordinary registered contract, and its five-argument constructor
exercises named args more fully.

Co-Authored-By: Claude <noreply@anthropic.com>
@pselle

pselle commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor Author

Ok, I've resolved all the comments. I added typed args, but the from_network didn't make sense because STELLAR_NETWORK covers that.

I also added a recipe for testing through a contract build on testnet, alas that adds another fixture so that I can import that specific contract (alternatively, we could deploy hello_v1 or a different fixture to testnet ... but unverified/token is from the oz-wasms and I thought it fit well).

The perk of adding the fixture is that it shows the full example within the repo of how you'd use import_contract and then use register_contract, which I think was what you were aiming for. I like the token one too because it does have a handful of args, so it showcases the typed args well.

@pselle
pselle requested a review from chadoh October 16, 2026 15:20
@pselle
pselle dismissed chadoh’s stale review October 16, 2026 20:29

Resolved comments

Main now derives asset-syntax SAC addresses at runtime, so resolve()
returns a new Resolved::Asset carrying the asset XDR instead of a
build-time address. register_import! rejects it like any other SAC, and
its expansion now tracks the network env so it re-expands alongside
import_contract! when the network changes.

Co-Authored-By: Claude <noreply@anthropic.com>
@chadoh

chadoh commented Nov 2, 2026

Copy link
Copy Markdown
Member

from_network didn't make sense because STELLAR_NETWORK covers that

I am building for local but I want to pull a contract/Wasm from testnet. STELLAR_NETWORK covers the target for the build, but I still need a way to say where to fetch this Wasm from.

pselle and others added 2 commits November 3, 2026 04:27
Co-Authored-By: Claude <noreply@anthropic.com>
Copies a registered contract from another network: look the name up on
`--from-network` (refusing flagged contracts unless `--force`), fetch the
deployed contract's Wasm, deploy it on the target network with the given
constructor args, and register it there under the same name or `--as`.
This lets a local network hold a real copy of a contract that
`import_contract!` can then resolve.

Co-Authored-By: Claude <noreply@anthropic.com>
@pselle pselle changed the title feat: add register_import! for testing import_contract! callers feat: register_import! and clone-contract for import_contract! callers Nov 3, 2026
pselle and others added 3 commits November 3, 2026 04:48
`STELLAR_REGISTRY_CONTRACT_ID` points at one registry deployment, usually
a local one, so applying it to the source network made a testnet-to-local
copy look the name up at the local registry's id on testnet. Use the
source network's canonical root registry unless source and target are
the same network.

Co-Authored-By: Claude <noreply@anthropic.com>
`stellar registry deploy --contract-name <name> --from-network testnet -- <args>`
copies a contract registered on another network: it fetches the deployed
Wasm there, deploys it here from the source account (not through the
registry's `deploy`) and registers it as `--contract-name`.
`--from-contract-name` names it on the source network when different;
`--force` copies a flagged contract. This replaces the separate
`clone-contract` command.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@pselle pselle changed the title feat: register_import! and clone-contract for import_contract! callers feat: register_import! and deploy --from-network for import_contract! callers Nov 3, 2026
A fresh local network has nothing at the root registry address, so every
registry command failed with a bare "contract not found". On local, check
the root first and say how to fix it: deploy the registry contract and set
STELLAR_REGISTRY_CONTRACT_ID, or use Stellar Scaffold.

Co-Authored-By: Claude <noreply@anthropic.com>
@pselle

pselle commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor Author

Macros shouldn't deploy anything, so the contract's own import_contract! will fail on local unless the dependency is actually deployed and registered there. By hand, that's stellar registry fetch-contract-id <name> --network testnet, then stellar contract fetch --id <id> --network testnet to get its Wasm, then deploy it on local and stellar registry register-contract it.

Since this seemed to be a blocker for you, I added it to this PR rather than a follow-on, though it does expand the PR:

stellar registry deploy --contract-name unverified/my-token --from-network testnet -- <constructor args>

It copies the contract from testnet to local and registers it under the same name, so import_contract! resolves on local as usual.

One caveat: the local network needs a root registry deployed first, with STELLAR_REGISTRY_CONTRACT_ID pointing at it (the integration tests do the same). "You need a local registry" is another foot gun, and we could do some things to help with that; I would rather not also tack that into this PR as well. Something like adding a bootstrap command to the registry CLI that fetches the registry's wasm from testnet and deploys it locally with a predictable/derived address (like testnet and mainnet). I can add an issue for this if we want it.

Getting a contract onto a local network is a separate concern from
testing with register_import!, so it moves out of this PR. This restores
the CLI and stellar-registry-build to how they were before clone-contract,
including dropping the missing-local-registry error that went with it.

Co-Authored-By: Claude <noreply@anthropic.com>
@pselle pselle changed the title feat: register_import! and deploy --from-network for import_contract! callers feat: add register_import! for testing import_contract! callers Nov 4, 2026
A fresh local network has nothing at the root registry address, so every
registry command failed with a bare "contract not found". On local, check
the root first and say how to fix it: deploy the registry contract and set
STELLAR_REGISTRY_CONTRACT_ID, or use Stellar Scaffold.

Co-Authored-By: Claude <noreply@anthropic.com>

@chadoh chadoh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allllmost. This is looking really good. I have a few small-i-swear ideas for cleanup before we merge, though as always I'm happy to be convinced that the current shape of it is good enough, in which case I'll update with the ✅

Comment thread justfile Resolved
Comment thread crates/stellar-registry/README.md Resolved
Comment thread crates/stellar-registry/README.md Resolved
pselle and others added 5 commits November 4, 2026 16:44
- Move register_import! and its tests into register.rs; contract.rs
  keeps the shared resolve.
- Drop the token_caller fixture and test-register-import-testnet recipe.
- README: workspace dependencies in the example, link the justfile.
- Docs: trim the args text, say tuple args are allowed with `contract`
  but named args aren't, and say the name must match the contract's
  import_contract! call.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Drop the shorthand note from the README, add a missing period, keep
type-checked on one line in the macro docs, list the named `args` form
in the unknown-option error, and list register_import! in CLAUDE.md.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@pselle
pselle requested a review from chadoh November 5, 2026 16:44

@chadoh chadoh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all the exploration here! Looks like a great starting point now.

@pselle
pselle merged commit fa49d99 into main Nov 5, 2026
5 checks passed
@pselle
pselle deleted the feat/register-import branch November 5, 2026 19:34
@aha-release-plz aha-release-plz Bot mentioned this pull request Nov 5, 2026
pselle pushed a commit that referenced this pull request Nov 9, 2026
## 🤖 New release

* `stellar-registry-macro`: 0.1.3 -> 0.1.4
* `stellar-registry`: 0.1.3 -> 0.1.4 (✓ API compatible changes)
* `stellar-registry-build`: 0.2.0 -> 0.3.0 (⚠ API breaking changes)
* `stellar-registry-cli`: 0.3.0 -> 0.3.1 (✓ API compatible changes)

### ⚠ `stellar-registry-build` breaking changes

```text
--- failure enum_variant_added: enum variant added on exhaustive enum ---

Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.51.0/src/lints/enum_variant_added.ron

Failed in:
  variant Error:NoLocalRegistry in /tmp/.tmpx1tFqO/cli/crates/stellar-registry-build/src/error.rs:35
  variant Error:NoLocalRegistry in /tmp/.tmpx1tFqO/cli/crates/stellar-registry-build/src/error.rs:35
```

<details><summary><i><b>Changelog</b></i></summary><p>

## `stellar-registry-macro`

<blockquote>

##
[0.1.4](stellar-registry-macro-v0.1.3...stellar-registry-macro-v0.1.4)
- 2026-11-09

### Added

- support Stellar Asset Contracts in register_import!
([#82](#82))
- add register_import! for testing import_contract! callers
([#77](#77))
</blockquote>

## `stellar-registry`

<blockquote>

##
[0.1.4](stellar-registry-v0.1.3...stellar-registry-v0.1.4)
- 2026-11-09

### Added

- support Stellar Asset Contracts in register_import!
([#82](#82))
- add register_import! for testing import_contract! callers
([#77](#77))
</blockquote>

## `stellar-registry-build`

<blockquote>

##
[0.3.0](stellar-registry-build-v0.2.0...stellar-registry-build-v0.3.0)
- 2026-11-09

### Added

- add register_import! for testing import_contract! callers
([#77](#77))
</blockquote>

## `stellar-registry-cli`

<blockquote>

##
[0.3.1](stellar-registry-cli-v0.3.0...stellar-registry-cli-v0.3.1)
- 2026-11-09

### Added

- add register_import! for testing import_contract! callers
([#77](#77))

### Fixed

- read-only commands don't require a source account
([#112](#112))

### Other

- *(deps)* bump shlex from 1.3.0 to 2.0.1
([#105](#105))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: aha-release-plz[bot] <211513279+aha-release-plz[bot]@users.noreply.github.com>
pselle added a commit that referenced this pull request Nov 11, 2026
Part of #65

On `STELLAR_NETWORK=local`, when `import_contract!` or
`import_contract_client!` can't find a name in the local registry, the
"Things to try" list now also suggests Stellar Scaffold for predictable
local builds. Other networks are unchanged, and a missing local registry
already has its own error from #77.

Before (building a contract that imports `hello_v1`, against a local
registry without it):
```
error: Could not resolve a contract id for `hello_v1` on local. Things to try:

       - Run `stellar registry fetch-contract-id hello_v1` yourself and make sure the name and network match your expectations.
       - Set STELLAR_NO_REGISTRY=1 to prevent network calls. You will need to create …/target/stellar/local/deployed/hello_v1.id and …/target/stellar/local/deployed/hello_v1.wasm yourself, perhaps using `stellar registry fetch-contract-id` for the id and `stellar contract fetch` for the wasm.

       stderr from `stellar registry fetch-contract-id`:
       error: transaction simulation failed: HostError: Error(Contract, #4)
       …
```

After:
```
error: Could not resolve a contract id for `hello_v1` on local. Things to try:

       - Run `stellar registry fetch-contract-id hello_v1` yourself and make sure the name and network match your expectations.
       - Set STELLAR_NO_REGISTRY=1 to prevent network calls. You will need to create …/target/stellar/local/deployed/hello_v1.id and …/target/stellar/local/deployed/hello_v1.wasm yourself, perhaps using `stellar registry fetch-contract-id` for the id and `stellar contract fetch` for the wasm.
       - Use Stellar Scaffold to achieve predictable local builds: https://stellarscaffold.org

       stderr from `stellar registry fetch-contract-id`:
       error: transaction simulation failed: HostError: Error(Contract, #4)
       …
```

---------

Co-authored-by: Claude <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.

2 participants