#! miden::standards::attachments::network_account_target
#!
#! Provides a standardized way to work with network account targets.

use miden::protocol::account_id
use miden::protocol::active_account
use miden::protocol::active_note

# CONSTANTS
# ================================================================================================

#! The attachment scheme for NetworkAccountTarget attachments.
#! This is a valid u32 that can be compared against an extracted attachment scheme.
pub const NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME = 2

#! The number of words in the network account target attachment.
pub const NETWORK_ACCOUNT_TARGET_ATTACHMENT_NUM_WORDS = 1

# ERRORS
# ================================================================================================

const ERR_NETWORK_ACCOUNT_TARGET_MISSING = "network account target attachment is not present on active note"

const ERR_NETWORK_ACCOUNT_TARGET_INCORRECT_NUMBER_OF_WORDS = "network account target attachment must consist of exactly one word"

# PROCEDURES
# ================================================================================================

#! Returns a boolean indicating whether the attachment scheme matches the expected
#! scheme for a NetworkAccountTarget attachment.
#!
#! Inputs:  [attachment_scheme]
#! Outputs: [is_network_account_target]
#!
#! Invocation: exec
pub proc is_network_account_target
    eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME
    # => [is_network_account_target]
end

#! Returns the account ID encoded in the attachment.
#!
#! The attachment is expected to have the following layout:
#! [account_id_suffix, account_id_prefix, exec_hint_tag, 0]
#!
#! WARNING: This procedure does not validate the attachment scheme. The caller
#! should validate it using `is_network_account_target` before calling this procedure.
#!
#! WARNING: This procedure does not validate that the returned account ID is well-formed.
#! The caller should validate the account ID if needed using `account_id::validate`.
#!
#! Inputs:  [NETWORK_ACCOUNT_TARGET_ATTACHMENT]
#! Outputs: [account_id_suffix, account_id_prefix]
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of an account ID.
#!
#! Invocation: exec
pub proc into_target_id
    # => [NETWORK_ACCOUNT_TARGET_ATTACHMENT]
    # => [account_id_suffix, account_id_prefix, exec_hint_tag, 0]

    movup.2 drop movup.2 drop
    # => [account_id_suffix, account_id_prefix]
end

#! Creates a new attachment of type NetworkAccountTarget with the following layout:
#! [account_id_suffix, account_id_prefix, exec_hint_tag, 0]
#!
#! Inputs:  [account_id_suffix, account_id_prefix, exec_hint_tag]
#! Outputs: [attachment_scheme, NOTE_ATTACHMENT]
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of an account ID.
#! - exec_hint_tag is the encoded execution hint for the note with its tag.
#! - attachment_scheme is the attachment scheme (1) for use with `output_note::add_word_attachment`.
#!
#! Invocation: exec
pub proc new
    # => [account_id_suffix, account_id_prefix, exec_hint_tag]
    push.0 movdn.3
    # => [NOTE_ATTACHMENT] = [account_id_suffix, account_id_prefix, exec_hint_tag, 0]
    push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME
    # => [attachment_scheme, NOTE_ATTACHMENT]
end

#! Returns a boolean indicating whether the active account matches the target account
#! encoded in the active note's attachment.
#!
#! Inputs:  []
#! Outputs: [is_equal]
#!
#! Where:
#! - is_equal is a boolean indicating whether the active account matches the target account.
#!
#! Panics if:
#! - the attachment is missing from the active note or the number of words is invalid.
#!
#! Invocation: exec
@locals(4)
pub proc active_account_matches_target_account
    # find the network account target attachment, if any
    # if there are multiple, we consider the first one the canonical one
    push.NETWORK_ACCOUNT_TARGET_ATTACHMENT_SCHEME
    exec.active_note::find_attachment
    # => [is_found, attachment_idx]

    # network account target attachment must be present
    assert.err=ERR_NETWORK_ACCOUNT_TARGET_MISSING
    # => [attachment_idx]

    # write the attachment data to local memory
    # we allocate one word of local memory matching NETWORK_ACCOUNT_TARGET_ATTACHMENT_NUM_WORDS
    locaddr.0
    # => [dest_ptr, attachment_idx]

    exec.active_note::write_attachment_to_memory
    # => [num_words]

    eq.NETWORK_ACCOUNT_TARGET_ATTACHMENT_NUM_WORDS
    assert.err=ERR_NETWORK_ACCOUNT_TARGET_INCORRECT_NUMBER_OF_WORDS
    # => []

    padw loc_loadw_le.0
    # => [NETWORK_ACCOUNT_TARGET_ATTACHMENT]
    # => [target_id_suffix, target_id_prefix, exec_hint_tag, 0]

    exec.into_target_id
    # => [target_id_suffix, target_id_prefix]

    exec.active_account::get_id
    # => [active_account_id_suffix, active_account_id_prefix, target_id_suffix, target_id_prefix]

    exec.account_id::is_equal
    # => [is_equal]
end
