From c72ca8581c548f3f9cc6aa0ea12a66b9ed57de0b Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:11:23 -0400 Subject: [PATCH] add framework_sdk_builder to compatibility --- Cargo.lock | 1 + compatibility/Cargo.toml | 1 + compatibility/src/lib.rs | 3 +- compatibility/src/sdk/README.md | 11 + compatibility/src/sdk/mod.rs | 1 + .../src/sdk/v7_libra_framework_sdk_builder.rs | 3537 +++++++++++++++++ 6 files changed, 3552 insertions(+), 2 deletions(-) create mode 100644 compatibility/src/sdk/README.md create mode 100644 compatibility/src/sdk/mod.rs create mode 100644 compatibility/src/sdk/v7_libra_framework_sdk_builder.rs diff --git a/Cargo.lock b/Cargo.lock index f75c79118..461ea091b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5842,6 +5842,7 @@ dependencies = [ "hex", "libra-types", "move-core-types", + "once_cell", "rand 0.7.3", "serde 1.0.213", "serde_bytes", diff --git a/compatibility/Cargo.toml b/compatibility/Cargo.toml index ba2c8373d..4820a038d 100644 --- a/compatibility/Cargo.toml +++ b/compatibility/Cargo.toml @@ -24,6 +24,7 @@ diem-types = { workspace = true } move-core-types = { workspace = true } hex = { workspace = true } libra-types = { workspace = true } +once_cell = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true } diff --git a/compatibility/src/lib.rs b/compatibility/src/lib.rs index 954a5cbc2..e156b76c4 100644 --- a/compatibility/src/lib.rs +++ b/compatibility/src/lib.rs @@ -1,4 +1,3 @@ -//! `legacy-types` - pub mod legacy_recovery_v6; pub mod version_five; +pub mod sdk; diff --git a/compatibility/src/sdk/README.md b/compatibility/src/sdk/README.md new file mode 100644 index 000000000..d8fc3cd1a --- /dev/null +++ b/compatibility/src/sdk/README.md @@ -0,0 +1,11 @@ +# Versions of Libra SDK + +## Why do we need these? +Transactions submitted to blockchain are done in bytecode. Decoding that bytecode into a useful object (function name, arguments, timestamp) is hard to do if you do not have the Rust serialization lib which generated the bytecode originally. + +The names of functions (and some primitives like Account Address), change between versions. + +Suppose you would like to analyze a V5 transaction. Without these files you'll have to guess the transaction type and craft an individual decoder. + +# Modifications to originals +Note that these files are code generated, and were not intended to be changed. We have however added serde De/Serialize attributes to the EntryFunctionCall, so that they can be easily be read into memory. diff --git a/compatibility/src/sdk/mod.rs b/compatibility/src/sdk/mod.rs new file mode 100644 index 000000000..077f18bed --- /dev/null +++ b/compatibility/src/sdk/mod.rs @@ -0,0 +1 @@ +pub mod v7_libra_framework_sdk_builder; diff --git a/compatibility/src/sdk/v7_libra_framework_sdk_builder.rs b/compatibility/src/sdk/v7_libra_framework_sdk_builder.rs new file mode 100644 index 000000000..7d7258282 --- /dev/null +++ b/compatibility/src/sdk/v7_libra_framework_sdk_builder.rs @@ -0,0 +1,3537 @@ +/////// OL //////// +// NOTE: these files are copied from the original version which were at +// the time deployed to production. +// They are originally automatically generated code. +// A minor modification is adding serde de/serializers to the EntryFunctionCall enum. +//////// end //////// + +// Copyright © Diem Foundation +// 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 Diem transactions (`Script`). +// +// This code was generated by compiling known Script interfaces ("ABIs") with the tool `diem-sdk-builder`. + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(clippy::too_many_arguments)] +use diem_types::{ + account_address::AccountAddress, + transaction::{EntryFunction, TransactionPayload}, +}; +use move_core_types::{ + ident_str, + language_storage::{ModuleId, TypeTag}, +}; + +type Bytes = Vec; + +/// Structured representation of a call into a known Move entry function. +/// ```ignore +/// impl EntryFunctionCall { +/// pub fn encode(self) -> TransactionPayload { .. } +/// pub fn decode(&TransactionPayload) -> Option { .. } +/// } +/// ``` + +//////// OL /////// +// NOTE: the serde de/serializers were added manually for use in +// explorer and data warehouse +//////// end //////// +#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)] +#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] +#[cfg_attr(feature = "fuzzing", proptest(no_params))] +pub enum EntryFunctionCall { + /// Offers rotation capability on behalf of `account` to the account at address `recipient_address`. + /// An account can delegate its rotation capability to only one other address at one time. If the account + /// has an existing rotation capability offer, calling this function will update the rotation capability offer with + /// the new `recipient_address`. + /// Here, `rotation_capability_sig_bytes` signature indicates that this key rotation is authorized by the account owner, + /// and prevents the classic "time-of-check time-of-use" attack. + /// For example, users usually rely on what the wallet displays to them as the transaction's outcome. Consider a contract that with 50% probability + /// (based on the current timestamp in Move), rotates somebody's key. The wallet might be unlucky and get an outcome where nothing is rotated, + /// incorrectly telling the user nothing bad will happen. But when the transaction actually gets executed, the attacker gets lucky and + /// the execution path triggers the account key rotation. + /// We prevent such attacks by asking for this extra signature authorizing the key rotation. + /// + /// @param rotation_capability_sig_bytes is the signature by the account owner's key on `RotationCapabilityOfferProofChallengeV2`. + /// @param account_scheme is the scheme of the account (ed25519 or multi_ed25519). + /// @param account_public_key_bytes is the public key of the account owner. + /// @param recipient_address is the address of the recipient of the rotation capability - note that if there's an existing rotation capability + /// offer, calling this function will replace the previous `recipient_address` upon successful verification. + AccountOfferRotationCapability { + rotation_capability_sig_bytes: Vec, + account_scheme: u8, + account_public_key_bytes: Vec, + recipient_address: AccountAddress, + }, + + /// Offers signer capability on behalf of `account` to the account at address `recipient_address`. + /// An account can delegate its signer capability to only one other address at one time. + /// `signer_capability_key_bytes` is the `SignerCapabilityOfferProofChallengeV2` signed by the account owner's key + /// `account_scheme` is the scheme of the account (ed25519 or multi_ed25519). + /// `account_public_key_bytes` is the public key of the account owner. + /// `recipient_address` is the address of the recipient of the signer capability - note that if there's an existing + /// `recipient_address` in the account owner's `SignerCapabilityOffer`, this will replace the + /// previous `recipient_address` upon successful verification (the previous recipient will no longer have access + /// to the account owner's signer capability). + AccountOfferSignerCapability { + signer_capability_sig_bytes: Vec, + account_scheme: u8, + account_public_key_bytes: Vec, + recipient_address: AccountAddress, + }, + + /// Revoke any rotation capability offer in the specified account. + AccountRevokeAnyRotationCapability {}, + + /// Revoke any signer capability offer in the specified account. + AccountRevokeAnySignerCapability {}, + + /// Revoke the rotation capability offer given to `to_be_revoked_recipient_address` from `account` + AccountRevokeRotationCapability { + to_be_revoked_address: AccountAddress, + }, + + /// Revoke the account owner's signer capability offer for `to_be_revoked_address` (i.e., the address that + /// has a signer capability offer from `account` but will be revoked in this function). + AccountRevokeSignerCapability { + to_be_revoked_address: AccountAddress, + }, + + /// Generic authentication key rotation function that allows the user to rotate their authentication key from any scheme to any scheme. + /// To authorize the rotation, we need two signatures: + /// - the first signature `cap_rotate_key` refers to the signature by the account owner's current key on a valid `RotationProofChallenge`, + /// demonstrating that the user intends to and has the capability to rotate the authentication key of this account; + /// - the second signature `cap_update_table` refers to the signature by the new key (that the account owner wants to rotate to) on a + /// valid `RotationProofChallenge`, demonstrating that the user owns the new private key, and has the authority to update the + /// `OriginatingAddress` map with the new address mapping ``. + /// To verify these two signatures, we need their corresponding public key and public key scheme: we use `from_scheme` and `from_public_key_bytes` + /// to verify `cap_rotate_key`, and `to_scheme` and `to_public_key_bytes` to verify `cap_update_table`. + /// A scheme of 0 refers to an Ed25519 key and a scheme of 1 refers to Multi-Ed25519 keys. + /// `originating address` refers to an account's original/first address. + /// + /// Here is an example attack if we don't ask for the second signature `cap_update_table`: + /// Alice has rotated her account `addr_a` to `new_addr_a`. As a result, the following entry is created, to help Alice when recovering her wallet: + /// `OriginatingAddress[new_addr_a]` -> `addr_a` + /// Alice has had bad day: her laptop blew up and she needs to reset her account on a new one. + /// (Fortunately, she still has her secret key `new_sk_a` associated with her new address `new_addr_a`, so she can do this.) + /// + /// But Bob likes to mess with Alice. + /// Bob creates an account `addr_b` and maliciously rotates it to Alice's new address `new_addr_a`. Since we are no longer checking a PoK, + /// Bob can easily do this. + /// + /// Now, the table will be updated to make Alice's new address point to Bob's address: `OriginatingAddress[new_addr_a]` -> `addr_b`. + /// When Alice recovers her account, her wallet will display the attacker's address (Bob's) `addr_b` as her address. + /// Now Alice will give `addr_b` to everyone to pay her, but the money will go to Bob. + /// + /// Because we ask for a valid `cap_update_table`, this kind of attack is not possible. Bob would not have the secret key of Alice's address + /// to rotate his address to Alice's address in the first place. + AccountRotateAuthenticationKey { + from_scheme: u8, + from_public_key_bytes: Vec, + to_scheme: u8, + to_public_key_bytes: Vec, + cap_rotate_key: Vec, + cap_update_table: Vec, + }, + + AccountRotateAuthenticationKeyWithRotationCapability { + rotation_cap_offerer_address: AccountAddress, + new_scheme: u8, + new_public_key_bytes: Vec, + cap_update_table: Vec, + }, + + /// User opts into burns being sent to community (recycle burn). + /// default is false (burn is final). + BurnSetSendCommunity { + community: bool, + }, + + /// Same as `publish_package` but as an entry function which can be called as a transaction. Because + /// of current restrictions for txn parameters, the metadata needs to be passed in serialized form. + CodePublishPackageTxn { + metadata_serialized: Vec, + code: Vec>, + }, + + /// Transfers `amount` of coins `CoinType` from `from` to `to`. + CoinTransfer { + coin_type: TypeTag, + to: AccountAddress, + amount: u64, + }, + + /// TODO: Allow to propose change only on the signature threshold + /// Add or remove a signer to/from the multisig, and check if they may be related in the ancestry tree + CommunityWalletInitChangeSignerCommunityMultisig { + multisig_address: AccountAddress, + new_signer: AccountAddress, + is_add_operation: bool, + n_of_m: u64, + vote_duration_epochs: u64, + }, + + /// convenience function to check if the account can be caged + /// after all the structs are in place + CommunityWalletInitFinalizeAndCage { + num_signers: u64, + }, + + CommunityWalletInitInitCommunity { + initial_authorities: Vec, + check_threshold: u64, + }, + + /// Propose offer to the multisig, and check if the signers are not related family + CommunityWalletInitProposeOffer { + new_signers: Vec, + num_signers: u64, + }, + + DiemGovernanceAddApprovedScriptHashScript { + proposal_id: u64, + }, + + DiemGovernanceAssertCanResolve { + proposal_id: u64, + }, + + /// Create a single-step or multi-step proposal + /// @param execution_hash Required. This is the hash of the resolution script. When the proposal is resolved, + /// only the exact script with matching hash can be successfully executed. + DiemGovernanceCreateProposalV2 { + execution_hash: Vec, + metadata_location: Vec, + metadata_hash: Vec, + is_multi_step_proposal: bool, + }, + + /// Create a single-step or multi-step proposal + /// @param execution_hash Required. This is the hash of the resolution script. When the proposal is resolved, + /// only the exact script with matching hash can be successfully executed. + DiemGovernanceOlCreateProposalV2 { + execution_hash: Vec, + metadata_location: Vec, + metadata_hash: Vec, + is_multi_step_proposal: bool, + }, + + /// Vote on proposal with `proposal_id`. + DiemGovernanceOlVote { + proposal_id: u64, + should_pass: bool, + }, + + DiemGovernanceSmokeTriggerEpoch {}, + + /// Any end user can triger epoch/boundary and reconfiguration + /// as long as the VM set the BoundaryBit to true. + /// We do this because we don't want the VM calling complex + /// logic itself. Any abort would cause a halt. + /// On the other hand, a user can call the function once the VM + /// decides the epoch can change. Any error will just cause the + /// user's transaction to abort, but the chain will continue. + /// Whatever fix is needed can be done online with on-chain governance. + DiemGovernanceTriggerEpoch {}, + + /// Vote on proposal with `proposal_id` + DiemGovernanceVote { + proposal_id: u64, + should_pass: bool, + }, + + DonorVoiceTxsProposeLiquidateTx { + multisig_address: AccountAddress, + }, + + DonorVoiceTxsProposePaymentTx { + multisig_address: AccountAddress, + payee: AccountAddress, + value: u64, + description: Vec, + }, + + DonorVoiceTxsProposeVetoTx { + multisig_address: AccountAddress, + id: u64, + }, + + DonorVoiceTxsVoteLiquidationTx { + multisig_address: AccountAddress, + }, + + /// Entry functiont to vote the veto. + DonorVoiceTxsVoteVetoTx { + multisig_address: AccountAddress, + id: u64, + }, + + EpochBoundarySmokeTriggerEpoch {}, + + /// Only a Voucher of the validator can flip the unjail bit. + /// This is a way to make sure the validator is ready to rejoin. + JailUnjailByVoucher { + addr: AccountAddress, + }, + + /// Only callable in tests and testnets where the core resources account exists. + /// Claim the delegated mint capability and destroy the delegated token. + LibraCoinClaimMintCapability {}, + + /// Only callable in tests and testnets where the core resources account exists. + /// Create delegated token for the address so the account could claim MintCapability later. + LibraCoinDelegateMintCapability { + to: AccountAddress, + }, + + /// Root account can mint to an address. Only used for genesis and tests. + /// The "root" account in smoke tests has some privileges. + LibraCoinMintToImpl { + dst_addr: AccountAddress, + amount: u64, + }, + + MultiActionClaimOffer { + multisig_address: AccountAddress, + }, + + MultiActionInitGovDeprecated {}, + + MultiActionMigrationMigrateOffer { + multisig_address: AccountAddress, + }, + + /// Similar to add_owners, but only allow adding one owner. + MultisigAccountAddOwner { + new_owner: AccountAddress, + }, + + /// Add new owners to the multisig account. This can only be invoked by the multisig account itself, through the + /// proposal flow. + /// + /// Note that this function is not public so it can only be invoked directly instead of via a module or script. This + /// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to + /// maliciously alter the owners list. + MultisigAccountAddOwners { + new_owners: Vec, + }, + + /// Approve a multisig transaction. + MultisigAccountApproveTransaction { + multisig_account: AccountAddress, + sequence_number: u64, + }, + + /// Creates a new multisig account and add the signer as a single owner. + MultisigAccountCreate { + num_signatures_required: u64, + metadata_keys: Vec>, + metadata_values: Vec>, + }, + + /// Create a multisig transaction, which will have one approval initially (from the creator). + /// + /// @param target_function The target function to call such as 0x123::module_to_call::function_to_call. + /// @param args Vector of BCS-encoded argument values to invoke the target function with. + MultisigAccountCreateTransaction { + multisig_account: AccountAddress, + payload: Vec, + }, + + /// Create a multisig transaction with a transaction hash instead of the full payload. + /// This means the payload will be stored off chain for gas saving. Later, during execution, the executor will need + /// to provide the full payload, which will be validated against the hash stored on-chain. + /// + /// @param function_hash The sha-256 hash of the function to invoke, e.g. 0x123::module_to_call::function_to_call. + /// @param args_hash The sha-256 hash of the function arguments - a concatenated vector of the bcs-encoded + /// function arguments. + MultisigAccountCreateTransactionWithHash { + multisig_account: AccountAddress, + payload_hash: Vec, + }, + + /// Creates a new multisig account on top of an existing account. + /// + /// This offers a migration path for an existing account with a multi-ed25519 auth key (native multisig account). + /// In order to ensure a malicious module cannot obtain backdoor control over an existing account, a signed message + /// with a valid signature from the account's auth key is required. + MultisigAccountCreateWithExistingAccount { + multisig_address: AccountAddress, + owners: Vec, + num_signatures_required: u64, + account_scheme: u8, + account_public_key: Vec, + create_multisig_account_signed_message: Vec, + metadata_keys: Vec>, + metadata_values: Vec>, + }, + + /// Creates a new multisig account with the specified additional owner list and signatures required. + /// + /// @param additional_owners The owner account who calls this function cannot be in the additional_owners and there + /// cannot be any duplicate owners in the list. + /// @param num_signatures_required The number of signatures required to execute a transaction. Must be at least 1 and + /// at most the total number of owners. + MultisigAccountCreateWithOwners { + additional_owners: Vec, + num_signatures_required: u64, + metadata_keys: Vec>, + metadata_values: Vec>, + }, + + /// Remove the next transaction if it has sufficient owner rejections. + MultisigAccountExecuteRejectedTransaction { + multisig_account: AccountAddress, + }, + + /// keeps the origin account as the ADDRESS + /// rotates the key to ZERO + MultisigAccountMigrateWithOwners { + additional_owners: Vec, + num_signatures_required: u64, + metadata_keys: Vec>, + metadata_values: Vec>, + }, + + /// Reject a multisig transaction. + MultisigAccountRejectTransaction { + multisig_account: AccountAddress, + sequence_number: u64, + }, + + /// Similar to remove_owners, but only allow removing one owner. + MultisigAccountRemoveOwner { + owner_to_remove: AccountAddress, + }, + + /// Remove owners from the multisig account. This can only be invoked by the multisig account itself, through the + /// proposal flow. + /// + /// This function skips any owners who are not in the multisig account's list of owners. + /// Note that this function is not public so it can only be invoked directly instead of via a module or script. This + /// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to + /// maliciously alter the owners list. + MultisigAccountRemoveOwners { + owners_to_remove: Vec, + }, + + /// Allow the multisig account to update its own metadata. Note that this overrides the entire existing metadata. + /// If any attributes are not specified in the metadata, they will be removed! + /// + /// This can only be invoked by the multisig account itself, through the proposal flow. + /// Note that this function is not public so it can only be invoked directly instead of via a module or script. This + /// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to + /// maliciously alter the number of signatures required. + MultisigAccountUpdateMetadata { + keys: Vec>, + values: Vec>, + }, + + /// Update the number of signatures required to execute transaction in the specified multisig account. + /// + /// This can only be invoked by the multisig account itself, through the proposal flow. + /// Note that this function is not public so it can only be invoked directly instead of via a module or script. This + /// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to + /// maliciously alter the number of signatures required. + MultisigAccountUpdateSignaturesRequired { + new_num_signatures_required: u64, + }, + + /// Generic function that can be used to either approve or reject a multisig transaction + MultisigAccountVoteTransanction { + multisig_account: AccountAddress, + sequence_number: u64, + approved: bool, + }, + + /// Entry function that can be used to transfer, if allow_ungated_transfer is set true. + ObjectTransferCall { + object: AccountAddress, + to: AccountAddress, + }, + + /// Helper for smoke tests to create acounts. + /// Belt and suspenders + OlAccountCreateAccount { + auth_key: AccountAddress, + }, + + /// Set whether `account` can receive direct transfers of coins that they have not explicitly registered to receive. + OlAccountSetAllowDirectCoinTransfers { + allow: bool, + }, + + /// Convenient function to transfer GAS to a recipient account that might not exist. + /// This would create the recipient account first, which also registers it to receive GAS, before transferring. + OlAccountTransfer { + to: AccountAddress, + amount: u64, + }, + + ProofOfFeeInitBidding {}, + + /// retract bid + ProofOfFeePofRetractBid {}, + + /// update the bid for the sender + ProofOfFeePofUpdateBid { + bid: u64, + epoch_expiry: u64, + }, + + /// This function initiates governance for the multisig. It is called by the sponsor address, and is only callable once. + /// init_gov fails gracefully if the governance is already initialized. + /// init_type will throw errors if the type is already initialized. + SafeInitPaymentMultisig { + authorities: Vec, + }, + + SlowWalletSmokeTestVmUnlock { + user_addr: AccountAddress, + unlocked: u64, + transferred: u64, + }, + + /// Users can change their account to slow, by calling the entry function + /// Warning: this is permanent for the account. There's no way to + /// reverse a "slow wallet". + SlowWalletUserSetSlow {}, + + /// Initialize the validator account and give ownership to the signing account. + StakeInitializeValidator { + consensus_pubkey: Vec, + proof_of_possession: Vec, + network_addresses: Vec, + fullnode_addresses: Vec, + }, + + /// Rotate the consensus key of the validator, it'll take effect in next epoch. + StakeRotateConsensusKey { + validator_address: AccountAddress, + new_consensus_pubkey: Vec, + proof_of_possession: Vec, + }, + + /// Update the network and full node addresses of the validator. This only takes effect in the next epoch. + StakeUpdateNetworkAndFullnodeAddresses { + validator_address: AccountAddress, + new_network_addresses: Vec, + new_fullnode_addresses: Vec, + }, + + /// This is the entrypoint for a validator joining the network. + /// Separates the logic of registration from validator election etc. (in stake.move). + /// This prevents dependency cycling issues, since stake.move is a large module. + ValidatorUniverseRegisterValidator { + consensus_pubkey: Vec, + proof_of_possession: Vec, + network_addresses: Vec, + fullnode_addresses: Vec, + }, + + /// Updates the major version to a larger version. + /// This can be called by on chain governance. + VersionSetVersion { + major: u64, + }, + + /// you may want to add people who are related to you + /// there are no known use cases for this at the moment. + VouchInsistVouchFor { + friend_account: AccountAddress, + }, + + VouchRevoke { + friend_account: AccountAddress, + }, + + /// will only succesfully vouch if the two are not related by ancestry + /// prevents spending a vouch that would not be counted. + /// to add a vouch and ignore this check use insist_vouch + VouchVouchFor { + friend_account: AccountAddress, + }, +} + +impl EntryFunctionCall { + /// Build an Diem `TransactionPayload` from a structured object `EntryFunctionCall`. + pub fn encode(self) -> TransactionPayload { + use EntryFunctionCall::*; + match self { + AccountOfferRotationCapability { + rotation_capability_sig_bytes, + account_scheme, + account_public_key_bytes, + recipient_address, + } => account_offer_rotation_capability( + rotation_capability_sig_bytes, + account_scheme, + account_public_key_bytes, + recipient_address, + ), + AccountOfferSignerCapability { + signer_capability_sig_bytes, + account_scheme, + account_public_key_bytes, + recipient_address, + } => account_offer_signer_capability( + signer_capability_sig_bytes, + account_scheme, + account_public_key_bytes, + recipient_address, + ), + AccountRevokeAnyRotationCapability {} => account_revoke_any_rotation_capability(), + AccountRevokeAnySignerCapability {} => account_revoke_any_signer_capability(), + AccountRevokeRotationCapability { + to_be_revoked_address, + } => account_revoke_rotation_capability(to_be_revoked_address), + AccountRevokeSignerCapability { + to_be_revoked_address, + } => account_revoke_signer_capability(to_be_revoked_address), + AccountRotateAuthenticationKey { + from_scheme, + from_public_key_bytes, + to_scheme, + to_public_key_bytes, + cap_rotate_key, + cap_update_table, + } => account_rotate_authentication_key( + from_scheme, + from_public_key_bytes, + to_scheme, + to_public_key_bytes, + cap_rotate_key, + cap_update_table, + ), + AccountRotateAuthenticationKeyWithRotationCapability { + rotation_cap_offerer_address, + new_scheme, + new_public_key_bytes, + cap_update_table, + } => account_rotate_authentication_key_with_rotation_capability( + rotation_cap_offerer_address, + new_scheme, + new_public_key_bytes, + cap_update_table, + ), + BurnSetSendCommunity { community } => burn_set_send_community(community), + CodePublishPackageTxn { + metadata_serialized, + code, + } => code_publish_package_txn(metadata_serialized, code), + CoinTransfer { + coin_type, + to, + amount, + } => coin_transfer(coin_type, to, amount), + CommunityWalletInitChangeSignerCommunityMultisig { + multisig_address, + new_signer, + is_add_operation, + n_of_m, + vote_duration_epochs, + } => community_wallet_init_change_signer_community_multisig( + multisig_address, + new_signer, + is_add_operation, + n_of_m, + vote_duration_epochs, + ), + CommunityWalletInitFinalizeAndCage { num_signers } => { + community_wallet_init_finalize_and_cage(num_signers) + } + CommunityWalletInitInitCommunity { + initial_authorities, + check_threshold, + } => community_wallet_init_init_community(initial_authorities, check_threshold), + CommunityWalletInitProposeOffer { + new_signers, + num_signers, + } => community_wallet_init_propose_offer(new_signers, num_signers), + DiemGovernanceAddApprovedScriptHashScript { proposal_id } => { + diem_governance_add_approved_script_hash_script(proposal_id) + } + DiemGovernanceAssertCanResolve { proposal_id } => { + diem_governance_assert_can_resolve(proposal_id) + } + DiemGovernanceCreateProposalV2 { + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + } => diem_governance_create_proposal_v2( + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + ), + DiemGovernanceOlCreateProposalV2 { + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + } => diem_governance_ol_create_proposal_v2( + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + ), + DiemGovernanceOlVote { + proposal_id, + should_pass, + } => diem_governance_ol_vote(proposal_id, should_pass), + DiemGovernanceSmokeTriggerEpoch {} => diem_governance_smoke_trigger_epoch(), + DiemGovernanceTriggerEpoch {} => diem_governance_trigger_epoch(), + DiemGovernanceVote { + proposal_id, + should_pass, + } => diem_governance_vote(proposal_id, should_pass), + DonorVoiceTxsProposeLiquidateTx { multisig_address } => { + donor_voice_txs_propose_liquidate_tx(multisig_address) + } + DonorVoiceTxsProposePaymentTx { + multisig_address, + payee, + value, + description, + } => donor_voice_txs_propose_payment_tx(multisig_address, payee, value, description), + DonorVoiceTxsProposeVetoTx { + multisig_address, + id, + } => donor_voice_txs_propose_veto_tx(multisig_address, id), + DonorVoiceTxsVoteLiquidationTx { multisig_address } => { + donor_voice_txs_vote_liquidation_tx(multisig_address) + } + DonorVoiceTxsVoteVetoTx { + multisig_address, + id, + } => donor_voice_txs_vote_veto_tx(multisig_address, id), + EpochBoundarySmokeTriggerEpoch {} => epoch_boundary_smoke_trigger_epoch(), + JailUnjailByVoucher { addr } => jail_unjail_by_voucher(addr), + LibraCoinClaimMintCapability {} => libra_coin_claim_mint_capability(), + LibraCoinDelegateMintCapability { to } => libra_coin_delegate_mint_capability(to), + LibraCoinMintToImpl { dst_addr, amount } => libra_coin_mint_to_impl(dst_addr, amount), + MultiActionClaimOffer { multisig_address } => { + multi_action_claim_offer(multisig_address) + } + MultiActionInitGovDeprecated {} => multi_action_init_gov_deprecated(), + MultiActionMigrationMigrateOffer { multisig_address } => { + multi_action_migration_migrate_offer(multisig_address) + } + MultisigAccountAddOwner { new_owner } => multisig_account_add_owner(new_owner), + MultisigAccountAddOwners { new_owners } => multisig_account_add_owners(new_owners), + MultisigAccountApproveTransaction { + multisig_account, + sequence_number, + } => multisig_account_approve_transaction(multisig_account, sequence_number), + MultisigAccountCreate { + num_signatures_required, + metadata_keys, + metadata_values, + } => multisig_account_create(num_signatures_required, metadata_keys, metadata_values), + MultisigAccountCreateTransaction { + multisig_account, + payload, + } => multisig_account_create_transaction(multisig_account, payload), + MultisigAccountCreateTransactionWithHash { + multisig_account, + payload_hash, + } => multisig_account_create_transaction_with_hash(multisig_account, payload_hash), + MultisigAccountCreateWithExistingAccount { + multisig_address, + owners, + num_signatures_required, + account_scheme, + account_public_key, + create_multisig_account_signed_message, + metadata_keys, + metadata_values, + } => multisig_account_create_with_existing_account( + multisig_address, + owners, + num_signatures_required, + account_scheme, + account_public_key, + create_multisig_account_signed_message, + metadata_keys, + metadata_values, + ), + MultisigAccountCreateWithOwners { + additional_owners, + num_signatures_required, + metadata_keys, + metadata_values, + } => multisig_account_create_with_owners( + additional_owners, + num_signatures_required, + metadata_keys, + metadata_values, + ), + MultisigAccountExecuteRejectedTransaction { multisig_account } => { + multisig_account_execute_rejected_transaction(multisig_account) + } + MultisigAccountMigrateWithOwners { + additional_owners, + num_signatures_required, + metadata_keys, + metadata_values, + } => multisig_account_migrate_with_owners( + additional_owners, + num_signatures_required, + metadata_keys, + metadata_values, + ), + MultisigAccountRejectTransaction { + multisig_account, + sequence_number, + } => multisig_account_reject_transaction(multisig_account, sequence_number), + MultisigAccountRemoveOwner { owner_to_remove } => { + multisig_account_remove_owner(owner_to_remove) + } + MultisigAccountRemoveOwners { owners_to_remove } => { + multisig_account_remove_owners(owners_to_remove) + } + MultisigAccountUpdateMetadata { keys, values } => { + multisig_account_update_metadata(keys, values) + } + MultisigAccountUpdateSignaturesRequired { + new_num_signatures_required, + } => multisig_account_update_signatures_required(new_num_signatures_required), + MultisigAccountVoteTransanction { + multisig_account, + sequence_number, + approved, + } => multisig_account_vote_transanction(multisig_account, sequence_number, approved), + ObjectTransferCall { object, to } => object_transfer_call(object, to), + OlAccountCreateAccount { auth_key } => ol_account_create_account(auth_key), + OlAccountSetAllowDirectCoinTransfers { allow } => { + ol_account_set_allow_direct_coin_transfers(allow) + } + OlAccountTransfer { to, amount } => ol_account_transfer(to, amount), + ProofOfFeeInitBidding {} => proof_of_fee_init_bidding(), + ProofOfFeePofRetractBid {} => proof_of_fee_pof_retract_bid(), + ProofOfFeePofUpdateBid { bid, epoch_expiry } => { + proof_of_fee_pof_update_bid(bid, epoch_expiry) + } + SafeInitPaymentMultisig { authorities } => safe_init_payment_multisig(authorities), + SlowWalletSmokeTestVmUnlock { + user_addr, + unlocked, + transferred, + } => slow_wallet_smoke_test_vm_unlock(user_addr, unlocked, transferred), + SlowWalletUserSetSlow {} => slow_wallet_user_set_slow(), + StakeInitializeValidator { + consensus_pubkey, + proof_of_possession, + network_addresses, + fullnode_addresses, + } => stake_initialize_validator( + consensus_pubkey, + proof_of_possession, + network_addresses, + fullnode_addresses, + ), + StakeRotateConsensusKey { + validator_address, + new_consensus_pubkey, + proof_of_possession, + } => stake_rotate_consensus_key( + validator_address, + new_consensus_pubkey, + proof_of_possession, + ), + StakeUpdateNetworkAndFullnodeAddresses { + validator_address, + new_network_addresses, + new_fullnode_addresses, + } => stake_update_network_and_fullnode_addresses( + validator_address, + new_network_addresses, + new_fullnode_addresses, + ), + ValidatorUniverseRegisterValidator { + consensus_pubkey, + proof_of_possession, + network_addresses, + fullnode_addresses, + } => validator_universe_register_validator( + consensus_pubkey, + proof_of_possession, + network_addresses, + fullnode_addresses, + ), + VersionSetVersion { major } => version_set_version(major), + VouchInsistVouchFor { friend_account } => vouch_insist_vouch_for(friend_account), + VouchRevoke { friend_account } => vouch_revoke(friend_account), + VouchVouchFor { friend_account } => vouch_vouch_for(friend_account), + } + } + + /// Try to recognize an Diem `TransactionPayload` and convert it into a structured object `EntryFunctionCall`. + pub fn decode(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + match SCRIPT_FUNCTION_DECODER_MAP.get(&format!( + "{}_{}", + script.module().name(), + script.function() + )) { + Some(decoder) => decoder(payload), + None => None, + } + } else { + None + } + } +} + +/// Offers rotation capability on behalf of `account` to the account at address `recipient_address`. +/// An account can delegate its rotation capability to only one other address at one time. If the account +/// has an existing rotation capability offer, calling this function will update the rotation capability offer with +/// the new `recipient_address`. +/// Here, `rotation_capability_sig_bytes` signature indicates that this key rotation is authorized by the account owner, +/// and prevents the classic "time-of-check time-of-use" attack. +/// For example, users usually rely on what the wallet displays to them as the transaction's outcome. Consider a contract that with 50% probability +/// (based on the current timestamp in Move), rotates somebody's key. The wallet might be unlucky and get an outcome where nothing is rotated, +/// incorrectly telling the user nothing bad will happen. But when the transaction actually gets executed, the attacker gets lucky and +/// the execution path triggers the account key rotation. +/// We prevent such attacks by asking for this extra signature authorizing the key rotation. +/// +/// @param rotation_capability_sig_bytes is the signature by the account owner's key on `RotationCapabilityOfferProofChallengeV2`. +/// @param account_scheme is the scheme of the account (ed25519 or multi_ed25519). +/// @param account_public_key_bytes is the public key of the account owner. +/// @param recipient_address is the address of the recipient of the rotation capability - note that if there's an existing rotation capability +/// offer, calling this function will replace the previous `recipient_address` upon successful verification. +pub fn account_offer_rotation_capability( + rotation_capability_sig_bytes: Vec, + account_scheme: u8, + account_public_key_bytes: Vec, + recipient_address: AccountAddress, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("offer_rotation_capability").to_owned(), + vec![], + vec![ + bcs::to_bytes(&rotation_capability_sig_bytes).unwrap(), + bcs::to_bytes(&account_scheme).unwrap(), + bcs::to_bytes(&account_public_key_bytes).unwrap(), + bcs::to_bytes(&recipient_address).unwrap(), + ], + )) +} + +/// Offers signer capability on behalf of `account` to the account at address `recipient_address`. +/// An account can delegate its signer capability to only one other address at one time. +/// `signer_capability_key_bytes` is the `SignerCapabilityOfferProofChallengeV2` signed by the account owner's key +/// `account_scheme` is the scheme of the account (ed25519 or multi_ed25519). +/// `account_public_key_bytes` is the public key of the account owner. +/// `recipient_address` is the address of the recipient of the signer capability - note that if there's an existing +/// `recipient_address` in the account owner's `SignerCapabilityOffer`, this will replace the +/// previous `recipient_address` upon successful verification (the previous recipient will no longer have access +/// to the account owner's signer capability). +pub fn account_offer_signer_capability( + signer_capability_sig_bytes: Vec, + account_scheme: u8, + account_public_key_bytes: Vec, + recipient_address: AccountAddress, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("offer_signer_capability").to_owned(), + vec![], + vec![ + bcs::to_bytes(&signer_capability_sig_bytes).unwrap(), + bcs::to_bytes(&account_scheme).unwrap(), + bcs::to_bytes(&account_public_key_bytes).unwrap(), + bcs::to_bytes(&recipient_address).unwrap(), + ], + )) +} + +/// Revoke any rotation capability offer in the specified account. +pub fn account_revoke_any_rotation_capability() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("revoke_any_rotation_capability").to_owned(), + vec![], + vec![], + )) +} + +/// Revoke any signer capability offer in the specified account. +pub fn account_revoke_any_signer_capability() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("revoke_any_signer_capability").to_owned(), + vec![], + vec![], + )) +} + +/// Revoke the rotation capability offer given to `to_be_revoked_recipient_address` from `account` +pub fn account_revoke_rotation_capability( + to_be_revoked_address: AccountAddress, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("revoke_rotation_capability").to_owned(), + vec![], + vec![bcs::to_bytes(&to_be_revoked_address).unwrap()], + )) +} + +/// Revoke the account owner's signer capability offer for `to_be_revoked_address` (i.e., the address that +/// has a signer capability offer from `account` but will be revoked in this function). +pub fn account_revoke_signer_capability( + to_be_revoked_address: AccountAddress, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("revoke_signer_capability").to_owned(), + vec![], + vec![bcs::to_bytes(&to_be_revoked_address).unwrap()], + )) +} + +/// Generic authentication key rotation function that allows the user to rotate their authentication key from any scheme to any scheme. +/// To authorize the rotation, we need two signatures: +/// - the first signature `cap_rotate_key` refers to the signature by the account owner's current key on a valid `RotationProofChallenge`, +/// demonstrating that the user intends to and has the capability to rotate the authentication key of this account; +/// - the second signature `cap_update_table` refers to the signature by the new key (that the account owner wants to rotate to) on a +/// valid `RotationProofChallenge`, demonstrating that the user owns the new private key, and has the authority to update the +/// `OriginatingAddress` map with the new address mapping ``. +/// To verify these two signatures, we need their corresponding public key and public key scheme: we use `from_scheme` and `from_public_key_bytes` +/// to verify `cap_rotate_key`, and `to_scheme` and `to_public_key_bytes` to verify `cap_update_table`. +/// A scheme of 0 refers to an Ed25519 key and a scheme of 1 refers to Multi-Ed25519 keys. +/// `originating address` refers to an account's original/first address. +/// +/// Here is an example attack if we don't ask for the second signature `cap_update_table`: +/// Alice has rotated her account `addr_a` to `new_addr_a`. As a result, the following entry is created, to help Alice when recovering her wallet: +/// `OriginatingAddress[new_addr_a]` -> `addr_a` +/// Alice has had bad day: her laptop blew up and she needs to reset her account on a new one. +/// (Fortunately, she still has her secret key `new_sk_a` associated with her new address `new_addr_a`, so she can do this.) +/// +/// But Bob likes to mess with Alice. +/// Bob creates an account `addr_b` and maliciously rotates it to Alice's new address `new_addr_a`. Since we are no longer checking a PoK, +/// Bob can easily do this. +/// +/// Now, the table will be updated to make Alice's new address point to Bob's address: `OriginatingAddress[new_addr_a]` -> `addr_b`. +/// When Alice recovers her account, her wallet will display the attacker's address (Bob's) `addr_b` as her address. +/// Now Alice will give `addr_b` to everyone to pay her, but the money will go to Bob. +/// +/// Because we ask for a valid `cap_update_table`, this kind of attack is not possible. Bob would not have the secret key of Alice's address +/// to rotate his address to Alice's address in the first place. +pub fn account_rotate_authentication_key( + from_scheme: u8, + from_public_key_bytes: Vec, + to_scheme: u8, + to_public_key_bytes: Vec, + cap_rotate_key: Vec, + cap_update_table: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("rotate_authentication_key").to_owned(), + vec![], + vec![ + bcs::to_bytes(&from_scheme).unwrap(), + bcs::to_bytes(&from_public_key_bytes).unwrap(), + bcs::to_bytes(&to_scheme).unwrap(), + bcs::to_bytes(&to_public_key_bytes).unwrap(), + bcs::to_bytes(&cap_rotate_key).unwrap(), + bcs::to_bytes(&cap_update_table).unwrap(), + ], + )) +} + +pub fn account_rotate_authentication_key_with_rotation_capability( + rotation_cap_offerer_address: AccountAddress, + new_scheme: u8, + new_public_key_bytes: Vec, + cap_update_table: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("account").to_owned(), + ), + ident_str!("rotate_authentication_key_with_rotation_capability").to_owned(), + vec![], + vec![ + bcs::to_bytes(&rotation_cap_offerer_address).unwrap(), + bcs::to_bytes(&new_scheme).unwrap(), + bcs::to_bytes(&new_public_key_bytes).unwrap(), + bcs::to_bytes(&cap_update_table).unwrap(), + ], + )) +} + +/// User opts into burns being sent to community (recycle burn). +/// default is false (burn is final). +pub fn burn_set_send_community(community: bool) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("burn").to_owned(), + ), + ident_str!("set_send_community").to_owned(), + vec![], + vec![bcs::to_bytes(&community).unwrap()], + )) +} + +/// Same as `publish_package` but as an entry function which can be called as a transaction. Because +/// of current restrictions for txn parameters, the metadata needs to be passed in serialized form. +pub fn code_publish_package_txn( + metadata_serialized: Vec, + code: Vec>, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("code").to_owned(), + ), + ident_str!("publish_package_txn").to_owned(), + vec![], + vec![ + bcs::to_bytes(&metadata_serialized).unwrap(), + bcs::to_bytes(&code).unwrap(), + ], + )) +} + +/// Transfers `amount` of coins `CoinType` from `from` to `to`. +pub fn coin_transfer(coin_type: TypeTag, to: AccountAddress, amount: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("coin").to_owned(), + ), + ident_str!("transfer").to_owned(), + vec![coin_type], + vec![bcs::to_bytes(&to).unwrap(), bcs::to_bytes(&amount).unwrap()], + )) +} + +/// TODO: Allow to propose change only on the signature threshold +/// Add or remove a signer to/from the multisig, and check if they may be related in the ancestry tree +pub fn community_wallet_init_change_signer_community_multisig( + multisig_address: AccountAddress, + new_signer: AccountAddress, + is_add_operation: bool, + n_of_m: u64, + vote_duration_epochs: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("community_wallet_init").to_owned(), + ), + ident_str!("change_signer_community_multisig").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_address).unwrap(), + bcs::to_bytes(&new_signer).unwrap(), + bcs::to_bytes(&is_add_operation).unwrap(), + bcs::to_bytes(&n_of_m).unwrap(), + bcs::to_bytes(&vote_duration_epochs).unwrap(), + ], + )) +} + +/// convenience function to check if the account can be caged +/// after all the structs are in place +pub fn community_wallet_init_finalize_and_cage(num_signers: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("community_wallet_init").to_owned(), + ), + ident_str!("finalize_and_cage").to_owned(), + vec![], + vec![bcs::to_bytes(&num_signers).unwrap()], + )) +} + +pub fn community_wallet_init_init_community( + initial_authorities: Vec, + check_threshold: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("community_wallet_init").to_owned(), + ), + ident_str!("init_community").to_owned(), + vec![], + vec![ + bcs::to_bytes(&initial_authorities).unwrap(), + bcs::to_bytes(&check_threshold).unwrap(), + ], + )) +} + +/// Propose offer to the multisig, and check if the signers are not related family +pub fn community_wallet_init_propose_offer( + new_signers: Vec, + num_signers: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("community_wallet_init").to_owned(), + ), + ident_str!("propose_offer").to_owned(), + vec![], + vec![ + bcs::to_bytes(&new_signers).unwrap(), + bcs::to_bytes(&num_signers).unwrap(), + ], + )) +} + +pub fn diem_governance_add_approved_script_hash_script(proposal_id: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("add_approved_script_hash_script").to_owned(), + vec![], + vec![bcs::to_bytes(&proposal_id).unwrap()], + )) +} + +pub fn diem_governance_assert_can_resolve(proposal_id: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("assert_can_resolve").to_owned(), + vec![], + vec![bcs::to_bytes(&proposal_id).unwrap()], + )) +} + +/// Create a single-step or multi-step proposal +/// @param execution_hash Required. This is the hash of the resolution script. When the proposal is resolved, +/// only the exact script with matching hash can be successfully executed. +pub fn diem_governance_create_proposal_v2( + execution_hash: Vec, + metadata_location: Vec, + metadata_hash: Vec, + is_multi_step_proposal: bool, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("create_proposal_v2").to_owned(), + vec![], + vec![ + bcs::to_bytes(&execution_hash).unwrap(), + bcs::to_bytes(&metadata_location).unwrap(), + bcs::to_bytes(&metadata_hash).unwrap(), + bcs::to_bytes(&is_multi_step_proposal).unwrap(), + ], + )) +} + +/// Create a single-step or multi-step proposal +/// @param execution_hash Required. This is the hash of the resolution script. When the proposal is resolved, +/// only the exact script with matching hash can be successfully executed. +pub fn diem_governance_ol_create_proposal_v2( + execution_hash: Vec, + metadata_location: Vec, + metadata_hash: Vec, + is_multi_step_proposal: bool, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("ol_create_proposal_v2").to_owned(), + vec![], + vec![ + bcs::to_bytes(&execution_hash).unwrap(), + bcs::to_bytes(&metadata_location).unwrap(), + bcs::to_bytes(&metadata_hash).unwrap(), + bcs::to_bytes(&is_multi_step_proposal).unwrap(), + ], + )) +} + +/// Vote on proposal with `proposal_id`. +pub fn diem_governance_ol_vote(proposal_id: u64, should_pass: bool) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("ol_vote").to_owned(), + vec![], + vec![ + bcs::to_bytes(&proposal_id).unwrap(), + bcs::to_bytes(&should_pass).unwrap(), + ], + )) +} + +pub fn diem_governance_smoke_trigger_epoch() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("smoke_trigger_epoch").to_owned(), + vec![], + vec![], + )) +} + +/// Any end user can triger epoch/boundary and reconfiguration +/// as long as the VM set the BoundaryBit to true. +/// We do this because we don't want the VM calling complex +/// logic itself. Any abort would cause a halt. +/// On the other hand, a user can call the function once the VM +/// decides the epoch can change. Any error will just cause the +/// user's transaction to abort, but the chain will continue. +/// Whatever fix is needed can be done online with on-chain governance. +pub fn diem_governance_trigger_epoch() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("trigger_epoch").to_owned(), + vec![], + vec![], + )) +} + +/// Vote on proposal with `proposal_id` +pub fn diem_governance_vote(proposal_id: u64, should_pass: bool) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("diem_governance").to_owned(), + ), + ident_str!("vote").to_owned(), + vec![], + vec![ + bcs::to_bytes(&proposal_id).unwrap(), + bcs::to_bytes(&should_pass).unwrap(), + ], + )) +} + +pub fn donor_voice_txs_propose_liquidate_tx( + multisig_address: AccountAddress, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("donor_voice_txs").to_owned(), + ), + ident_str!("propose_liquidate_tx").to_owned(), + vec![], + vec![bcs::to_bytes(&multisig_address).unwrap()], + )) +} + +pub fn donor_voice_txs_propose_payment_tx( + multisig_address: AccountAddress, + payee: AccountAddress, + value: u64, + description: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("donor_voice_txs").to_owned(), + ), + ident_str!("propose_payment_tx").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_address).unwrap(), + bcs::to_bytes(&payee).unwrap(), + bcs::to_bytes(&value).unwrap(), + bcs::to_bytes(&description).unwrap(), + ], + )) +} + +pub fn donor_voice_txs_propose_veto_tx( + multisig_address: AccountAddress, + id: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("donor_voice_txs").to_owned(), + ), + ident_str!("propose_veto_tx").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_address).unwrap(), + bcs::to_bytes(&id).unwrap(), + ], + )) +} + +pub fn donor_voice_txs_vote_liquidation_tx(multisig_address: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("donor_voice_txs").to_owned(), + ), + ident_str!("vote_liquidation_tx").to_owned(), + vec![], + vec![bcs::to_bytes(&multisig_address).unwrap()], + )) +} + +/// Entry functiont to vote the veto. +pub fn donor_voice_txs_vote_veto_tx( + multisig_address: AccountAddress, + id: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("donor_voice_txs").to_owned(), + ), + ident_str!("vote_veto_tx").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_address).unwrap(), + bcs::to_bytes(&id).unwrap(), + ], + )) +} + +pub fn epoch_boundary_smoke_trigger_epoch() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("epoch_boundary").to_owned(), + ), + ident_str!("smoke_trigger_epoch").to_owned(), + vec![], + vec![], + )) +} + +/// Only a Voucher of the validator can flip the unjail bit. +/// This is a way to make sure the validator is ready to rejoin. +pub fn jail_unjail_by_voucher(addr: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("jail").to_owned(), + ), + ident_str!("unjail_by_voucher").to_owned(), + vec![], + vec![bcs::to_bytes(&addr).unwrap()], + )) +} + +/// Only callable in tests and testnets where the core resources account exists. +/// Claim the delegated mint capability and destroy the delegated token. +pub fn libra_coin_claim_mint_capability() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("libra_coin").to_owned(), + ), + ident_str!("claim_mint_capability").to_owned(), + vec![], + vec![], + )) +} + +/// Only callable in tests and testnets where the core resources account exists. +/// Create delegated token for the address so the account could claim MintCapability later. +pub fn libra_coin_delegate_mint_capability(to: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("libra_coin").to_owned(), + ), + ident_str!("delegate_mint_capability").to_owned(), + vec![], + vec![bcs::to_bytes(&to).unwrap()], + )) +} + +/// Root account can mint to an address. Only used for genesis and tests. +/// The "root" account in smoke tests has some privileges. +pub fn libra_coin_mint_to_impl(dst_addr: AccountAddress, amount: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("libra_coin").to_owned(), + ), + ident_str!("mint_to_impl").to_owned(), + vec![], + vec![ + bcs::to_bytes(&dst_addr).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +pub fn multi_action_claim_offer(multisig_address: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multi_action").to_owned(), + ), + ident_str!("claim_offer").to_owned(), + vec![], + vec![bcs::to_bytes(&multisig_address).unwrap()], + )) +} + +pub fn multi_action_init_gov_deprecated() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multi_action").to_owned(), + ), + ident_str!("init_gov_deprecated").to_owned(), + vec![], + vec![], + )) +} + +pub fn multi_action_migration_migrate_offer( + multisig_address: AccountAddress, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multi_action_migration").to_owned(), + ), + ident_str!("migrate_offer").to_owned(), + vec![], + vec![bcs::to_bytes(&multisig_address).unwrap()], + )) +} + +/// Similar to add_owners, but only allow adding one owner. +pub fn multisig_account_add_owner(new_owner: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("add_owner").to_owned(), + vec![], + vec![bcs::to_bytes(&new_owner).unwrap()], + )) +} + +/// Add new owners to the multisig account. This can only be invoked by the multisig account itself, through the +/// proposal flow. +/// +/// Note that this function is not public so it can only be invoked directly instead of via a module or script. This +/// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to +/// maliciously alter the owners list. +pub fn multisig_account_add_owners(new_owners: Vec) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("add_owners").to_owned(), + vec![], + vec![bcs::to_bytes(&new_owners).unwrap()], + )) +} + +/// Approve a multisig transaction. +pub fn multisig_account_approve_transaction( + multisig_account: AccountAddress, + sequence_number: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("approve_transaction").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&sequence_number).unwrap(), + ], + )) +} + +/// Creates a new multisig account and add the signer as a single owner. +pub fn multisig_account_create( + num_signatures_required: u64, + metadata_keys: Vec>, + metadata_values: Vec>, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("create").to_owned(), + vec![], + vec![ + bcs::to_bytes(&num_signatures_required).unwrap(), + bcs::to_bytes(&metadata_keys).unwrap(), + bcs::to_bytes(&metadata_values).unwrap(), + ], + )) +} + +/// Create a multisig transaction, which will have one approval initially (from the creator). +/// +/// @param target_function The target function to call such as 0x123::module_to_call::function_to_call. +/// @param args Vector of BCS-encoded argument values to invoke the target function with. +pub fn multisig_account_create_transaction( + multisig_account: AccountAddress, + payload: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("create_transaction").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&payload).unwrap(), + ], + )) +} + +/// Create a multisig transaction with a transaction hash instead of the full payload. +/// This means the payload will be stored off chain for gas saving. Later, during execution, the executor will need +/// to provide the full payload, which will be validated against the hash stored on-chain. +/// +/// @param function_hash The sha-256 hash of the function to invoke, e.g. 0x123::module_to_call::function_to_call. +/// @param args_hash The sha-256 hash of the function arguments - a concatenated vector of the bcs-encoded +/// function arguments. +pub fn multisig_account_create_transaction_with_hash( + multisig_account: AccountAddress, + payload_hash: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("create_transaction_with_hash").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&payload_hash).unwrap(), + ], + )) +} + +/// Creates a new multisig account on top of an existing account. +/// +/// This offers a migration path for an existing account with a multi-ed25519 auth key (native multisig account). +/// In order to ensure a malicious module cannot obtain backdoor control over an existing account, a signed message +/// with a valid signature from the account's auth key is required. +pub fn multisig_account_create_with_existing_account( + multisig_address: AccountAddress, + owners: Vec, + num_signatures_required: u64, + account_scheme: u8, + account_public_key: Vec, + create_multisig_account_signed_message: Vec, + metadata_keys: Vec>, + metadata_values: Vec>, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("create_with_existing_account").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_address).unwrap(), + bcs::to_bytes(&owners).unwrap(), + bcs::to_bytes(&num_signatures_required).unwrap(), + bcs::to_bytes(&account_scheme).unwrap(), + bcs::to_bytes(&account_public_key).unwrap(), + bcs::to_bytes(&create_multisig_account_signed_message).unwrap(), + bcs::to_bytes(&metadata_keys).unwrap(), + bcs::to_bytes(&metadata_values).unwrap(), + ], + )) +} + +/// Creates a new multisig account with the specified additional owner list and signatures required. +/// +/// @param additional_owners The owner account who calls this function cannot be in the additional_owners and there +/// cannot be any duplicate owners in the list. +/// @param num_signatures_required The number of signatures required to execute a transaction. Must be at least 1 and +/// at most the total number of owners. +pub fn multisig_account_create_with_owners( + additional_owners: Vec, + num_signatures_required: u64, + metadata_keys: Vec>, + metadata_values: Vec>, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("create_with_owners").to_owned(), + vec![], + vec![ + bcs::to_bytes(&additional_owners).unwrap(), + bcs::to_bytes(&num_signatures_required).unwrap(), + bcs::to_bytes(&metadata_keys).unwrap(), + bcs::to_bytes(&metadata_values).unwrap(), + ], + )) +} + +/// Remove the next transaction if it has sufficient owner rejections. +pub fn multisig_account_execute_rejected_transaction( + multisig_account: AccountAddress, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("execute_rejected_transaction").to_owned(), + vec![], + vec![bcs::to_bytes(&multisig_account).unwrap()], + )) +} + +/// keeps the origin account as the ADDRESS +/// rotates the key to ZERO +pub fn multisig_account_migrate_with_owners( + additional_owners: Vec, + num_signatures_required: u64, + metadata_keys: Vec>, + metadata_values: Vec>, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("migrate_with_owners").to_owned(), + vec![], + vec![ + bcs::to_bytes(&additional_owners).unwrap(), + bcs::to_bytes(&num_signatures_required).unwrap(), + bcs::to_bytes(&metadata_keys).unwrap(), + bcs::to_bytes(&metadata_values).unwrap(), + ], + )) +} + +/// Reject a multisig transaction. +pub fn multisig_account_reject_transaction( + multisig_account: AccountAddress, + sequence_number: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("reject_transaction").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&sequence_number).unwrap(), + ], + )) +} + +/// Similar to remove_owners, but only allow removing one owner. +pub fn multisig_account_remove_owner(owner_to_remove: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("remove_owner").to_owned(), + vec![], + vec![bcs::to_bytes(&owner_to_remove).unwrap()], + )) +} + +/// Remove owners from the multisig account. This can only be invoked by the multisig account itself, through the +/// proposal flow. +/// +/// This function skips any owners who are not in the multisig account's list of owners. +/// Note that this function is not public so it can only be invoked directly instead of via a module or script. This +/// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to +/// maliciously alter the owners list. +pub fn multisig_account_remove_owners(owners_to_remove: Vec) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("remove_owners").to_owned(), + vec![], + vec![bcs::to_bytes(&owners_to_remove).unwrap()], + )) +} + +/// Allow the multisig account to update its own metadata. Note that this overrides the entire existing metadata. +/// If any attributes are not specified in the metadata, they will be removed! +/// +/// This can only be invoked by the multisig account itself, through the proposal flow. +/// Note that this function is not public so it can only be invoked directly instead of via a module or script. This +/// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to +/// maliciously alter the number of signatures required. +pub fn multisig_account_update_metadata( + keys: Vec>, + values: Vec>, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("update_metadata").to_owned(), + vec![], + vec![ + bcs::to_bytes(&keys).unwrap(), + bcs::to_bytes(&values).unwrap(), + ], + )) +} + +/// Update the number of signatures required to execute transaction in the specified multisig account. +/// +/// This can only be invoked by the multisig account itself, through the proposal flow. +/// Note that this function is not public so it can only be invoked directly instead of via a module or script. This +/// ensures that a multisig transaction cannot lead to another module obtaining the multisig signer and using it to +/// maliciously alter the number of signatures required. +pub fn multisig_account_update_signatures_required( + new_num_signatures_required: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("update_signatures_required").to_owned(), + vec![], + vec![bcs::to_bytes(&new_num_signatures_required).unwrap()], + )) +} + +/// Generic function that can be used to either approve or reject a multisig transaction +pub fn multisig_account_vote_transanction( + multisig_account: AccountAddress, + sequence_number: u64, + approved: bool, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("multisig_account").to_owned(), + ), + ident_str!("vote_transanction").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&sequence_number).unwrap(), + bcs::to_bytes(&approved).unwrap(), + ], + )) +} + +/// Entry function that can be used to transfer, if allow_ungated_transfer is set true. +pub fn object_transfer_call(object: AccountAddress, to: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("object").to_owned(), + ), + ident_str!("transfer_call").to_owned(), + vec![], + vec![bcs::to_bytes(&object).unwrap(), bcs::to_bytes(&to).unwrap()], + )) +} + +/// Helper for smoke tests to create acounts. +/// Belt and suspenders +pub fn ol_account_create_account(auth_key: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("ol_account").to_owned(), + ), + ident_str!("create_account").to_owned(), + vec![], + vec![bcs::to_bytes(&auth_key).unwrap()], + )) +} + +/// Set whether `account` can receive direct transfers of coins that they have not explicitly registered to receive. +pub fn ol_account_set_allow_direct_coin_transfers(allow: bool) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("ol_account").to_owned(), + ), + ident_str!("set_allow_direct_coin_transfers").to_owned(), + vec![], + vec![bcs::to_bytes(&allow).unwrap()], + )) +} + +/// Convenient function to transfer GAS to a recipient account that might not exist. +/// This would create the recipient account first, which also registers it to receive GAS, before transferring. +pub fn ol_account_transfer(to: AccountAddress, amount: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("ol_account").to_owned(), + ), + ident_str!("transfer").to_owned(), + vec![], + vec![bcs::to_bytes(&to).unwrap(), bcs::to_bytes(&amount).unwrap()], + )) +} + +pub fn proof_of_fee_init_bidding() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("proof_of_fee").to_owned(), + ), + ident_str!("init_bidding").to_owned(), + vec![], + vec![], + )) +} + +/// retract bid +pub fn proof_of_fee_pof_retract_bid() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("proof_of_fee").to_owned(), + ), + ident_str!("pof_retract_bid").to_owned(), + vec![], + vec![], + )) +} + +/// update the bid for the sender +pub fn proof_of_fee_pof_update_bid(bid: u64, epoch_expiry: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("proof_of_fee").to_owned(), + ), + ident_str!("pof_update_bid").to_owned(), + vec![], + vec![ + bcs::to_bytes(&bid).unwrap(), + bcs::to_bytes(&epoch_expiry).unwrap(), + ], + )) +} + +/// This function initiates governance for the multisig. It is called by the sponsor address, and is only callable once. +/// init_gov fails gracefully if the governance is already initialized. +/// init_type will throw errors if the type is already initialized. +pub fn safe_init_payment_multisig(authorities: Vec) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("safe").to_owned(), + ), + ident_str!("init_payment_multisig").to_owned(), + vec![], + vec![bcs::to_bytes(&authorities).unwrap()], + )) +} + +pub fn slow_wallet_smoke_test_vm_unlock( + user_addr: AccountAddress, + unlocked: u64, + transferred: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("slow_wallet").to_owned(), + ), + ident_str!("smoke_test_vm_unlock").to_owned(), + vec![], + vec![ + bcs::to_bytes(&user_addr).unwrap(), + bcs::to_bytes(&unlocked).unwrap(), + bcs::to_bytes(&transferred).unwrap(), + ], + )) +} + +/// Users can change their account to slow, by calling the entry function +/// Warning: this is permanent for the account. There's no way to +/// reverse a "slow wallet". +pub fn slow_wallet_user_set_slow() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("slow_wallet").to_owned(), + ), + ident_str!("user_set_slow").to_owned(), + vec![], + vec![], + )) +} + +/// Initialize the validator account and give ownership to the signing account. +pub fn stake_initialize_validator( + consensus_pubkey: Vec, + proof_of_possession: Vec, + network_addresses: Vec, + fullnode_addresses: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("stake").to_owned(), + ), + ident_str!("initialize_validator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&consensus_pubkey).unwrap(), + bcs::to_bytes(&proof_of_possession).unwrap(), + bcs::to_bytes(&network_addresses).unwrap(), + bcs::to_bytes(&fullnode_addresses).unwrap(), + ], + )) +} + +/// Rotate the consensus key of the validator, it'll take effect in next epoch. +pub fn stake_rotate_consensus_key( + validator_address: AccountAddress, + new_consensus_pubkey: Vec, + proof_of_possession: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("stake").to_owned(), + ), + ident_str!("rotate_consensus_key").to_owned(), + vec![], + vec![ + bcs::to_bytes(&validator_address).unwrap(), + bcs::to_bytes(&new_consensus_pubkey).unwrap(), + bcs::to_bytes(&proof_of_possession).unwrap(), + ], + )) +} + +/// Update the network and full node addresses of the validator. This only takes effect in the next epoch. +pub fn stake_update_network_and_fullnode_addresses( + validator_address: AccountAddress, + new_network_addresses: Vec, + new_fullnode_addresses: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("stake").to_owned(), + ), + ident_str!("update_network_and_fullnode_addresses").to_owned(), + vec![], + vec![ + bcs::to_bytes(&validator_address).unwrap(), + bcs::to_bytes(&new_network_addresses).unwrap(), + bcs::to_bytes(&new_fullnode_addresses).unwrap(), + ], + )) +} + +/// This is the entrypoint for a validator joining the network. +/// Separates the logic of registration from validator election etc. (in stake.move). +/// This prevents dependency cycling issues, since stake.move is a large module. +pub fn validator_universe_register_validator( + consensus_pubkey: Vec, + proof_of_possession: Vec, + network_addresses: Vec, + fullnode_addresses: Vec, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("validator_universe").to_owned(), + ), + ident_str!("register_validator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&consensus_pubkey).unwrap(), + bcs::to_bytes(&proof_of_possession).unwrap(), + bcs::to_bytes(&network_addresses).unwrap(), + bcs::to_bytes(&fullnode_addresses).unwrap(), + ], + )) +} + +/// Updates the major version to a larger version. +/// This can be called by on chain governance. +pub fn version_set_version(major: u64) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("version").to_owned(), + ), + ident_str!("set_version").to_owned(), + vec![], + vec![bcs::to_bytes(&major).unwrap()], + )) +} + +/// you may want to add people who are related to you +/// there are no known use cases for this at the moment. +pub fn vouch_insist_vouch_for(friend_account: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("vouch").to_owned(), + ), + ident_str!("insist_vouch_for").to_owned(), + vec![], + vec![bcs::to_bytes(&friend_account).unwrap()], + )) +} + +pub fn vouch_revoke(friend_account: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("vouch").to_owned(), + ), + ident_str!("revoke").to_owned(), + vec![], + vec![bcs::to_bytes(&friend_account).unwrap()], + )) +} + +/// will only succesfully vouch if the two are not related by ancestry +/// prevents spending a vouch that would not be counted. +/// to add a vouch and ignore this check use insist_vouch +pub fn vouch_vouch_for(friend_account: AccountAddress) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("vouch").to_owned(), + ), + ident_str!("vouch_for").to_owned(), + vec![], + vec![bcs::to_bytes(&friend_account).unwrap()], + )) +} +mod decoder { + use super::*; + pub fn account_offer_rotation_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AccountOfferRotationCapability { + rotation_capability_sig_bytes: bcs::from_bytes(script.args().first()?).ok()?, + account_scheme: bcs::from_bytes(script.args().get(1)?).ok()?, + account_public_key_bytes: bcs::from_bytes(script.args().get(2)?).ok()?, + recipient_address: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn account_offer_signer_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AccountOfferSignerCapability { + signer_capability_sig_bytes: bcs::from_bytes(script.args().first()?).ok()?, + account_scheme: bcs::from_bytes(script.args().get(1)?).ok()?, + account_public_key_bytes: bcs::from_bytes(script.args().get(2)?).ok()?, + recipient_address: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn account_revoke_any_rotation_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::AccountRevokeAnyRotationCapability {}) + } else { + None + } + } + + pub fn account_revoke_any_signer_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::AccountRevokeAnySignerCapability {}) + } else { + None + } + } + + pub fn account_revoke_rotation_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AccountRevokeRotationCapability { + to_be_revoked_address: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn account_revoke_signer_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AccountRevokeSignerCapability { + to_be_revoked_address: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn account_rotate_authentication_key( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AccountRotateAuthenticationKey { + from_scheme: bcs::from_bytes(script.args().first()?).ok()?, + from_public_key_bytes: bcs::from_bytes(script.args().get(1)?).ok()?, + to_scheme: bcs::from_bytes(script.args().get(2)?).ok()?, + to_public_key_bytes: bcs::from_bytes(script.args().get(3)?).ok()?, + cap_rotate_key: bcs::from_bytes(script.args().get(4)?).ok()?, + cap_update_table: bcs::from_bytes(script.args().get(5)?).ok()?, + }) + } else { + None + } + } + + pub fn account_rotate_authentication_key_with_rotation_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::AccountRotateAuthenticationKeyWithRotationCapability { + rotation_cap_offerer_address: bcs::from_bytes(script.args().first()?).ok()?, + new_scheme: bcs::from_bytes(script.args().get(1)?).ok()?, + new_public_key_bytes: bcs::from_bytes(script.args().get(2)?).ok()?, + cap_update_table: bcs::from_bytes(script.args().get(3)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn burn_set_send_community(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::BurnSetSendCommunity { + community: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn code_publish_package_txn(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CodePublishPackageTxn { + metadata_serialized: bcs::from_bytes(script.args().first()?).ok()?, + code: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn coin_transfer(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CoinTransfer { + coin_type: script.ty_args().first()?.clone(), + to: bcs::from_bytes(script.args().first()?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn community_wallet_init_change_signer_community_multisig( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::CommunityWalletInitChangeSignerCommunityMultisig { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + new_signer: bcs::from_bytes(script.args().get(1)?).ok()?, + is_add_operation: bcs::from_bytes(script.args().get(2)?).ok()?, + n_of_m: bcs::from_bytes(script.args().get(3)?).ok()?, + vote_duration_epochs: bcs::from_bytes(script.args().get(4)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn community_wallet_init_finalize_and_cage( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CommunityWalletInitFinalizeAndCage { + num_signers: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn community_wallet_init_init_community( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CommunityWalletInitInitCommunity { + initial_authorities: bcs::from_bytes(script.args().first()?).ok()?, + check_threshold: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn community_wallet_init_propose_offer( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CommunityWalletInitProposeOffer { + new_signers: bcs::from_bytes(script.args().first()?).ok()?, + num_signers: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn diem_governance_add_approved_script_hash_script( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::DiemGovernanceAddApprovedScriptHashScript { + proposal_id: bcs::from_bytes(script.args().first()?).ok()?, + }, + ) + } else { + None + } + } + + pub fn diem_governance_assert_can_resolve( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DiemGovernanceAssertCanResolve { + proposal_id: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn diem_governance_create_proposal_v2( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DiemGovernanceCreateProposalV2 { + execution_hash: bcs::from_bytes(script.args().first()?).ok()?, + metadata_location: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_hash: bcs::from_bytes(script.args().get(2)?).ok()?, + is_multi_step_proposal: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn diem_governance_ol_create_proposal_v2( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DiemGovernanceOlCreateProposalV2 { + execution_hash: bcs::from_bytes(script.args().first()?).ok()?, + metadata_location: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_hash: bcs::from_bytes(script.args().get(2)?).ok()?, + is_multi_step_proposal: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn diem_governance_ol_vote(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DiemGovernanceOlVote { + proposal_id: bcs::from_bytes(script.args().first()?).ok()?, + should_pass: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn diem_governance_smoke_trigger_epoch( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::DiemGovernanceSmokeTriggerEpoch {}) + } else { + None + } + } + + pub fn diem_governance_trigger_epoch( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::DiemGovernanceTriggerEpoch {}) + } else { + None + } + } + + pub fn diem_governance_vote(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DiemGovernanceVote { + proposal_id: bcs::from_bytes(script.args().first()?).ok()?, + should_pass: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn donor_voice_txs_propose_liquidate_tx( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DonorVoiceTxsProposeLiquidateTx { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn donor_voice_txs_propose_payment_tx( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DonorVoiceTxsProposePaymentTx { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + payee: bcs::from_bytes(script.args().get(1)?).ok()?, + value: bcs::from_bytes(script.args().get(2)?).ok()?, + description: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn donor_voice_txs_propose_veto_tx( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DonorVoiceTxsProposeVetoTx { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + id: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn donor_voice_txs_vote_liquidation_tx( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DonorVoiceTxsVoteLiquidationTx { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn donor_voice_txs_vote_veto_tx(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DonorVoiceTxsVoteVetoTx { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + id: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn epoch_boundary_smoke_trigger_epoch( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::EpochBoundarySmokeTriggerEpoch {}) + } else { + None + } + } + + pub fn jail_unjail_by_voucher(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::JailUnjailByVoucher { + addr: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn libra_coin_claim_mint_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::LibraCoinClaimMintCapability {}) + } else { + None + } + } + + pub fn libra_coin_delegate_mint_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::LibraCoinDelegateMintCapability { + to: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn libra_coin_mint_to_impl(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::LibraCoinMintToImpl { + dst_addr: bcs::from_bytes(script.args().first()?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn multi_action_claim_offer(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultiActionClaimOffer { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn multi_action_init_gov_deprecated( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::MultiActionInitGovDeprecated {}) + } else { + None + } + } + + pub fn multi_action_migration_migrate_offer( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultiActionMigrationMigrateOffer { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_add_owner(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountAddOwner { + new_owner: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_add_owners(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountAddOwners { + new_owners: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_approve_transaction( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountApproveTransaction { + multisig_account: bcs::from_bytes(script.args().first()?).ok()?, + sequence_number: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_create(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountCreate { + num_signatures_required: bcs::from_bytes(script.args().first()?).ok()?, + metadata_keys: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_values: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_create_transaction( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountCreateTransaction { + multisig_account: bcs::from_bytes(script.args().first()?).ok()?, + payload: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_create_transaction_with_hash( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountCreateTransactionWithHash { + multisig_account: bcs::from_bytes(script.args().first()?).ok()?, + payload_hash: bcs::from_bytes(script.args().get(1)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn multisig_account_create_with_existing_account( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountCreateWithExistingAccount { + multisig_address: bcs::from_bytes(script.args().first()?).ok()?, + owners: bcs::from_bytes(script.args().get(1)?).ok()?, + num_signatures_required: bcs::from_bytes(script.args().get(2)?).ok()?, + account_scheme: bcs::from_bytes(script.args().get(3)?).ok()?, + account_public_key: bcs::from_bytes(script.args().get(4)?).ok()?, + create_multisig_account_signed_message: bcs::from_bytes(script.args().get(5)?) + .ok()?, + metadata_keys: bcs::from_bytes(script.args().get(6)?).ok()?, + metadata_values: bcs::from_bytes(script.args().get(7)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn multisig_account_create_with_owners( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountCreateWithOwners { + additional_owners: bcs::from_bytes(script.args().first()?).ok()?, + num_signatures_required: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_keys: bcs::from_bytes(script.args().get(2)?).ok()?, + metadata_values: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_execute_rejected_transaction( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountExecuteRejectedTransaction { + multisig_account: bcs::from_bytes(script.args().first()?).ok()?, + }, + ) + } else { + None + } + } + + pub fn multisig_account_migrate_with_owners( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountMigrateWithOwners { + additional_owners: bcs::from_bytes(script.args().first()?).ok()?, + num_signatures_required: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_keys: bcs::from_bytes(script.args().get(2)?).ok()?, + metadata_values: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_reject_transaction( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountRejectTransaction { + multisig_account: bcs::from_bytes(script.args().first()?).ok()?, + sequence_number: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_remove_owner( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountRemoveOwner { + owner_to_remove: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_remove_owners( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountRemoveOwners { + owners_to_remove: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_update_metadata( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountUpdateMetadata { + keys: bcs::from_bytes(script.args().first()?).ok()?, + values: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_update_signatures_required( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountUpdateSignaturesRequired { + new_num_signatures_required: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_vote_transanction( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountVoteTransanction { + multisig_account: bcs::from_bytes(script.args().first()?).ok()?, + sequence_number: bcs::from_bytes(script.args().get(1)?).ok()?, + approved: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn object_transfer_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ObjectTransferCall { + object: bcs::from_bytes(script.args().first()?).ok()?, + to: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn ol_account_create_account(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::OlAccountCreateAccount { + auth_key: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn ol_account_set_allow_direct_coin_transfers( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::OlAccountSetAllowDirectCoinTransfers { + allow: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn ol_account_transfer(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::OlAccountTransfer { + to: bcs::from_bytes(script.args().first()?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn proof_of_fee_init_bidding(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::ProofOfFeeInitBidding {}) + } else { + None + } + } + + pub fn proof_of_fee_pof_retract_bid(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::ProofOfFeePofRetractBid {}) + } else { + None + } + } + + pub fn proof_of_fee_pof_update_bid(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ProofOfFeePofUpdateBid { + bid: bcs::from_bytes(script.args().first()?).ok()?, + epoch_expiry: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn safe_init_payment_multisig(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::SafeInitPaymentMultisig { + authorities: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn slow_wallet_smoke_test_vm_unlock( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::SlowWalletSmokeTestVmUnlock { + user_addr: bcs::from_bytes(script.args().first()?).ok()?, + unlocked: bcs::from_bytes(script.args().get(1)?).ok()?, + transferred: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn slow_wallet_user_set_slow(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::SlowWalletUserSetSlow {}) + } else { + None + } + } + + pub fn stake_initialize_validator(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeInitializeValidator { + consensus_pubkey: bcs::from_bytes(script.args().first()?).ok()?, + proof_of_possession: bcs::from_bytes(script.args().get(1)?).ok()?, + network_addresses: bcs::from_bytes(script.args().get(2)?).ok()?, + fullnode_addresses: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_rotate_consensus_key(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeRotateConsensusKey { + validator_address: bcs::from_bytes(script.args().first()?).ok()?, + new_consensus_pubkey: bcs::from_bytes(script.args().get(1)?).ok()?, + proof_of_possession: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_update_network_and_fullnode_addresses( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeUpdateNetworkAndFullnodeAddresses { + validator_address: bcs::from_bytes(script.args().first()?).ok()?, + new_network_addresses: bcs::from_bytes(script.args().get(1)?).ok()?, + new_fullnode_addresses: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn validator_universe_register_validator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ValidatorUniverseRegisterValidator { + consensus_pubkey: bcs::from_bytes(script.args().first()?).ok()?, + proof_of_possession: bcs::from_bytes(script.args().get(1)?).ok()?, + network_addresses: bcs::from_bytes(script.args().get(2)?).ok()?, + fullnode_addresses: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn version_set_version(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VersionSetVersion { + major: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn vouch_insist_vouch_for(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VouchInsistVouchFor { + friend_account: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn vouch_revoke(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VouchRevoke { + friend_account: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } + + pub fn vouch_vouch_for(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VouchVouchFor { + friend_account: bcs::from_bytes(script.args().first()?).ok()?, + }) + } else { + None + } + } +} + +type EntryFunctionDecoderMap = std::collections::HashMap< + String, + Box< + dyn Fn(&TransactionPayload) -> Option + + std::marker::Sync + + std::marker::Send, + >, +>; + +static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(|| { + let mut map: EntryFunctionDecoderMap = std::collections::HashMap::new(); + map.insert( + "account_offer_rotation_capability".to_string(), + Box::new(decoder::account_offer_rotation_capability), + ); + map.insert( + "account_offer_signer_capability".to_string(), + Box::new(decoder::account_offer_signer_capability), + ); + map.insert( + "account_revoke_any_rotation_capability".to_string(), + Box::new(decoder::account_revoke_any_rotation_capability), + ); + map.insert( + "account_revoke_any_signer_capability".to_string(), + Box::new(decoder::account_revoke_any_signer_capability), + ); + map.insert( + "account_revoke_rotation_capability".to_string(), + Box::new(decoder::account_revoke_rotation_capability), + ); + map.insert( + "account_revoke_signer_capability".to_string(), + Box::new(decoder::account_revoke_signer_capability), + ); + map.insert( + "account_rotate_authentication_key".to_string(), + Box::new(decoder::account_rotate_authentication_key), + ); + map.insert( + "account_rotate_authentication_key_with_rotation_capability".to_string(), + Box::new(decoder::account_rotate_authentication_key_with_rotation_capability), + ); + map.insert( + "burn_set_send_community".to_string(), + Box::new(decoder::burn_set_send_community), + ); + map.insert( + "code_publish_package_txn".to_string(), + Box::new(decoder::code_publish_package_txn), + ); + map.insert( + "coin_transfer".to_string(), + Box::new(decoder::coin_transfer), + ); + map.insert( + "community_wallet_init_change_signer_community_multisig".to_string(), + Box::new(decoder::community_wallet_init_change_signer_community_multisig), + ); + map.insert( + "community_wallet_init_finalize_and_cage".to_string(), + Box::new(decoder::community_wallet_init_finalize_and_cage), + ); + map.insert( + "community_wallet_init_init_community".to_string(), + Box::new(decoder::community_wallet_init_init_community), + ); + map.insert( + "community_wallet_init_propose_offer".to_string(), + Box::new(decoder::community_wallet_init_propose_offer), + ); + map.insert( + "diem_governance_add_approved_script_hash_script".to_string(), + Box::new(decoder::diem_governance_add_approved_script_hash_script), + ); + map.insert( + "diem_governance_assert_can_resolve".to_string(), + Box::new(decoder::diem_governance_assert_can_resolve), + ); + map.insert( + "diem_governance_create_proposal_v2".to_string(), + Box::new(decoder::diem_governance_create_proposal_v2), + ); + map.insert( + "diem_governance_ol_create_proposal_v2".to_string(), + Box::new(decoder::diem_governance_ol_create_proposal_v2), + ); + map.insert( + "diem_governance_ol_vote".to_string(), + Box::new(decoder::diem_governance_ol_vote), + ); + map.insert( + "diem_governance_smoke_trigger_epoch".to_string(), + Box::new(decoder::diem_governance_smoke_trigger_epoch), + ); + map.insert( + "diem_governance_trigger_epoch".to_string(), + Box::new(decoder::diem_governance_trigger_epoch), + ); + map.insert( + "diem_governance_vote".to_string(), + Box::new(decoder::diem_governance_vote), + ); + map.insert( + "donor_voice_txs_propose_liquidate_tx".to_string(), + Box::new(decoder::donor_voice_txs_propose_liquidate_tx), + ); + map.insert( + "donor_voice_txs_propose_payment_tx".to_string(), + Box::new(decoder::donor_voice_txs_propose_payment_tx), + ); + map.insert( + "donor_voice_txs_propose_veto_tx".to_string(), + Box::new(decoder::donor_voice_txs_propose_veto_tx), + ); + map.insert( + "donor_voice_txs_vote_liquidation_tx".to_string(), + Box::new(decoder::donor_voice_txs_vote_liquidation_tx), + ); + map.insert( + "donor_voice_txs_vote_veto_tx".to_string(), + Box::new(decoder::donor_voice_txs_vote_veto_tx), + ); + map.insert( + "epoch_boundary_smoke_trigger_epoch".to_string(), + Box::new(decoder::epoch_boundary_smoke_trigger_epoch), + ); + map.insert( + "jail_unjail_by_voucher".to_string(), + Box::new(decoder::jail_unjail_by_voucher), + ); + map.insert( + "libra_coin_claim_mint_capability".to_string(), + Box::new(decoder::libra_coin_claim_mint_capability), + ); + map.insert( + "libra_coin_delegate_mint_capability".to_string(), + Box::new(decoder::libra_coin_delegate_mint_capability), + ); + map.insert( + "libra_coin_mint_to_impl".to_string(), + Box::new(decoder::libra_coin_mint_to_impl), + ); + map.insert( + "multi_action_claim_offer".to_string(), + Box::new(decoder::multi_action_claim_offer), + ); + map.insert( + "multi_action_init_gov_deprecated".to_string(), + Box::new(decoder::multi_action_init_gov_deprecated), + ); + map.insert( + "multi_action_migration_migrate_offer".to_string(), + Box::new(decoder::multi_action_migration_migrate_offer), + ); + map.insert( + "multisig_account_add_owner".to_string(), + Box::new(decoder::multisig_account_add_owner), + ); + map.insert( + "multisig_account_add_owners".to_string(), + Box::new(decoder::multisig_account_add_owners), + ); + map.insert( + "multisig_account_approve_transaction".to_string(), + Box::new(decoder::multisig_account_approve_transaction), + ); + map.insert( + "multisig_account_create".to_string(), + Box::new(decoder::multisig_account_create), + ); + map.insert( + "multisig_account_create_transaction".to_string(), + Box::new(decoder::multisig_account_create_transaction), + ); + map.insert( + "multisig_account_create_transaction_with_hash".to_string(), + Box::new(decoder::multisig_account_create_transaction_with_hash), + ); + map.insert( + "multisig_account_create_with_existing_account".to_string(), + Box::new(decoder::multisig_account_create_with_existing_account), + ); + map.insert( + "multisig_account_create_with_owners".to_string(), + Box::new(decoder::multisig_account_create_with_owners), + ); + map.insert( + "multisig_account_execute_rejected_transaction".to_string(), + Box::new(decoder::multisig_account_execute_rejected_transaction), + ); + map.insert( + "multisig_account_migrate_with_owners".to_string(), + Box::new(decoder::multisig_account_migrate_with_owners), + ); + map.insert( + "multisig_account_reject_transaction".to_string(), + Box::new(decoder::multisig_account_reject_transaction), + ); + map.insert( + "multisig_account_remove_owner".to_string(), + Box::new(decoder::multisig_account_remove_owner), + ); + map.insert( + "multisig_account_remove_owners".to_string(), + Box::new(decoder::multisig_account_remove_owners), + ); + map.insert( + "multisig_account_update_metadata".to_string(), + Box::new(decoder::multisig_account_update_metadata), + ); + map.insert( + "multisig_account_update_signatures_required".to_string(), + Box::new(decoder::multisig_account_update_signatures_required), + ); + map.insert( + "multisig_account_vote_transanction".to_string(), + Box::new(decoder::multisig_account_vote_transanction), + ); + map.insert( + "object_transfer_call".to_string(), + Box::new(decoder::object_transfer_call), + ); + map.insert( + "ol_account_create_account".to_string(), + Box::new(decoder::ol_account_create_account), + ); + map.insert( + "ol_account_set_allow_direct_coin_transfers".to_string(), + Box::new(decoder::ol_account_set_allow_direct_coin_transfers), + ); + map.insert( + "ol_account_transfer".to_string(), + Box::new(decoder::ol_account_transfer), + ); + map.insert( + "proof_of_fee_init_bidding".to_string(), + Box::new(decoder::proof_of_fee_init_bidding), + ); + map.insert( + "proof_of_fee_pof_retract_bid".to_string(), + Box::new(decoder::proof_of_fee_pof_retract_bid), + ); + map.insert( + "proof_of_fee_pof_update_bid".to_string(), + Box::new(decoder::proof_of_fee_pof_update_bid), + ); + map.insert( + "safe_init_payment_multisig".to_string(), + Box::new(decoder::safe_init_payment_multisig), + ); + map.insert( + "slow_wallet_smoke_test_vm_unlock".to_string(), + Box::new(decoder::slow_wallet_smoke_test_vm_unlock), + ); + map.insert( + "slow_wallet_user_set_slow".to_string(), + Box::new(decoder::slow_wallet_user_set_slow), + ); + map.insert( + "stake_initialize_validator".to_string(), + Box::new(decoder::stake_initialize_validator), + ); + map.insert( + "stake_rotate_consensus_key".to_string(), + Box::new(decoder::stake_rotate_consensus_key), + ); + map.insert( + "stake_update_network_and_fullnode_addresses".to_string(), + Box::new(decoder::stake_update_network_and_fullnode_addresses), + ); + map.insert( + "validator_universe_register_validator".to_string(), + Box::new(decoder::validator_universe_register_validator), + ); + map.insert( + "version_set_version".to_string(), + Box::new(decoder::version_set_version), + ); + map.insert( + "vouch_insist_vouch_for".to_string(), + Box::new(decoder::vouch_insist_vouch_for), + ); + map.insert("vouch_revoke".to_string(), Box::new(decoder::vouch_revoke)); + map.insert( + "vouch_vouch_for".to_string(), + Box::new(decoder::vouch_vouch_for), + ); + map + });