// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

// This file was generated. Do not modify!
//
// To update this code, run: `cargo run --release -p framework`.

//! Conversion library between a structured representation of a Move script call (`ScriptCall`) and the
//! standard BCS-compatible representation used in Aptos transactions (`Script`).
//!
//! This code was generated by compiling known Script interfaces ("ABIs") with the tool `transaction-builder-generator`.

#![allow(clippy::unnecessary_wraps)]
#![allow(unused_imports)]
use aptos_types::{
    account_address::AccountAddress,
    transaction::{Script, ScriptFunction, TransactionArgument, TransactionPayload, VecBytes},
};
use move_core_types::{
    ident_str,
    language_storage::{ModuleId, TypeTag},
};
use std::collections::BTreeMap as Map;

type Bytes = Vec<u8>;

/// Structured representation of a call into a known Move script function.
/// ```ignore
/// impl ScriptFunctionCall {
///     pub fn encode(self) -> TransactionPayload { .. }
///     pub fn decode(&TransactionPayload) -> Option<ScriptFunctionCall> { .. }
/// }
/// ```
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))]
#[cfg_attr(feature = "fuzzing", proptest(no_params))]
pub enum ScriptFunctionCall {
    CreateAccount {
        new_account_address: AccountAddress,
        auth_key_prefix: Bytes,
    },

    /// # Summary
    /// Creates a Validator account. This transaction can only be sent by the Diem
    /// Root account.
    ///
    /// # Technical Description
    /// Creates an account with a Validator role at `new_account_address`, with authentication key
    /// `auth_key_prefix` | `new_account_address`. It publishes a
    /// `ValidatorConfig::ValidatorConfig` resource with empty `config`, and
    /// `operator_account` fields. The `human_name` field of the
    /// `ValidatorConfig::ValidatorConfig` is set to the passed in `human_name`.
    /// This script does not add the validator to the validator set or the system,
    /// but only creates the account.
    /// Authentication keys, prefixes, and how to construct them from an ed25519 public key are described
    /// [here](https://aptos.dev/docs/core/accounts/#addresses-authentication-keys-and-cryptographic-keys).
    ///
    /// # Events
    /// Successful execution will emit:
    /// * A `ExperimentalAccount::CreateAccountEvent` with the `created` field being `new_account_address`,
    /// and the `rold_id` field being `Roles::VALIDATOR_ROLE_ID`. This is emitted on the
    /// `ExperimentalAccount::AccountOperationsCapability` `creation_events` handle.
    ///
    /// # Parameters
    /// | Name                  | Type         | Description                                                                              |
    /// | ------                | ------       | -------------                                                                            |
    /// | `dr_account`          | `signer`     | The signer of the sending account of this transaction. Must be the Diem Root signer.     |
    /// | `sliding_nonce`       | `u64`        | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction.               |
    /// | `new_account_address` | `address`    | Address of the to-be-created Validator account.                                          |
    /// | `auth_key_prefix`     | `vector<u8>` | The authentication key prefix that will be used initially for the newly created account. |
    /// | `human_name`          | `vector<u8>` | ASCII-encoded human name for the validator.                                              |
    ///
    /// # Common Abort Conditions
    /// | Error Category              | Error Reason                            | Description                                                                                |
    /// | ----------------            | --------------                          | -------------                                                                              |
    /// | `Errors::NOT_PUBLISHED`     | `SlidingNonce::ESLIDING_NONCE`          | A `SlidingNonce` resource is not published under `dr_account`.                             |
    /// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_OLD`          | The `sliding_nonce` is too old and it's impossible to determine if it's duplicated or not. |
    /// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_NEW`          | The `sliding_nonce` is too far in the future.                                              |
    /// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_ALREADY_RECORDED` | The `sliding_nonce` has been previously recorded.                                          |
    /// | `Errors::REQUIRES_ADDRESS`  | `CoreAddresses::EDIEM_ROOT`            | The sending account is not the Diem Root account.                                         |
    /// | `Errors::REQUIRES_ROLE`     | `Roles::EDIEM_ROOT`                    | The sending account is not the Diem Root account.                                         |
    /// | `Errors::ALREADY_PUBLISHED` | `Roles::EROLE_ID`                       | The `new_account_address` address is already taken.                                        |
    ///
    /// # Related Scripts
    /// * `AccountCreationScripts::create_validator_operator_account`
    /// * `ValidatorAdministrationScripts::add_validator_and_reconfigure`
    /// * `ValidatorAdministrationScripts::register_validator_config`
    /// * `ValidatorAdministrationScripts::remove_validator_and_reconfigure`
    /// * `ValidatorAdministrationScripts::set_validator_operator`
    /// * `ValidatorAdministrationScripts::set_validator_operator_with_nonce_admin`
    /// * `ValidatorAdministrationScripts::set_validator_config_and_reconfigure`
    CreateValidatorAccount {
        new_account_address: AccountAddress,
        auth_key_prefix: Bytes,
        human_name: Bytes,
    },

    /// # Summary
    /// Creates a Validator Operator account. This transaction can only be sent by the Diem
    /// Root account.
    ///
    /// # Technical Description
    /// Creates an account with a Validator Operator role at `new_account_address`, with authentication key
    /// `auth_key_prefix` | `new_account_address`. It publishes a
    /// `ValidatorOperatorConfig::ValidatorOperatorConfig` resource with the specified `human_name`.
    /// This script does not assign the validator operator to any validator accounts but only creates the account.
    /// Authentication key prefixes, and how to construct them from an ed25519 public key are described
    /// [here](https://aptos.dev/docs/core/accounts/#addresses-authentication-keys-and-cryptographic-keys).
    ///
    /// # Events
    /// Successful execution will emit:
    /// * A `ExperimentalAccount::CreateAccountEvent` with the `created` field being `new_account_address`,
    /// and the `rold_id` field being `Roles::VALIDATOR_OPERATOR_ROLE_ID`. This is emitted on the
    /// `ExperimentalAccount::AccountOperationsCapability` `creation_events` handle.
    ///
    /// # Parameters
    /// | Name                  | Type         | Description                                                                              |
    /// | ------                | ------       | -------------                                                                            |
    /// | `dr_account`          | `signer`     | The signer of the sending account of this transaction. Must be the Diem Root signer.     |
    /// | `sliding_nonce`       | `u64`        | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction.               |
    /// | `new_account_address` | `address`    | Address of the to-be-created Validator account.                                          |
    /// | `auth_key_prefix`     | `vector<u8>` | The authentication key prefix that will be used initially for the newly created account. |
    /// | `human_name`          | `vector<u8>` | ASCII-encoded human name for the validator.                                              |
    ///
    /// # Common Abort Conditions
    /// | Error Category              | Error Reason                            | Description                                                                                |
    /// | ----------------            | --------------                          | -------------                                                                              |
    /// | `Errors::NOT_PUBLISHED`     | `SlidingNonce::ESLIDING_NONCE`          | A `SlidingNonce` resource is not published under `dr_account`.                             |
    /// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_OLD`          | The `sliding_nonce` is too old and it's impossible to determine if it's duplicated or not. |
    /// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_NEW`          | The `sliding_nonce` is too far in the future.                                              |
    /// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_ALREADY_RECORDED` | The `sliding_nonce` has been previously recorded.                                          |
    /// | `Errors::REQUIRES_ADDRESS`  | `CoreAddresses::EDIEM_ROOT`            | The sending account is not the Diem Root account.                                         |
    /// | `Errors::REQUIRES_ROLE`     | `Roles::EDIEM_ROOT`                    | The sending account is not the Diem Root account.                                         |
    /// | `Errors::ALREADY_PUBLISHED` | `Roles::EROLE_ID`                       | The `new_account_address` address is already taken.                                        |
    ///
    /// # Related Scripts
    /// * `AccountCreationScripts::create_validator_account`
    /// * `ValidatorAdministrationScripts::add_validator_and_reconfigure`
    /// * `ValidatorAdministrationScripts::register_validator_config`
    /// * `ValidatorAdministrationScripts::remove_validator_and_reconfigure`
    /// * `ValidatorAdministrationScripts::set_validator_operator`
    /// * `ValidatorAdministrationScripts::set_validator_operator_with_nonce_admin`
    /// * `ValidatorAdministrationScripts::set_validator_config_and_reconfigure`
    CreateValidatorOperatorAccount {
        new_account_address: AccountAddress,
        auth_key_prefix: Bytes,
        human_name: Bytes,
    },

    /// gc_ballots deletes all the expired ballots of the type `Proposal`
    /// under the provided address `addr`. The signer can be anybody
    /// and does not need to have the same address as `addr`
    GcBallots {
        proposal: TypeTag,
        addr: AccountAddress,
    },

    /// # Summary
    /// Initializes the Diem consensus config that is stored on-chain.  This
    /// transaction can only be sent from the Diem Root account.
    ///
    /// # Technical Description
    /// Initializes the `DiemConsensusConfig` on-chain config to empty and allows future updates from DiemRoot via
    /// `update_diem_consensus_config`. This doesn't emit a `Reconfiguration::NewEpochEvent`.
    ///
    /// # Parameters
    /// | Name            | Type      | Description                                                                |
    /// | ------          | ------    | -------------                                                              |
    /// | `account`       | `signer` | Signer of the sending account. Must be the Diem Root account.               |
    /// | `_sliding_nonce` | `u64`     | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction. |
    ///
    /// # Common Abort Conditions
    /// | Error Category             | Error Reason                                  | Description                                                                                |
    /// | ----------------           | --------------                                | -------------                                                                              |
    /// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                   | `account` is not the Diem Root account.                                                    |
    InitializeDiemConsensusConfig { _sliding_nonce: u64 },

    /// BARS account mints `amount` copies of BARS tokens to the artist's account.
    MintBars {
        artist: AccountAddress,
        artist_name: Bytes,
        content_uri: Bytes,
        amount: u64,
    },

    /// Initialize this module
    NftInitialize {},

    /// Call this function to set up relevant resources in order to
    /// mint and receive tokens.
    /// Note that this also gives BARS account a capability to mint BARS NFTs on behalf of the user.
    /// (the NFTs of other types cannot be created by BARS account).
    RegisterBarsUser {},

    /// # Summary
    /// Updates the gas constants stored on chain and used by the VM for gas
    /// metering. This transaction can only be sent from the Diem Root account.
    ///
    /// # Technical Description
    /// Updates the on-chain config holding the `VMConfig` and emits a
    /// `Reconfiguration::NewEpochEvent` to trigger a reconfiguration of the system.
    ///
    /// # Parameters
    /// | Name                                | Type     | Description                                                                                            |
    /// | ------                              | ------   | -------------                                                                                          |
    /// | `account`                           | `signer` | Signer of the sending account. Must be the Diem Root account.                                          |
    /// | `_sliding_nonce`                     | `u64`    | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction.                             |
    /// | `global_memory_per_byte_cost`       | `u64`    | The new cost to read global memory per-byte to be used for gas metering.                               |
    /// | `global_memory_per_byte_write_cost` | `u64`    | The new cost to write global memory per-byte to be used for gas metering.                              |
    /// | `min_transaction_gas_units`         | `u64`    | The new flat minimum amount of gas required for any transaction.                                       |
    /// | `large_transaction_cutoff`          | `u64`    | The new size over which an additional charge will be assessed for each additional byte.                |
    /// | `intrinsic_gas_per_byte`            | `u64`    | The new number of units of gas that to be charged per-byte over the new `large_transaction_cutoff`.    |
    /// | `maximum_number_of_gas_units`       | `u64`    | The new maximum number of gas units that can be set in a transaction.                                  |
    /// | `min_price_per_gas_unit`            | `u64`    | The new minimum gas price that can be set for a transaction.                                           |
    /// | `max_price_per_gas_unit`            | `u64`    | The new maximum gas price that can be set for a transaction.                                           |
    /// | `max_transaction_size_in_bytes`     | `u64`    | The new maximum size of a transaction that can be processed.                                           |
    /// | `gas_unit_scaling_factor`           | `u64`    | The new scaling factor to use when scaling between external and internal gas units.                    |
    /// | `default_account_size`              | `u64`    | The new default account size to use when assessing final costs for reads and writes to global storage. |
    ///
    /// # Common Abort Conditions
    /// | Error Category             | Error Reason                                | Description                                                                                |
    /// | ----------------           | --------------                              | -------------                                                                              |
    /// | `Errors::INVALID_ARGUMENT` | `VMConfig::EGAS_CONSTANT_INCONSISTENCY` | The provided gas constants are inconsistent.                                               |
    /// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                 | `account` is not the Diem Root account.                                                    |
    SetGasConstants {
        _sliding_nonce: u64,
        global_memory_per_byte_cost: u64,
        global_memory_per_byte_write_cost: u64,
        min_transaction_gas_units: u64,
        large_transaction_cutoff: u64,
        intrinsic_gas_per_byte: u64,
        maximum_number_of_gas_units: u64,
        min_price_per_gas_unit: u64,
        max_price_per_gas_unit: u64,
        max_transaction_size_in_bytes: u64,
        gas_unit_scaling_factor: u64,
        default_account_size: u64,
    },

    /// Transfer `amount` of token with id `GUID::id(creator, creation_num)` from `owner`'s
    /// balance to `to`'s balance. This operation has to be done by either the owner or an
    /// approved operator of the owner.
    TransferMultiTokenBetweenGalleries {
        token_type: TypeTag,
        to: AccountAddress,
        amount: u64,
        creator: AccountAddress,
        creation_num: u64,
    },

    /// Transfer `amount` of token with id `GUID::id(creator, creation_num)` from `owner`'s
    /// balance to `to`'s balance. This operation has to be done by either the owner or an
    /// approved operator of the owner.
    TransferTokenBetweenGalleries {
        token_type: TypeTag,
        to: AccountAddress,
        amount: u64,
        creator: AccountAddress,
        creation_num: u64,
    },

    /// # Summary
    /// Updates the Diem consensus config that is stored on-chain and is used by the Consensus.  This
    /// transaction can only be sent from the Diem Root account.
    ///
    /// # Technical Description
    /// Updates the `DiemConsensusConfig` on-chain config and emits a `Reconfiguration::NewEpochEvent` to trigger
    /// a reconfiguration of the system.
    ///
    /// # Parameters
    /// | Name            | Type          | Description                                                                |
    /// | ------          | ------        | -------------                                                              |
    /// | `account`       | `signer`      | Signer of the sending account. Must be the Diem Root account.              |
    /// | `_sliding_nonce` | `u64`         | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction. |
    /// | `config`        | `vector<u8>`  | The serialized bytes of consensus config.                                  |
    ///
    /// # Common Abort Conditions
    /// | Error Category             | Error Reason                                  | Description                                                                                |
    /// | ----------------           | --------------                                | -------------                                                                              |
    /// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                   | `account` is not the Diem Root account.                                                    |
    UpdateDiemConsensusConfig { _sliding_nonce: u64, config: Bytes },

    /// # Summary
    /// Updates the Diem major version that is stored on-chain and is used by the VM.  This
    /// transaction can only be sent from the Diem Root account.
    ///
    /// # Technical Description
    /// Updates the `Version` on-chain config and emits a `Reconfiguration::NewEpochEvent` to trigger
    /// a reconfiguration of the system. The `major` version that is passed in must be strictly greater
    /// than the current major version held on-chain. The VM reads this information and can use it to
    /// preserve backwards compatibility with previous major versions of the VM.
    ///
    /// # Parameters
    /// | Name            | Type     | Description                                                                |
    /// | ------          | ------   | -------------                                                              |
    /// | `account`       | `signer` | Signer of the sending account. Must be the Diem Root account.              |
    /// | `_sliding_nonce` | `u64`    | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction. |
    /// | `major`         | `u64`    | The `major` version of the VM to be used from this transaction on.         |
    ///
    /// # Common Abort Conditions
    /// | Error Category             | Error Reason                                  | Description                                                                                |
    /// | ----------------           | --------------                                | -------------                                                                              |
    /// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                   | `account` is not the Diem Root account.                                                    |
    /// | `Errors::INVALID_ARGUMENT` | `Version::EINVALID_MAJOR_VERSION_NUMBER`  | `major` is less-than or equal to the current major version stored on-chain.                |
    UpdateDiemVersion { _sliding_nonce: u64, major: u64 },
}

impl ScriptFunctionCall {
    /// Build an Aptos `TransactionPayload` from a structured object `ScriptFunctionCall`.
    pub fn encode(self) -> TransactionPayload {
        use ScriptFunctionCall::*;
        match self {
            CreateAccount {
                new_account_address,
                auth_key_prefix,
            } => encode_create_account_script_function(new_account_address, auth_key_prefix),
            CreateValidatorAccount {
                new_account_address,
                auth_key_prefix,
                human_name,
            } => encode_create_validator_account_script_function(
                new_account_address,
                auth_key_prefix,
                human_name,
            ),
            CreateValidatorOperatorAccount {
                new_account_address,
                auth_key_prefix,
                human_name,
            } => encode_create_validator_operator_account_script_function(
                new_account_address,
                auth_key_prefix,
                human_name,
            ),
            GcBallots { proposal, addr } => encode_gc_ballots_script_function(proposal, addr),
            InitializeDiemConsensusConfig { _sliding_nonce } => {
                encode_initialize_diem_consensus_config_script_function(_sliding_nonce)
            }
            MintBars {
                artist,
                artist_name,
                content_uri,
                amount,
            } => encode_mint_bars_script_function(artist, artist_name, content_uri, amount),
            NftInitialize {} => encode_nft_initialize_script_function(),
            RegisterBarsUser {} => encode_register_bars_user_script_function(),
            SetGasConstants {
                _sliding_nonce,
                global_memory_per_byte_cost,
                global_memory_per_byte_write_cost,
                min_transaction_gas_units,
                large_transaction_cutoff,
                intrinsic_gas_per_byte,
                maximum_number_of_gas_units,
                min_price_per_gas_unit,
                max_price_per_gas_unit,
                max_transaction_size_in_bytes,
                gas_unit_scaling_factor,
                default_account_size,
            } => encode_set_gas_constants_script_function(
                _sliding_nonce,
                global_memory_per_byte_cost,
                global_memory_per_byte_write_cost,
                min_transaction_gas_units,
                large_transaction_cutoff,
                intrinsic_gas_per_byte,
                maximum_number_of_gas_units,
                min_price_per_gas_unit,
                max_price_per_gas_unit,
                max_transaction_size_in_bytes,
                gas_unit_scaling_factor,
                default_account_size,
            ),
            TransferMultiTokenBetweenGalleries {
                token_type,
                to,
                amount,
                creator,
                creation_num,
            } => encode_transfer_multi_token_between_galleries_script_function(
                token_type,
                to,
                amount,
                creator,
                creation_num,
            ),
            TransferTokenBetweenGalleries {
                token_type,
                to,
                amount,
                creator,
                creation_num,
            } => encode_transfer_token_between_galleries_script_function(
                token_type,
                to,
                amount,
                creator,
                creation_num,
            ),
            UpdateDiemConsensusConfig {
                _sliding_nonce,
                config,
            } => encode_update_diem_consensus_config_script_function(_sliding_nonce, config),
            UpdateDiemVersion {
                _sliding_nonce,
                major,
            } => encode_update_diem_version_script_function(_sliding_nonce, major),
        }
    }

    /// Try to recognize an Aptos `TransactionPayload` and convert it into a structured object `ScriptFunctionCall`.
    pub fn decode(payload: &TransactionPayload) -> Option<ScriptFunctionCall> {
        if let TransactionPayload::ScriptFunction(script) = payload {
            match SCRIPT_FUNCTION_DECODER_MAP.get(&format!(
                "{}{}",
                script.module().name(),
                script.function()
            )) {
                Some(decoder) => decoder(payload),
                None => None,
            }
        } else {
            None
        }
    }
}

pub fn encode_create_account_script_function(
    new_account_address: AccountAddress,
    auth_key_prefix: Vec<u8>,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("AccountCreationScripts").to_owned(),
        ),
        ident_str!("create_account").to_owned(),
        vec![],
        vec![
            bcs::to_bytes(&new_account_address).unwrap(),
            bcs::to_bytes(&auth_key_prefix).unwrap(),
        ],
    ))
}

/// # Summary
/// Creates a Validator account. This transaction can only be sent by the Diem
/// Root account.
///
/// # Technical Description
/// Creates an account with a Validator role at `new_account_address`, with authentication key
/// `auth_key_prefix` | `new_account_address`. It publishes a
/// `ValidatorConfig::ValidatorConfig` resource with empty `config`, and
/// `operator_account` fields. The `human_name` field of the
/// `ValidatorConfig::ValidatorConfig` is set to the passed in `human_name`.
/// This script does not add the validator to the validator set or the system,
/// but only creates the account.
/// Authentication keys, prefixes, and how to construct them from an ed25519 public key are described
/// [here](https://aptos.dev/docs/core/accounts/#addresses-authentication-keys-and-cryptographic-keys).
///
/// # Events
/// Successful execution will emit:
/// * A `ExperimentalAccount::CreateAccountEvent` with the `created` field being `new_account_address`,
/// and the `rold_id` field being `Roles::VALIDATOR_ROLE_ID`. This is emitted on the
/// `ExperimentalAccount::AccountOperationsCapability` `creation_events` handle.
///
/// # Parameters
/// | Name                  | Type         | Description                                                                              |
/// | ------                | ------       | -------------                                                                            |
/// | `dr_account`          | `signer`     | The signer of the sending account of this transaction. Must be the Diem Root signer.     |
/// | `sliding_nonce`       | `u64`        | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction.               |
/// | `new_account_address` | `address`    | Address of the to-be-created Validator account.                                          |
/// | `auth_key_prefix`     | `vector<u8>` | The authentication key prefix that will be used initially for the newly created account. |
/// | `human_name`          | `vector<u8>` | ASCII-encoded human name for the validator.                                              |
///
/// # Common Abort Conditions
/// | Error Category              | Error Reason                            | Description                                                                                |
/// | ----------------            | --------------                          | -------------                                                                              |
/// | `Errors::NOT_PUBLISHED`     | `SlidingNonce::ESLIDING_NONCE`          | A `SlidingNonce` resource is not published under `dr_account`.                             |
/// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_OLD`          | The `sliding_nonce` is too old and it's impossible to determine if it's duplicated or not. |
/// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_NEW`          | The `sliding_nonce` is too far in the future.                                              |
/// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_ALREADY_RECORDED` | The `sliding_nonce` has been previously recorded.                                          |
/// | `Errors::REQUIRES_ADDRESS`  | `CoreAddresses::EDIEM_ROOT`            | The sending account is not the Diem Root account.                                         |
/// | `Errors::REQUIRES_ROLE`     | `Roles::EDIEM_ROOT`                    | The sending account is not the Diem Root account.                                         |
/// | `Errors::ALREADY_PUBLISHED` | `Roles::EROLE_ID`                       | The `new_account_address` address is already taken.                                        |
///
/// # Related Scripts
/// * `AccountCreationScripts::create_validator_operator_account`
/// * `ValidatorAdministrationScripts::add_validator_and_reconfigure`
/// * `ValidatorAdministrationScripts::register_validator_config`
/// * `ValidatorAdministrationScripts::remove_validator_and_reconfigure`
/// * `ValidatorAdministrationScripts::set_validator_operator`
/// * `ValidatorAdministrationScripts::set_validator_operator_with_nonce_admin`
/// * `ValidatorAdministrationScripts::set_validator_config_and_reconfigure`
pub fn encode_create_validator_account_script_function(
    new_account_address: AccountAddress,
    auth_key_prefix: Vec<u8>,
    human_name: Vec<u8>,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("AccountCreationScripts").to_owned(),
        ),
        ident_str!("create_validator_account").to_owned(),
        vec![],
        vec![
            bcs::to_bytes(&new_account_address).unwrap(),
            bcs::to_bytes(&auth_key_prefix).unwrap(),
            bcs::to_bytes(&human_name).unwrap(),
        ],
    ))
}

/// # Summary
/// Creates a Validator Operator account. This transaction can only be sent by the Diem
/// Root account.
///
/// # Technical Description
/// Creates an account with a Validator Operator role at `new_account_address`, with authentication key
/// `auth_key_prefix` | `new_account_address`. It publishes a
/// `ValidatorOperatorConfig::ValidatorOperatorConfig` resource with the specified `human_name`.
/// This script does not assign the validator operator to any validator accounts but only creates the account.
/// Authentication key prefixes, and how to construct them from an ed25519 public key are described
/// [here](https://aptos.dev/docs/core/accounts/#addresses-authentication-keys-and-cryptographic-keys).
///
/// # Events
/// Successful execution will emit:
/// * A `ExperimentalAccount::CreateAccountEvent` with the `created` field being `new_account_address`,
/// and the `rold_id` field being `Roles::VALIDATOR_OPERATOR_ROLE_ID`. This is emitted on the
/// `ExperimentalAccount::AccountOperationsCapability` `creation_events` handle.
///
/// # Parameters
/// | Name                  | Type         | Description                                                                              |
/// | ------                | ------       | -------------                                                                            |
/// | `dr_account`          | `signer`     | The signer of the sending account of this transaction. Must be the Diem Root signer.     |
/// | `sliding_nonce`       | `u64`        | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction.               |
/// | `new_account_address` | `address`    | Address of the to-be-created Validator account.                                          |
/// | `auth_key_prefix`     | `vector<u8>` | The authentication key prefix that will be used initially for the newly created account. |
/// | `human_name`          | `vector<u8>` | ASCII-encoded human name for the validator.                                              |
///
/// # Common Abort Conditions
/// | Error Category              | Error Reason                            | Description                                                                                |
/// | ----------------            | --------------                          | -------------                                                                              |
/// | `Errors::NOT_PUBLISHED`     | `SlidingNonce::ESLIDING_NONCE`          | A `SlidingNonce` resource is not published under `dr_account`.                             |
/// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_OLD`          | The `sliding_nonce` is too old and it's impossible to determine if it's duplicated or not. |
/// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_TOO_NEW`          | The `sliding_nonce` is too far in the future.                                              |
/// | `Errors::INVALID_ARGUMENT`  | `SlidingNonce::ENONCE_ALREADY_RECORDED` | The `sliding_nonce` has been previously recorded.                                          |
/// | `Errors::REQUIRES_ADDRESS`  | `CoreAddresses::EDIEM_ROOT`            | The sending account is not the Diem Root account.                                         |
/// | `Errors::REQUIRES_ROLE`     | `Roles::EDIEM_ROOT`                    | The sending account is not the Diem Root account.                                         |
/// | `Errors::ALREADY_PUBLISHED` | `Roles::EROLE_ID`                       | The `new_account_address` address is already taken.                                        |
///
/// # Related Scripts
/// * `AccountCreationScripts::create_validator_account`
/// * `ValidatorAdministrationScripts::add_validator_and_reconfigure`
/// * `ValidatorAdministrationScripts::register_validator_config`
/// * `ValidatorAdministrationScripts::remove_validator_and_reconfigure`
/// * `ValidatorAdministrationScripts::set_validator_operator`
/// * `ValidatorAdministrationScripts::set_validator_operator_with_nonce_admin`
/// * `ValidatorAdministrationScripts::set_validator_config_and_reconfigure`
pub fn encode_create_validator_operator_account_script_function(
    new_account_address: AccountAddress,
    auth_key_prefix: Vec<u8>,
    human_name: Vec<u8>,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("AccountCreationScripts").to_owned(),
        ),
        ident_str!("create_validator_operator_account").to_owned(),
        vec![],
        vec![
            bcs::to_bytes(&new_account_address).unwrap(),
            bcs::to_bytes(&auth_key_prefix).unwrap(),
            bcs::to_bytes(&human_name).unwrap(),
        ],
    ))
}

/// gc_ballots deletes all the expired ballots of the type `Proposal`
/// under the provided address `addr`. The signer can be anybody
/// and does not need to have the same address as `addr`
pub fn encode_gc_ballots_script_function(
    proposal: TypeTag,
    addr: AccountAddress,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("Vote").to_owned(),
        ),
        ident_str!("gc_ballots").to_owned(),
        vec![proposal],
        vec![bcs::to_bytes(&addr).unwrap()],
    ))
}

/// # Summary
/// Initializes the Diem consensus config that is stored on-chain.  This
/// transaction can only be sent from the Diem Root account.
///
/// # Technical Description
/// Initializes the `DiemConsensusConfig` on-chain config to empty and allows future updates from DiemRoot via
/// `update_diem_consensus_config`. This doesn't emit a `Reconfiguration::NewEpochEvent`.
///
/// # Parameters
/// | Name            | Type      | Description                                                                |
/// | ------          | ------    | -------------                                                              |
/// | `account`       | `signer` | Signer of the sending account. Must be the Diem Root account.               |
/// | `_sliding_nonce` | `u64`     | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction. |
///
/// # Common Abort Conditions
/// | Error Category             | Error Reason                                  | Description                                                                                |
/// | ----------------           | --------------                                | -------------                                                                              |
/// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                   | `account` is not the Diem Root account.                                                    |
pub fn encode_initialize_diem_consensus_config_script_function(
    _sliding_nonce: u64,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("SystemAdministrationScripts").to_owned(),
        ),
        ident_str!("initialize_diem_consensus_config").to_owned(),
        vec![],
        vec![bcs::to_bytes(&_sliding_nonce).unwrap()],
    ))
}

/// BARS account mints `amount` copies of BARS tokens to the artist's account.
pub fn encode_mint_bars_script_function(
    artist: AccountAddress,
    artist_name: Vec<u8>,
    content_uri: Vec<u8>,
    amount: u64,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("BARSToken").to_owned(),
        ),
        ident_str!("mint_bars").to_owned(),
        vec![],
        vec![
            bcs::to_bytes(&artist).unwrap(),
            bcs::to_bytes(&artist_name).unwrap(),
            bcs::to_bytes(&content_uri).unwrap(),
            bcs::to_bytes(&amount).unwrap(),
        ],
    ))
}

/// Initialize this module
pub fn encode_nft_initialize_script_function() -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("NFT").to_owned(),
        ),
        ident_str!("nft_initialize").to_owned(),
        vec![],
        vec![],
    ))
}

/// Call this function to set up relevant resources in order to
/// mint and receive tokens.
/// Note that this also gives BARS account a capability to mint BARS NFTs on behalf of the user.
/// (the NFTs of other types cannot be created by BARS account).
pub fn encode_register_bars_user_script_function() -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("BARSToken").to_owned(),
        ),
        ident_str!("register_bars_user").to_owned(),
        vec![],
        vec![],
    ))
}

/// # Summary
/// Updates the gas constants stored on chain and used by the VM for gas
/// metering. This transaction can only be sent from the Diem Root account.
///
/// # Technical Description
/// Updates the on-chain config holding the `VMConfig` and emits a
/// `Reconfiguration::NewEpochEvent` to trigger a reconfiguration of the system.
///
/// # Parameters
/// | Name                                | Type     | Description                                                                                            |
/// | ------                              | ------   | -------------                                                                                          |
/// | `account`                           | `signer` | Signer of the sending account. Must be the Diem Root account.                                          |
/// | `_sliding_nonce`                     | `u64`    | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction.                             |
/// | `global_memory_per_byte_cost`       | `u64`    | The new cost to read global memory per-byte to be used for gas metering.                               |
/// | `global_memory_per_byte_write_cost` | `u64`    | The new cost to write global memory per-byte to be used for gas metering.                              |
/// | `min_transaction_gas_units`         | `u64`    | The new flat minimum amount of gas required for any transaction.                                       |
/// | `large_transaction_cutoff`          | `u64`    | The new size over which an additional charge will be assessed for each additional byte.                |
/// | `intrinsic_gas_per_byte`            | `u64`    | The new number of units of gas that to be charged per-byte over the new `large_transaction_cutoff`.    |
/// | `maximum_number_of_gas_units`       | `u64`    | The new maximum number of gas units that can be set in a transaction.                                  |
/// | `min_price_per_gas_unit`            | `u64`    | The new minimum gas price that can be set for a transaction.                                           |
/// | `max_price_per_gas_unit`            | `u64`    | The new maximum gas price that can be set for a transaction.                                           |
/// | `max_transaction_size_in_bytes`     | `u64`    | The new maximum size of a transaction that can be processed.                                           |
/// | `gas_unit_scaling_factor`           | `u64`    | The new scaling factor to use when scaling between external and internal gas units.                    |
/// | `default_account_size`              | `u64`    | The new default account size to use when assessing final costs for reads and writes to global storage. |
///
/// # Common Abort Conditions
/// | Error Category             | Error Reason                                | Description                                                                                |
/// | ----------------           | --------------                              | -------------                                                                              |
/// | `Errors::INVALID_ARGUMENT` | `VMConfig::EGAS_CONSTANT_INCONSISTENCY` | The provided gas constants are inconsistent.                                               |
/// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                 | `account` is not the Diem Root account.                                                    |
pub fn encode_set_gas_constants_script_function(
    _sliding_nonce: u64,
    global_memory_per_byte_cost: u64,
    global_memory_per_byte_write_cost: u64,
    min_transaction_gas_units: u64,
    large_transaction_cutoff: u64,
    intrinsic_gas_per_byte: u64,
    maximum_number_of_gas_units: u64,
    min_price_per_gas_unit: u64,
    max_price_per_gas_unit: u64,
    max_transaction_size_in_bytes: u64,
    gas_unit_scaling_factor: u64,
    default_account_size: u64,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("SystemAdministrationScripts").to_owned(),
        ),
        ident_str!("set_gas_constants").to_owned(),
        vec![],
        vec![
            bcs::to_bytes(&_sliding_nonce).unwrap(),
            bcs::to_bytes(&global_memory_per_byte_cost).unwrap(),
            bcs::to_bytes(&global_memory_per_byte_write_cost).unwrap(),
            bcs::to_bytes(&min_transaction_gas_units).unwrap(),
            bcs::to_bytes(&large_transaction_cutoff).unwrap(),
            bcs::to_bytes(&intrinsic_gas_per_byte).unwrap(),
            bcs::to_bytes(&maximum_number_of_gas_units).unwrap(),
            bcs::to_bytes(&min_price_per_gas_unit).unwrap(),
            bcs::to_bytes(&max_price_per_gas_unit).unwrap(),
            bcs::to_bytes(&max_transaction_size_in_bytes).unwrap(),
            bcs::to_bytes(&gas_unit_scaling_factor).unwrap(),
            bcs::to_bytes(&default_account_size).unwrap(),
        ],
    ))
}

