Skip to content

Instantly share code, notes, and snippets.

@mazz
Created December 26, 2025 01:26
Show Gist options
  • Select an option

  • Save mazz/7235130052a4ebda1f235c56f9db0abc to your computer and use it in GitHub Desktop.

Select an option

Save mazz/7235130052a4ebda1f235c56f9db0abc to your computer and use it in GitHub Desktop.
defp build_configure_transaction(
{escrow_public_key, escrow_secret_seed},
depositor_public_key,
recipient_public_key,
asset_code,
asset_issuer,
network_passphrase,
sequence
) do
# Validate issuer public key
case StrKey.decode(asset_issuer, :ed25519_public_key) do
{:ok, _decoded_issuer} ->
server = horizon_server()
unless issuer_exists?(asset_issuer, server) do
Logger.error("Asset issuer #{asset_issuer} does not exist on network")
throw({:invalid_asset, "Asset issuer account does not exist"})
end
# Look up and normalize asset
normalized_code =
case Assets.all(server, asset_issuer: asset_issuer) do
{:ok, %Stellar.Horizon.Collection{records: assets}} ->
case Enum.find(assets, fn asset -> asset.asset_code == asset_code end) do
nil ->
Logger.error("Asset #{asset_code} not found for issuer #{asset_issuer}")
throw({:invalid_asset, "Asset not found for issuer"})
horizon_asset ->
code = String.trim(horizon_asset.asset_code)
unless code =~ ~r/^[A-Za-z0-9]{1,12}$/ do
Logger.error("Invalid asset code: #{code}")
throw({:invalid_asset, "Invalid asset code format"})
end
code
end
{:error, reason} ->
Logger.error("Failed to fetch assets for issuer #{asset_issuer}: #{inspect(reason)}")
throw({:invalid_asset, "Failed to fetch assets"})
end
escrow_account = Account.new(escrow_public_key)
trust_op =
ChangeTrust.new(asset: {normalized_code, asset_issuer}, limit: "922337203685.4775807")
Logger.debug("Trustline operation: #{inspect(trust_op, pretty: true)}")
# Decode signer keys to binary format
Logger.info("[TX 2 Build] Decoding signer public keys to binary format.")
{:ok, depositor_binary_key} = StrKey.decode(depositor_public_key, :ed25519_public_key)
{:ok, recipient_binary_key} = StrKey.decode(recipient_public_key, :ed25519_public_key)
Logger.debug("[TX 2 Build] Depositor Binary Key: #{inspect(depositor_binary_key)}")
Logger.debug("[TX 2 Build] Recipient Binary Key: #{inspect(recipient_binary_key)}")
# Build Signer structs directly with binary keys
depositor_signer = Signer.new(ed25519_public_key: depositor_binary_key, weight: 1)
recipient_signer = Signer.new(ed25519_public_key: recipient_binary_key, weight: 1)
Logger.debug("Depositor Signer struct: #{inspect(depositor_signer, pretty: true)}")
Logger.debug("Recipient Signer struct: #{inspect(recipient_signer, pretty: true)}")
# First SetOptions: thresholds + master weight only
set_options_master =
SetOptions.new(
master_weight: 0,
low_threshold: 0,
medium_threshold: 2,
high_threshold: 2
)
Logger.debug("SetOptions (master/thresholds) operation: #{inspect(set_options_master, pretty: true)}")
# Second SetOptions: add depositor as signer
set_options_depositor =
SetOptions.new(
signer: depositor_signer
)
Logger.debug("SetOptions (depositor signer) operation: #{inspect(set_options_depositor, pretty: true)}")
# Third SetOptions: add recipient as signer
set_options_recipient =
SetOptions.new(
signer: recipient_signer
)
Logger.debug("SetOptions (recipient signer) operation: #{inspect(set_options_recipient, pretty: true)}")
# Build transaction with 4 ops: trustline + 3 set-options
unsigned_tx =
Stellar.TxBuild.new(
escrow_account,
fee: @base_fee * 4,
network_passphrase: network_passphrase,
sequence_number: sequence
)
|> Stellar.TxBuild.add_operation(trust_op)
|> Stellar.TxBuild.add_operation(set_options_master)
|> Stellar.TxBuild.add_operation(set_options_depositor)
|> Stellar.TxBuild.add_operation(set_options_recipient)
Logger.debug("Unsigned transaction (TX 2): #{inspect(unsigned_tx, pretty: true)}")
signature = Signature.new(ed25519: escrow_secret_seed)
signed_tx = Stellar.TxBuild.sign(unsigned_tx, signature)
Logger.debug("Signed transaction (TX 2): #{inspect(signed_tx, pretty: true)}")
{:ok, signed_tx}
{:error, reason} ->
Logger.error("Invalid asset issuer public key: #{asset_issuer}, reason: #{inspect(reason)}")
{:error, {:invalid_asset, "Invalid asset issuer public key"}}
end
catch
{:invalid_asset, reason} ->
Logger.error("[TX 2 Build] Invalid asset: #{inspect(reason)}")
{:error, {:invalid_asset, reason}}
{:invalid_signer, reason} ->
Logger.error("[TX 2 Build] Invalid signer: #{inspect(reason)}")
{:error, {:invalid_signer, reason}}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment