Skip to content

feat: add IOTA Names example in Rust and all bindings#990

Open
EasonC13 wants to merge 5 commits intoiotaledger:developfrom
EasonC13:feat/iota-names-example
Open

feat: add IOTA Names example in Rust and all bindings#990
EasonC13 wants to merge 5 commits intoiotaledger:developfrom
EasonC13:feat/iota-names-example

Conversation

@EasonC13
Copy link

Summary

Closes #514

Add a comprehensive IOTA Names example demonstrating all major operations, implemented in Rust and all bindings (Python, Kotlin, Go, Swift).

What's included

New files:

  • crates/iota-sdk/examples/iota_names.rs
  • bindings/python/examples/iota_names.py
  • bindings/kotlin/examples/IotaNames.kt
  • bindings/go/examples/iota_names/main.go
  • bindings/swift/examples/iota_names.swift

4 operations demonstrated:

  1. Name lookup: resolve an IOTA name (e.g. name.iota) to an address
  2. Reverse lookup: resolve an address back to its IOTA name
  3. Name record details: query expiration timestamp and target address
  4. Check existence: verify if a name is registered

All operations use dev_inspect (dry run), so no gas or signing is needed.

Network support:

  • Supports both devnet and mainnet via CLI args
  • Usage: cargo run --example iota_names -- name.iota mainnet
  • Default: devnet with name.iota

Testing

All 5 languages tested on both devnet and mainnet:

Language devnet mainnet
Rust
Python
Swift
Kotlin
Go

Sample output (Rust, devnet):

=== IOTA Names Examples (devnet) ===

1. Looking up 'name.iota'...
   Resolved to: 0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900

2. Reverse lookup for 0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900...
  Address 0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900 has a reverse name record

3. Querying name record details for 'name.iota'...
  Name record details for 'name.iota':
  Expiration timestamp (ms): 1783692571549
  Target address: 0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900

4. Checking name existence...
   'name.iota' exists: true
   'this-name-probably-does-not-exist-12345.iota' exists: false

Add comprehensive IOTA Names example demonstrating:
1. Name lookup (name -> address) using resolve_address
2. Reverse lookup (address -> name)
3. Name record details (expiration timestamp, target address)
4. Check name existence (has_record)

All operations use dev_inspect (dry run) so no gas or signing is needed.

Examples added for:
- Rust: crates/iota-sdk/examples/iota_names.rs
- Python: bindings/python/examples/iota_names.py
- Kotlin: bindings/kotlin/examples/IotaNames.kt
- Go: bindings/go/examples/iota_names/main.go
- Swift: bindings/swift/examples/iota_names.swift

Closes iotaledger#514
- Add IotaNamesConfig for devnet/mainnet addresses
- Support CLI args: cargo run --example iota_names -- <name> <network>
- Handle names with no target address set (Option::None)
- Tested on devnet (name.iota) and mainnet (giverep.iota)
- Add mainnet IOTA Names config (package + object addresses) to all 5 languages
- Add CLI args support (name, network) to Python, Kotlin, Go, Swift
- Fix name_record_details to check existence before querying (prevents option::borrow abort)
- Tested on devnet and mainnet for Rust, Python, Swift, Kotlin, Go
@EasonC13 EasonC13 requested a review from a team as a code owner February 26, 2026 12:27
Comment on lines +351 to +357
let name = args.get(1).map(|s| s.as_str()).unwrap_or("name.iota");
let network = args.get(2).map(|s| s.as_str()).unwrap_or("devnet");

let (client, config) = match network {
"mainnet" => (Client::new_mainnet(), IotaNamesConfig::mainnet()?),
_ => (Client::new_devnet(), IotaNamesConfig::devnet()?),
};
Copy link
Member

Choose a reason for hiding this comment

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

I would just use testnet here, no need to make the examples more complicated with multiple networks and the devnet will be reset next week
Also right now the example only does read operations, there should be also examples (dry run) for how to register a name, register a subname, extend the expiration, set metadata (might make sense to have these in another file to not make this one too big)
Also the copyright year in the files should be 2026

Copy link
Member

@thibault-martinez thibault-martinez left a comment

Choose a reason for hiding this comment

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

We have merged C# since you opened the PR, would you mind adding an example for it? Otherwise we will do it.

@EasonC13
Copy link
Author

EasonC13 commented Mar 5, 2026

Let me look into it.

Add IotaNames example for C# bindings with all 4 operations:
1. Name lookup (name -> address)
2. Reverse lookup (address -> name)
3. Name record details (expiration timestamp, target address)
4. Check name existence (has_record)

Includes devnet/mainnet config and CLI args support.
Matches the pattern of existing Rust, Python, Kotlin, Go, Swift examples.
@EasonC13
Copy link
Author

EasonC13 commented Mar 7, 2026

@thibault-martinez done, please check.

}

impl IotaNamesConfig {
fn devnet() -> Result<Self> {
Copy link
Contributor

Choose a reason for hiding this comment

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

These are available in the library via IotaNamesConfig

let obj = config.object_id;
let sender = Address::from_str("0x0")?;

let mut builder = TransactionBuilder::new(sender).with_client(client.clone());
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
let mut builder = TransactionBuilder::new(sender).with_client(client.clone());
let mut builder = TransactionBuilder::new(sender).with_client(client);

Copy link
Contributor

Choose a reason for hiding this comment

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

These fetches may be better as dynamic field queries rather than dry runs. This is how it's done in the CLI for instance. We could use the client's dynamic_field fn like so:

let entry: RegistryEntry = bcs::deserialize(&client.dynamic_field(IotaNamesConfig::testnet().registry_id.into(), TypeTag::new_name(), Name::from_str(name)?)).await?)?;
let target_address = entry.name_record.target_address;

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.

[Bounty] Add IOTA Names example

5 participants