/// Transfer `amount` of token with id `GUID::id(creator, creation_num)` from `owner`'s
/// balance to `to`'s balance. This operation has to be done by either the owner or an
/// approved operator of the owner.
pub fn encode_transfer_multi_token_between_galleries_script_function(
    token_type: TypeTag,
    to: AccountAddress,
    amount: u64,
    creator: AccountAddress,
    creation_num: u64,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("MultiTokenBalance").to_owned(),
        ),
        ident_str!("transfer_multi_token_between_galleries").to_owned(),
        vec![token_type],
        vec![
            bcs::to_bytes(&to).unwrap(),
            bcs::to_bytes(&amount).unwrap(),
            bcs::to_bytes(&creator).unwrap(),
            bcs::to_bytes(&creation_num).unwrap(),
        ],
    ))
}

/// Transfer `amount` of token with id `GUID::id(creator, creation_num)` from `owner`'s
/// balance to `to`'s balance. This operation has to be done by either the owner or an
/// approved operator of the owner.
pub fn encode_transfer_token_between_galleries_script_function(
    token_type: TypeTag,
    to: AccountAddress,
    amount: u64,
    creator: AccountAddress,
    creation_num: u64,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("NFTGallery").to_owned(),
        ),
        ident_str!("transfer_token_between_galleries").to_owned(),
        vec![token_type],
        vec![
            bcs::to_bytes(&to).unwrap(),
            bcs::to_bytes(&amount).unwrap(),
            bcs::to_bytes(&creator).unwrap(),
            bcs::to_bytes(&creation_num).unwrap(),
        ],
    ))
}

/// # Summary
/// Updates the Diem consensus config that is stored on-chain and is used by the Consensus.  This
/// transaction can only be sent from the Diem Root account.
///
/// # Technical Description
/// Updates the `DiemConsensusConfig` on-chain config and emits a `Reconfiguration::NewEpochEvent` to trigger
/// a reconfiguration of the system.
///
/// # Parameters
/// | Name            | Type          | Description                                                                |
/// | ------          | ------        | -------------                                                              |
/// | `account`       | `signer`      | Signer of the sending account. Must be the Diem Root account.              |
/// | `_sliding_nonce` | `u64`         | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction. |
/// | `config`        | `vector<u8>`  | The serialized bytes of consensus config.                                  |
///
/// # Common Abort Conditions
/// | Error Category             | Error Reason                                  | Description                                                                                |
/// | ----------------           | --------------                                | -------------                                                                              |
/// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                   | `account` is not the Diem Root account.                                                    |
pub fn encode_update_diem_consensus_config_script_function(
    _sliding_nonce: u64,
    config: Vec<u8>,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("SystemAdministrationScripts").to_owned(),
        ),
        ident_str!("update_diem_consensus_config").to_owned(),
        vec![],
        vec![
            bcs::to_bytes(&_sliding_nonce).unwrap(),
            bcs::to_bytes(&config).unwrap(),
        ],
    ))
}

/// # Summary
/// Updates the Diem major version that is stored on-chain and is used by the VM.  This
/// transaction can only be sent from the Diem Root account.
///
/// # Technical Description
/// Updates the `Version` on-chain config and emits a `Reconfiguration::NewEpochEvent` to trigger
/// a reconfiguration of the system. The `major` version that is passed in must be strictly greater
/// than the current major version held on-chain. The VM reads this information and can use it to
/// preserve backwards compatibility with previous major versions of the VM.
///
/// # Parameters
/// | Name            | Type     | Description                                                                |
/// | ------          | ------   | -------------                                                              |
/// | `account`       | `signer` | Signer of the sending account. Must be the Diem Root account.              |
/// | `_sliding_nonce` | `u64`    | The `sliding_nonce` (see: `SlidingNonce`) to be used for this transaction. |
/// | `major`         | `u64`    | The `major` version of the VM to be used from this transaction on.         |
///
/// # Common Abort Conditions
/// | Error Category             | Error Reason                                  | Description                                                                                |
/// | ----------------           | --------------                                | -------------                                                                              |
/// | `Errors::REQUIRES_ADDRESS` | `CoreAddresses::EDIEM_ROOT`                   | `account` is not the Diem Root account.                                                    |
/// | `Errors::INVALID_ARGUMENT` | `Version::EINVALID_MAJOR_VERSION_NUMBER`  | `major` is less-than or equal to the current major version stored on-chain.                |
pub fn encode_update_diem_version_script_function(
    _sliding_nonce: u64,
    major: u64,
) -> TransactionPayload {
    TransactionPayload::ScriptFunction(ScriptFunction::new(
        ModuleId::new(
            AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
            ident_str!("SystemAdministrationScripts").to_owned(),
        ),
        ident_str!("update_diem_version").to_owned(),
        vec![],
        vec![
            bcs::to_bytes(&_sliding_nonce).unwrap(),
            bcs::to_bytes(&major).unwrap(),
        ],
    ))
}

