From 8f04df6fec373409351929ab72ecd328e9fdcebc Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Thu, 2 Oct 2025 10:05:09 +0200 Subject: [PATCH 1/2] chore(examples): Add `send_coins` example --- .../go/examples/prepare_send_coins/main.go | 52 ++++++++++++++++++ bindings/kotlin/examples/PrepareSendCoins.kt | 54 ++++++++++++++++++ .../python/examples/prepare_send_coins.py | 55 +++++++++++++++++++ .../examples/prepare_send_coins.rs | 52 ++++++++++++++++++ 4 files changed, 213 insertions(+) create mode 100644 bindings/go/examples/prepare_send_coins/main.go create mode 100644 bindings/kotlin/examples/PrepareSendCoins.kt create mode 100644 bindings/python/examples/prepare_send_coins.py create mode 100644 crates/iota-graphql-client/examples/prepare_send_coins.rs diff --git a/bindings/go/examples/prepare_send_coins/main.go b/bindings/go/examples/prepare_send_coins/main.go new file mode 100644 index 000000000..99fea90b3 --- /dev/null +++ b/bindings/go/examples/prepare_send_coins/main.go @@ -0,0 +1,52 @@ +// Copyright (c) 2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "log" + + sdk "bindings/iota_sdk_ffi" +) + +func main() { + client := sdk.GraphQlClientNewDevnet() + + fromAddress, _ := sdk.AddressFromHex("0x611830d3641a68f94a690dcc25d1f4b0dac948325ac18f6dd32564371735f32c") + + toAddress, _ := sdk.AddressFromHex("0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900") + + // This is a coin of type + // 0x3358bea865960fea2a1c6844b6fc365f662463dd1821f619838eb2e606a53b6a::cert::CERT + coinObjId, _ := sdk.ObjectIdFromHex("0x8ef4259fa2a3499826fa4b8aebeb1d8e478cf5397d05361c96438940b43d28c9") + amount := uint64(50000000000) + + gasCoinObjId, _ := sdk.ObjectIdFromHex("0x0b0270ee9d27da0db09651e5f7338dfa32c7ee6441ccefa1f6e305735bcfc7ab") + + builder := sdk.TransactionBuilderInit(fromAddress, client) + builder.SendCoins([]*sdk.ObjectId{coinObjId}, toAddress, &amount) + builder.Gas(gasCoinObjId).GasBudget(1000000000) + + txn, err := builder.Finish() + if err.(*sdk.SdkFfiError) != nil { + log.Fatalf("Failed to create transaction: %v", err) + } + + txnBytes, err := txn.BcsSerialize() + if err != nil { + log.Fatalf("Failed to serialize transaction: %v", err) + } + log.Printf("Signing Digest: %v", sdk.HexEncode(txn.SigningDigest())) + log.Printf("Txn Bytes: %v", sdk.Base64Encode(txnBytes)) + + res, err := builder.DryRun(false) + if err.(*sdk.SdkFfiError) != nil { + log.Fatalf("Failed to send coins: %v", err) + } + + if res.Error != nil { + log.Fatalf("Failed to send coins: %v", *res.Error) + } + + log.Print("Send coins dry run was successful!") +} diff --git a/bindings/kotlin/examples/PrepareSendCoins.kt b/bindings/kotlin/examples/PrepareSendCoins.kt new file mode 100644 index 000000000..c2aaa0f44 --- /dev/null +++ b/bindings/kotlin/examples/PrepareSendCoins.kt @@ -0,0 +1,54 @@ +// Copyright (c) 2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import iota_sdk.* +import kotlinx.coroutines.runBlocking + +fun main() = runBlocking { + try { + val client = GraphQlClient.newDevnet() + + val fromAddress = + Address.fromHex( + "0x611830d3641a68f94a690dcc25d1f4b0dac948325ac18f6dd32564371735f32c" + ) + + val toAddress = + Address.fromHex( + "0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900" + ) + + // This is a coin of type + // 0x3358bea865960fea2a1c6844b6fc365f662463dd1821f619838eb2e606a53b6a::cert::CERT + val coinId = + ObjectId.fromHex( + "0x8ef4259fa2a3499826fa4b8aebeb1d8e478cf5397d05361c96438940b43d28c9" + ) + + val gasCoinId = + ObjectId.fromHex( + "0x0b0270ee9d27da0db09651e5f7338dfa32c7ee6441ccefa1f6e305735bcfc7ab" + ) + + val builder = TransactionBuilder.init(fromAddress, client) + + builder.sendCoins(listOf(coinId), toAddress, 50000000000) + + builder.gas(gasCoinId).gasBudget(1000000000uL) + + val txn = builder.finish() + + println("Signing Digest: ${hexEncode(txn.signingDigest())}") + println("Txn Bytes: ${base64Encode(txn.bcsSerialize())}") + + val res = builder.dryRun() + + if (res.error != null) { + throw Exception("Failed to send coins: ${res.error}") + } + + println("Send coins dry run was successful!") + } catch (e: Exception) { + e.printStackTrace() + } +} diff --git a/bindings/python/examples/prepare_send_coins.py b/bindings/python/examples/prepare_send_coins.py new file mode 100644 index 000000000..7a1508112 --- /dev/null +++ b/bindings/python/examples/prepare_send_coins.py @@ -0,0 +1,55 @@ +# Copyright (c) 2025 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +from lib.iota_sdk_ffi import * + +import asyncio + + +async def main(): + try: + client = GraphQlClient.new_devnet() + + from_address = Address.from_hex( + "0x611830d3641a68f94a690dcc25d1f4b0dac948325ac18f6dd32564371735f32c" + ) + + to_address = Address.from_hex( + "0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900" + ) + + # This is a coin of type + # 0x3358bea865960fea2a1c6844b6fc365f662463dd1821f619838eb2e606a53b6a::cert::CERT + coin_id = ObjectId.from_hex( + "0x8ef4259fa2a3499826fa4b8aebeb1d8e478cf5397d05361c96438940b43d28c9" + ) + + gas_coin_id = ObjectId.from_hex( + "0x0b0270ee9d27da0db09651e5f7338dfa32c7ee6441ccefa1f6e305735bcfc7ab" + ) + + builder = await TransactionBuilder.init(from_address, client) + builder.send_coins( + [coin_id], + to_address, + 50000000000, + ) + builder.gas(gas_coin_id).gas_budget(1000000000) + + txn = await builder.finish() + + print("Signing Digest:", hex_encode(txn.signing_digest())) + print("Txn Bytes:", base64_encode(txn.bcs_serialize())) + + res = await builder.dry_run() + if res.error is not None: + raise Exception("Failed to send coins:", res.error) + + print("Send coins dry run was successful!") + + except Exception as e: + print(f"Error: {e}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/crates/iota-graphql-client/examples/prepare_send_coins.rs b/crates/iota-graphql-client/examples/prepare_send_coins.rs new file mode 100644 index 000000000..22c373d21 --- /dev/null +++ b/crates/iota-graphql-client/examples/prepare_send_coins.rs @@ -0,0 +1,52 @@ +// Copyright (c) 2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use base64ct::Encoding; +use eyre::Result; +use iota_graphql_client::Client; +use iota_transaction_builder::TransactionBuilder; +use iota_types::{Address, ObjectId}; + +#[tokio::main] +async fn main() -> Result<()> { + let client = Client::new_devnet(); + + let from_address = + Address::from_str("0x611830d3641a68f94a690dcc25d1f4b0dac948325ac18f6dd32564371735f32c")?; + let to_address = + Address::from_str("0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900")?; + + // This is a coin of type + // 0x3358bea865960fea2a1c6844b6fc365f662463dd1821f619838eb2e606a53b6a::cert::CERT + let coin = + ObjectId::from_str("0x8ef4259fa2a3499826fa4b8aebeb1d8e478cf5397d05361c96438940b43d28c9")?; + let gas_coin = + ObjectId::from_str("0x0b0270ee9d27da0db09651e5f7338dfa32c7ee6441ccefa1f6e305735bcfc7ab")?; + + let mut builder = TransactionBuilder::new(from_address).with_client(client.clone()); + + builder + .send_coins([coin], to_address, 50000000000) + .gas(gas_coin) + .gas_budget(1000000000); + + let txn = builder.finish().await?; + + println!("Signing Digest: {}", hex::encode(txn.signing_digest())); + println!( + "Txn Bytes: {}", + base64ct::Base64::encode_string(&bcs::to_bytes(&txn)?) + ); + + let res = client.dry_run_tx(&txn, false).await?; + + if let Some(err) = res.error { + eyre::bail!("Failed to send coins: {err}"); + } + + println!("Send coins dry run was successful!"); + + Ok(()) +} From 332a4660998f6f848f4ab6f3f5511f3e5a77ddc7 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Thu, 2 Oct 2025 14:27:07 +0200 Subject: [PATCH 2/2] cleanup --- bindings/go/examples/prepare_send_coins/main.go | 2 -- bindings/kotlin/examples/PrepareSendCoins.kt | 5 +---- bindings/python/examples/prepare_send_coins.py | 2 -- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/bindings/go/examples/prepare_send_coins/main.go b/bindings/go/examples/prepare_send_coins/main.go index 99fea90b3..45049ff1f 100644 --- a/bindings/go/examples/prepare_send_coins/main.go +++ b/bindings/go/examples/prepare_send_coins/main.go @@ -13,14 +13,12 @@ func main() { client := sdk.GraphQlClientNewDevnet() fromAddress, _ := sdk.AddressFromHex("0x611830d3641a68f94a690dcc25d1f4b0dac948325ac18f6dd32564371735f32c") - toAddress, _ := sdk.AddressFromHex("0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900") // This is a coin of type // 0x3358bea865960fea2a1c6844b6fc365f662463dd1821f619838eb2e606a53b6a::cert::CERT coinObjId, _ := sdk.ObjectIdFromHex("0x8ef4259fa2a3499826fa4b8aebeb1d8e478cf5397d05361c96438940b43d28c9") amount := uint64(50000000000) - gasCoinObjId, _ := sdk.ObjectIdFromHex("0x0b0270ee9d27da0db09651e5f7338dfa32c7ee6441ccefa1f6e305735bcfc7ab") builder := sdk.TransactionBuilderInit(fromAddress, client) diff --git a/bindings/kotlin/examples/PrepareSendCoins.kt b/bindings/kotlin/examples/PrepareSendCoins.kt index c2aaa0f44..4befa5326 100644 --- a/bindings/kotlin/examples/PrepareSendCoins.kt +++ b/bindings/kotlin/examples/PrepareSendCoins.kt @@ -12,7 +12,6 @@ fun main() = runBlocking { Address.fromHex( "0x611830d3641a68f94a690dcc25d1f4b0dac948325ac18f6dd32564371735f32c" ) - val toAddress = Address.fromHex( "0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900" @@ -24,7 +23,6 @@ fun main() = runBlocking { ObjectId.fromHex( "0x8ef4259fa2a3499826fa4b8aebeb1d8e478cf5397d05361c96438940b43d28c9" ) - val gasCoinId = ObjectId.fromHex( "0x0b0270ee9d27da0db09651e5f7338dfa32c7ee6441ccefa1f6e305735bcfc7ab" @@ -32,8 +30,7 @@ fun main() = runBlocking { val builder = TransactionBuilder.init(fromAddress, client) - builder.sendCoins(listOf(coinId), toAddress, 50000000000) - + builder.sendCoins(listOf(coinId), toAddress, 50000000000uL) builder.gas(gasCoinId).gasBudget(1000000000uL) val txn = builder.finish() diff --git a/bindings/python/examples/prepare_send_coins.py b/bindings/python/examples/prepare_send_coins.py index 7a1508112..d4f20b2e5 100644 --- a/bindings/python/examples/prepare_send_coins.py +++ b/bindings/python/examples/prepare_send_coins.py @@ -13,7 +13,6 @@ async def main(): from_address = Address.from_hex( "0x611830d3641a68f94a690dcc25d1f4b0dac948325ac18f6dd32564371735f32c" ) - to_address = Address.from_hex( "0x0000a4984bd495d4346fa208ddff4f5d5e5ad48c21dec631ddebc99809f16900" ) @@ -23,7 +22,6 @@ async def main(): coin_id = ObjectId.from_hex( "0x8ef4259fa2a3499826fa4b8aebeb1d8e478cf5397d05361c96438940b43d28c9" ) - gas_coin_id = ObjectId.from_hex( "0x0b0270ee9d27da0db09651e5f7338dfa32c7ee6441ccefa1f6e305735bcfc7ab" )