fn decode_create_account_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::CreateAccount {
            new_account_address: bcs::from_bytes(script.args().get(0)?).ok()?,
            auth_key_prefix: bcs::from_bytes(script.args().get(1)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_create_validator_account_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::CreateValidatorAccount {
            new_account_address: bcs::from_bytes(script.args().get(0)?).ok()?,
            auth_key_prefix: bcs::from_bytes(script.args().get(1)?).ok()?,
            human_name: bcs::from_bytes(script.args().get(2)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_create_validator_operator_account_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::CreateValidatorOperatorAccount {
            new_account_address: bcs::from_bytes(script.args().get(0)?).ok()?,
            auth_key_prefix: bcs::from_bytes(script.args().get(1)?).ok()?,
            human_name: bcs::from_bytes(script.args().get(2)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_gc_ballots_script_function(payload: &TransactionPayload) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::GcBallots {
            proposal: script.ty_args().get(0)?.clone(),
            addr: bcs::from_bytes(script.args().get(0)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_initialize_diem_consensus_config_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::InitializeDiemConsensusConfig {
            _sliding_nonce: bcs::from_bytes(script.args().get(0)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_mint_bars_script_function(payload: &TransactionPayload) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::MintBars {
            artist: bcs::from_bytes(script.args().get(0)?).ok()?,
            artist_name: bcs::from_bytes(script.args().get(1)?).ok()?,
            content_uri: bcs::from_bytes(script.args().get(2)?).ok()?,
            amount: bcs::from_bytes(script.args().get(3)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_nft_initialize_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(_script) = payload {
        Some(ScriptFunctionCall::NftInitialize {})
    } else {
        None
    }
}

fn decode_register_bars_user_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(_script) = payload {
        Some(ScriptFunctionCall::RegisterBarsUser {})
    } else {
        None
    }
}

fn decode_set_gas_constants_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::SetGasConstants {
            _sliding_nonce: bcs::from_bytes(script.args().get(0)?).ok()?,
            global_memory_per_byte_cost: bcs::from_bytes(script.args().get(1)?).ok()?,
            global_memory_per_byte_write_cost: bcs::from_bytes(script.args().get(2)?).ok()?,
            min_transaction_gas_units: bcs::from_bytes(script.args().get(3)?).ok()?,
            large_transaction_cutoff: bcs::from_bytes(script.args().get(4)?).ok()?,
            intrinsic_gas_per_byte: bcs::from_bytes(script.args().get(5)?).ok()?,
            maximum_number_of_gas_units: bcs::from_bytes(script.args().get(6)?).ok()?,
            min_price_per_gas_unit: bcs::from_bytes(script.args().get(7)?).ok()?,
            max_price_per_gas_unit: bcs::from_bytes(script.args().get(8)?).ok()?,
            max_transaction_size_in_bytes: bcs::from_bytes(script.args().get(9)?).ok()?,
            gas_unit_scaling_factor: bcs::from_bytes(script.args().get(10)?).ok()?,
            default_account_size: bcs::from_bytes(script.args().get(11)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_transfer_multi_token_between_galleries_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::TransferMultiTokenBetweenGalleries {
            token_type: script.ty_args().get(0)?.clone(),
            to: bcs::from_bytes(script.args().get(0)?).ok()?,
            amount: bcs::from_bytes(script.args().get(1)?).ok()?,
            creator: bcs::from_bytes(script.args().get(2)?).ok()?,
            creation_num: bcs::from_bytes(script.args().get(3)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_transfer_token_between_galleries_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::TransferTokenBetweenGalleries {
            token_type: script.ty_args().get(0)?.clone(),
            to: bcs::from_bytes(script.args().get(0)?).ok()?,
            amount: bcs::from_bytes(script.args().get(1)?).ok()?,
            creator: bcs::from_bytes(script.args().get(2)?).ok()?,
            creation_num: bcs::from_bytes(script.args().get(3)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_update_diem_consensus_config_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::UpdateDiemConsensusConfig {
            _sliding_nonce: bcs::from_bytes(script.args().get(0)?).ok()?,
            config: bcs::from_bytes(script.args().get(1)?).ok()?,
        })
    } else {
        None
    }
}

fn decode_update_diem_version_script_function(
    payload: &TransactionPayload,
) -> Option<ScriptFunctionCall> {
    if let TransactionPayload::ScriptFunction(script) = payload {
        Some(ScriptFunctionCall::UpdateDiemVersion {
            _sliding_nonce: bcs::from_bytes(script.args().get(0)?).ok()?,
            major: bcs::from_bytes(script.args().get(1)?).ok()?,
        })
    } else {
        None
    }
}

type ScriptFunctionDecoderMap = std::collections::HashMap<
    String,
    Box<
        dyn Fn(&TransactionPayload) -> Option<ScriptFunctionCall>
            + std::marker::Sync
            + std::marker::Send,
    >,
>;

static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy<ScriptFunctionDecoderMap> =
    once_cell::sync::Lazy::new(|| {
        let mut map: ScriptFunctionDecoderMap = std::collections::HashMap::new();
        map.insert(
            "AccountCreationScriptscreate_account".to_string(),
            Box::new(decode_create_account_script_function),
        );
        map.insert(
            "AccountCreationScriptscreate_validator_account".to_string(),
            Box::new(decode_create_validator_account_script_function),
        );
        map.insert(
            "AccountCreationScriptscreate_validator_operator_account".to_string(),
            Box::new(decode_create_validator_operator_account_script_function),
        );
        map.insert(
            "Votegc_ballots".to_string(),
            Box::new(decode_gc_ballots_script_function),
        );
        map.insert(
            "SystemAdministrationScriptsinitialize_diem_consensus_config".to_string(),
            Box::new(decode_initialize_diem_consensus_config_script_function),
        );
        map.insert(
            "BARSTokenmint_bars".to_string(),
            Box::new(decode_mint_bars_script_function),
        );
        map.insert(
            "NFTnft_initialize".to_string(),
            Box::new(decode_nft_initialize_script_function),
        );
        map.insert(
            "BARSTokenregister_bars_user".to_string(),
            Box::new(decode_register_bars_user_script_function),
        );
        map.insert(
            "SystemAdministrationScriptsset_gas_constants".to_string(),
            Box::new(decode_set_gas_constants_script_function),
        );
        map.insert(
            "MultiTokenBalancetransfer_multi_token_between_galleries".to_string(),
            Box::new(decode_transfer_multi_token_between_galleries_script_function),
        );
        map.insert(
            "NFTGallerytransfer_token_between_galleries".to_string(),
            Box::new(decode_transfer_token_between_galleries_script_function),
        );
        map.insert(
            "SystemAdministrationScriptsupdate_diem_consensus_config".to_string(),
            Box::new(decode_update_diem_consensus_config_script_function),
        );
        map.insert(
            "SystemAdministrationScriptsupdate_diem_version".to_string(),
            Box::new(decode_update_diem_version_script_function),
        );
        map
    });
