diff --git a/Cargo.lock b/Cargo.lock index 551fa211e0..2c8e7b921e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10623,6 +10623,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "starcoin-cached-packages" +version = "0.1.0" +dependencies = [ + "anyhow", + "bcs 0.1.6", + "move-core-types", + "once_cell", + "proptest", + "proptest-derive 0.3.0", + "starcoin-framework", + "starcoin-package-builder", + "starcoin-vm-types", +] + [[package]] name = "starcoin-chain" version = "2.0.1" @@ -12126,6 +12141,27 @@ dependencies = [ "vm-status-translator", ] +[[package]] +name = "starcoin-sdk-builder" +version = "0.2.0" +dependencies = [ + "anyhow", + "bcs 0.1.6", + "clap 3.2.25", + "heck 0.3.3", + "move-core-types", + "once_cell", + "serde-generate", + "serde-reflection 0.3.2", + "serde_yaml 0.8.26", + "starcoin-cached-packages", + "starcoin-framework", + "starcoin-vm-types", + "tempfile", + "textwrap 0.14.2", + "which", +] + [[package]] name = "starcoin-service-registry" version = "2.0.1" diff --git a/Cargo.toml b/Cargo.toml index 4e01f3c609..fe4e9527e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,7 @@ members = [ "vm/vm-runtime-types", "vm/vm-runtime", "vm/frameworks", + "vm/framework/cached-packages", "vm/starcoin-native-interface", "vm/stdlib", "vm/compiler", @@ -99,6 +100,7 @@ members = [ "vm/e2e-tests", "vm/proptest-helpers", "vm/starcoin-native-interface", + "vm/starcoin-sdk-builder", "abi/types", "abi/decoder", "abi/resolver", @@ -192,7 +194,9 @@ default-members = [ "vm/vm-runtime-types", "vm/vm-runtime", "vm/framework", + "vm/framework/cached-packages", "vm/frameworks", + "vm/starcoin-sdk-builder", "vm/starcoin-native-interface", "vm/stdlib", "vm/compiler", @@ -526,6 +530,7 @@ starcoin-rpc-api = { path = "rpc/api" } starcoin-rpc-client = { path = "rpc/client" } starcoin-rpc-middleware = { path = "rpc/middleware" } starcoin-rpc-server = { path = "rpc/server" } +starcoin-sdk-builder = {path = "vm/starcoin-sdk-builder"} starcoin-service-registry = { path = "commons/service-registry" } starcoin-state-api = { path = "state/api" } starcoin-state-service = { path = "state/service" } @@ -562,6 +567,8 @@ starcoin-proptest-helpers = { path = "vm/proptest-helpers" } starcoin-dag = { path = "flexidag" } starcoin-move-stdlib = { path = "vm/framework/move-stdlib"} starcoin-table-natives = { path = "vm/framework/table-natives" } +starcoin-cached-packages = { path = "vm/framework/cached-packages" } + syn = { version = "1.0.107", features = [ "full", diff --git a/vm/framework/cached-packages/Cargo.toml b/vm/framework/cached-packages/Cargo.toml new file mode 100644 index 0000000000..44a0156b5d --- /dev/null +++ b/vm/framework/cached-packages/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "starcoin-cached-packages" +description = "Builds framework packages for caching in builds and tests" +version = "0.1.0" + +# Workspace inherited keys +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +publish = { workspace = true } +repository = { workspace = true } +rust-version = { workspace = true } + +[dependencies] +starcoin-framework = { workspace = true } +starcoin-package-builder = { workspace = true } +starcoin-vm-types = { workspace = true } +bcs = { workspace = true } +move-core-types = { workspace = true } +once_cell = { workspace = true } +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } + +[build-dependencies] +anyhow = { workspace = true } +starcoin-framework = { workspace = true } + +[features] +default = [] +fuzzing = ["proptest", "proptest-derive"] + +[package.metadata.cargo-machete] +ignored = ["proptest"] diff --git a/vm/framework/cached-packages/build.rs b/vm/framework/cached-packages/build.rs new file mode 100644 index 0000000000..581e8c7b32 --- /dev/null +++ b/vm/framework/cached-packages/build.rs @@ -0,0 +1,86 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::{Context, Result}; +use aptos_framework::ReleaseTarget; +use std::{env::current_dir, path::PathBuf}; + +fn main() -> Result<()> { + // Set the below variable to skip the building step. This might be useful if the build + // is broken so it can be debugged with the old outdated artifacts. + if std::env::var("SKIP_FRAMEWORK_BUILD").is_err() { + let current_dir = current_dir().expect("Should be able to get current dir"); + // Get the previous directory + let mut prev_dir = current_dir; + prev_dir.pop(); + println!( + "cargo:rerun-if-changed={}", + prev_dir + .join("aptos-token-objects") + .join("Move.toml") + .display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir + .join("aptos-token-objects") + .join("sources") + .display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("aptos-token").join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("aptos-token").join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir + .join("aptos-token-objects") + .join("sources") + .display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir + .join("aptos-token-objects") + .join("Move.toml") + .display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("aptos-framework").join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("aptos-framework").join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("aptos-stdlib").join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("aptos-stdlib").join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("move-stdlib").join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + prev_dir.join("move-stdlib").join("Move.toml").display() + ); + + let path = + PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR defined")).join("head.mrb"); + + ReleaseTarget::Head + .create_release(true, Some(path)) + .context("Failed to create release")?; + } + + Ok(()) +} diff --git a/vm/framework/cached-packages/src/lib.rs b/vm/framework/cached-packages/src/lib.rs new file mode 100644 index 0000000000..f11c223ebc --- /dev/null +++ b/vm/framework/cached-packages/src/lib.rs @@ -0,0 +1,24 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use starcoin_framework::ReleaseBundle; +use once_cell::sync::Lazy; + +pub mod starcoin_framework_sdk_builder; +pub mod starcoin_stdlib; +pub mod starcoin_token_objects_sdk_builder; +pub mod starcoin_token_sdk_builder; + +#[cfg(unix)] +const HEAD_RELEASE_BUNDLE_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/head.mrb")); +#[cfg(windows)] +const HEAD_RELEASE_BUNDLE_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "\\head.mrb")); + +static HEAD_RELEASE_BUNDLE: Lazy = Lazy::new(|| { + bcs::from_bytes::(HEAD_RELEASE_BUNDLE_BYTES).expect("bcs succeeds") +}); + +/// Returns the release bundle for the current code. +pub fn head_release_bundle() -> &'static ReleaseBundle { + &HEAD_RELEASE_BUNDLE +} diff --git a/vm/framework/cached-packages/src/starcoin_framework_sdk_builder.rs b/vm/framework/cached-packages/src/starcoin_framework_sdk_builder.rs new file mode 100644 index 0000000000..160e0c5f3c --- /dev/null +++ b/vm/framework/cached-packages/src/starcoin_framework_sdk_builder.rs @@ -0,0 +1,6923 @@ +// Copyright © Aptos 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 Aptos transactions (`Script`). +// +// This code was generated by compiling known Script interfaces ("ABIs") with the tool `aptos-sdk-builder`. + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::arc_with_non_send_sync)] +#![allow(clippy::get_first)] +use starcoin_vm_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 { .. } +/// } +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +#[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, + }, + + /// Private entry function for key rotation that allows the signer to update their authentication key. + /// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it + /// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to + /// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in + /// the format expected in `rotate_authentication_key`. + AccountRotateAuthenticationKeyCall { + new_auth_key: Vec, + }, + + AccountRotateAuthenticationKeyWithRotationCapability { + rotation_cap_offerer_address: AccountAddress, + new_scheme: u8, + new_public_key_bytes: Vec, + cap_update_table: Vec, + }, + + /// Batch version of APT transfer. + AptosAccountBatchTransfer { + recipients: Vec, + amounts: Vec, + }, + + /// Batch version of transfer_coins. + AptosAccountBatchTransferCoins { + coin_type: TypeTag, + recipients: Vec, + amounts: Vec, + }, + + /// Basic account creation methods. + AptosAccountCreateAccount { + auth_key: AccountAddress, + }, + + /// Set whether `account` can receive direct transfers of coins that they have not explicitly registered to receive. + AptosAccountSetAllowDirectCoinTransfers { + allow: bool, + }, + + /// Convenient function to transfer APT to a recipient account that might not exist. + /// This would create the recipient account first, which also registers it to receive APT, before transferring. + AptosAccountTransfer { + to: AccountAddress, + amount: u64, + }, + + /// Convenient function to transfer a custom CoinType to a recipient account that might not exist. + /// This would create the recipient account first and register it to receive the CoinType, before transferring. + AptosAccountTransferCoins { + coin_type: TypeTag, + to: AccountAddress, + amount: u64, + }, + + /// Only callable in tests and testnets where the core resources account exists. + /// Claim the delegated mint capability and destroy the delegated token. + AptosCoinClaimMintCapability {}, + + /// 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. + AptosCoinDelegateMintCapability { + to: AccountAddress, + }, + + /// Only callable in tests and testnets where the core resources account exists. + /// Create new coins and deposit them into dst_addr's account. + AptosCoinMint { + dst_addr: AccountAddress, + amount: u64, + }, + + AptosGovernanceAddApprovedScriptHashScript { + proposal_id: u64, + }, + + /// Batch vote on proposal with proposal_id and specified voting power from multiple stake_pools. + AptosGovernanceBatchPartialVote { + stake_pools: Vec, + proposal_id: u64, + voting_power: u64, + should_pass: bool, + }, + + /// Vote on proposal with proposal_id and all voting power from multiple stake_pools. + AptosGovernanceBatchVote { + stake_pools: Vec, + proposal_id: u64, + should_pass: bool, + }, + + /// Create a single-step proposal with the backing `stake_pool`. + /// @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. + AptosGovernanceCreateProposal { + stake_pool: AccountAddress, + execution_hash: Vec, + metadata_location: Vec, + metadata_hash: Vec, + }, + + /// Create a single-step or multi-step proposal with the backing `stake_pool`. + /// @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. + AptosGovernanceCreateProposalV2 { + stake_pool: AccountAddress, + execution_hash: Vec, + metadata_location: Vec, + metadata_hash: Vec, + is_multi_step_proposal: bool, + }, + + /// Change epoch immediately. + /// If `RECONFIGURE_WITH_DKG` is enabled and we are in the middle of a DKG, + /// stop waiting for DKG and enter the new epoch without randomness. + /// + /// WARNING: currently only used by tests. In most cases you should use `reconfigure()` instead. + /// TODO: migrate these tests to be aware of async reconfiguration. + AptosGovernanceForceEndEpoch {}, + + /// `force_end_epoch()` equivalent but only called in testnet, + /// where the core resources account exists and has been granted power to mint Aptos coins. + AptosGovernanceForceEndEpochTestOnly {}, + + /// Vote on proposal with `proposal_id` and specified voting power from `stake_pool`. + AptosGovernancePartialVote { + stake_pool: AccountAddress, + proposal_id: u64, + voting_power: u64, + should_pass: bool, + }, + + /// Manually reconfigure. Called at the end of a governance txn that alters on-chain configs. + /// + /// WARNING: this function always ensures a reconfiguration starts, but when the reconfiguration finishes depends. + /// - If feature `RECONFIGURE_WITH_DKG` is disabled, it finishes immediately. + /// - At the end of the calling transaction, we will be in a new epoch. + /// - If feature `RECONFIGURE_WITH_DKG` is enabled, it starts DKG, and the new epoch will start in a block prologue after DKG finishes. + /// + /// This behavior affects when an update of an on-chain config (e.g. `ConsensusConfig`, `Features`) takes effect, + /// since such updates are applied whenever we enter an new epoch. + AptosGovernanceReconfigure {}, + + /// Vote on proposal with `proposal_id` and all voting power from `stake_pool`. + AptosGovernanceVote { + stake_pool: AccountAddress, + proposal_id: u64, + should_pass: 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>, + }, + + CoinCreateCoinConversionMap {}, + + /// Create APT pairing by passing `AptosCoin`. + CoinCreatePairing { + coin_type: TypeTag, + }, + + /// Voluntarily migrate to fungible store for `CoinType` if not yet. + CoinMigrateToFungibleStore { + coin_type: TypeTag, + }, + + /// Transfers `amount` of coins `CoinType` from `from` to `to`. + CoinTransfer { + coin_type: TypeTag, + to: AccountAddress, + amount: u64, + }, + + /// Upgrade total supply to use a parallelizable implementation if it is + /// available. + CoinUpgradeSupply { + coin_type: TypeTag, + }, + + /// Add `amount` of coins to the delegation pool `pool_address`. + DelegationPoolAddStake { + pool_address: AccountAddress, + amount: u64, + }, + + /// Allowlist a delegator as the pool owner. + DelegationPoolAllowlistDelegator { + delegator_address: AccountAddress, + }, + + /// A voter could create a governance proposal by this function. To successfully create a proposal, the voter's + /// voting power in THIS delegation pool must be not less than the minimum required voting power specified in + /// `aptos_governance.move`. + DelegationPoolCreateProposal { + pool_address: AccountAddress, + execution_hash: Vec, + metadata_location: Vec, + metadata_hash: Vec, + is_multi_step_proposal: bool, + }, + + /// Allows a delegator to delegate its voting power to a voter. If this delegator already has a delegated voter, + /// this change won't take effects until the next lockup period. + DelegationPoolDelegateVotingPower { + pool_address: AccountAddress, + new_voter: AccountAddress, + }, + + /// Disable delegators allowlisting as the pool owner. The existing allowlist will be emptied. + DelegationPoolDisableDelegatorsAllowlisting {}, + + /// Enable delegators allowlisting as the pool owner. + DelegationPoolEnableDelegatorsAllowlisting {}, + + /// Enable partial governance voting on a stake pool. The voter of this stake pool will be managed by this module. + /// The existing voter will be replaced. The function is permissionless. + DelegationPoolEnablePartialGovernanceVoting { + pool_address: AccountAddress, + }, + + /// Evict a delegator that is not allowlisted by unlocking their entire stake. + DelegationPoolEvictDelegator { + delegator_address: AccountAddress, + }, + + /// Initialize a delegation pool of custom fixed `operator_commission_percentage`. + /// A resource account is created from `owner` signer and its supplied `delegation_pool_creation_seed` + /// to host the delegation pool resource and own the underlying stake pool. + /// Ownership over setting the operator/voter is granted to `owner` who has both roles initially. + DelegationPoolInitializeDelegationPool { + operator_commission_percentage: u64, + delegation_pool_creation_seed: Vec, + }, + + /// Move `amount` of coins from pending_inactive to active. + DelegationPoolReactivateStake { + pool_address: AccountAddress, + amount: u64, + }, + + /// Remove a delegator from the allowlist as the pool owner, but do not unlock their stake. + DelegationPoolRemoveDelegatorFromAllowlist { + delegator_address: AccountAddress, + }, + + /// Allows an operator to change its beneficiary. Any existing unpaid commission rewards will be paid to the new + /// beneficiary. To ensure payment to the current beneficiary, one should first call `synchronize_delegation_pool` + /// before switching the beneficiary. An operator can set one beneficiary for delegation pools, not a separate + /// one for each pool. + DelegationPoolSetBeneficiaryForOperator { + new_beneficiary: AccountAddress, + }, + + /// Allows an owner to change the delegated voter of the underlying stake pool. + DelegationPoolSetDelegatedVoter { + new_voter: AccountAddress, + }, + + /// Allows an owner to change the operator of the underlying stake pool. + DelegationPoolSetOperator { + new_operator: AccountAddress, + }, + + /// Synchronize delegation and stake pools: distribute yet-undetected rewards to the corresponding internal + /// shares pools, assign commission to operator and eventually prepare delegation pool for a new lockup cycle. + DelegationPoolSynchronizeDelegationPool { + pool_address: AccountAddress, + }, + + /// Unlock `amount` from the active + pending_active stake of `delegator` or + /// at most how much active stake there is on the stake pool. + DelegationPoolUnlock { + pool_address: AccountAddress, + amount: u64, + }, + + /// Allows an owner to update the commission percentage for the operator of the underlying stake pool. + DelegationPoolUpdateCommissionPercentage { + new_commission_percentage: u64, + }, + + /// Vote on a proposal with a voter's voting power. To successfully vote, the following conditions must be met: + /// 1. The voting period of the proposal hasn't ended. + /// 2. The delegation pool's lockup period ends after the voting period of the proposal. + /// 3. The voter still has spare voting power on this proposal. + /// 4. The delegation pool never votes on the proposal before enabling partial governance voting. + DelegationPoolVote { + pool_address: AccountAddress, + proposal_id: u64, + voting_power: u64, + should_pass: bool, + }, + + /// Withdraw `amount` of owned inactive stake from the delegation pool at `pool_address`. + DelegationPoolWithdraw { + pool_address: AccountAddress, + amount: u64, + }, + + /// Withdraw an `amount` of coin `CoinType` from `account` and burn it. + ManagedCoinBurn { + coin_type: TypeTag, + amount: u64, + }, + + /// Initialize new coin `CoinType` in Aptos Blockchain. + /// Mint and Burn Capabilities will be stored under `account` in `Capabilities` resource. + ManagedCoinInitialize { + coin_type: TypeTag, + name: Vec, + symbol: Vec, + decimals: u8, + monitor_supply: bool, + }, + + /// Create new coins `CoinType` and deposit them into dst_addr's account. + ManagedCoinMint { + coin_type: TypeTag, + dst_addr: AccountAddress, + amount: u64, + }, + + /// Creating a resource that stores balance of `CoinType` on user's account, withdraw and deposit event handlers. + /// Required if user wants to start accepting deposits of `CoinType` in his account. + ManagedCoinRegister { + coin_type: TypeTag, + }, + + /// 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, + }, + + /// Add owners then update number of signatures required, in a single operation. + MultisigAccountAddOwnersAndUpdateSignaturesRequired { + new_owners: Vec, + new_num_signatures_required: u64, + }, + + /// 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). + 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. + 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. + /// + /// Note that this does not revoke auth key-based control over the account. Owners should separately rotate the auth + /// key after they are fully migrated to the new multisig account. Alternatively, they can call + /// create_with_existing_account_and_revoke_auth_key instead. + 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 on top of an existing account and immediately rotate the origin auth key to 0x0. + /// + /// Note: If the original account is a resource account, this does not revoke all control over it as if any + /// SignerCapability of the resource account still exists, it can still be used to generate the signer for the + /// account. + MultisigAccountCreateWithExistingAccountAndRevokeAuthKey { + 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>, + }, + + /// Like `create_with_owners`, but removes the calling account after creation. + /// + /// This is for creating a vanity multisig account from a bootstrapping account that should not + /// be an owner after the vanity multisig address has been secured. + MultisigAccountCreateWithOwnersThenRemoveBootstrapper { + 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, + }, + + /// Remove the next transactions until the final_sequence_number if they have sufficient owner rejections. + MultisigAccountExecuteRejectedTransactions { + multisig_account: AccountAddress, + final_sequence_number: u64, + }, + + /// 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, + }, + + /// Swap an owner in for an old one, without changing required signatures. + MultisigAccountSwapOwner { + to_swap_in: AccountAddress, + to_swap_out: AccountAddress, + }, + + /// Swap owners in and out, without changing required signatures. + MultisigAccountSwapOwners { + to_swap_in: Vec, + to_swap_out: Vec, + }, + + /// Swap owners in and out, updating number of required signatures. + MultisigAccountSwapOwnersAndUpdateSignaturesRequired { + new_owners: Vec, + owners_to_remove: Vec, + new_num_signatures_required: u64, + }, + + /// 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 + MultisigAccountVoteTransaction { + multisig_account: AccountAddress, + sequence_number: u64, + approved: bool, + }, + + /// Generic function that can be used to either approve or reject a batch of transactions within a specified range. + MultisigAccountVoteTransactions { + multisig_account: AccountAddress, + starting_sequence_number: u64, + final_sequence_number: u64, + approved: bool, + }, + + /// Generic function that can be used to either approve or reject a multisig transaction + /// Retained for backward compatibility: the function with the typographical error in its name + /// will continue to be an accessible entry point. + 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, + }, + + /// Creates a new object with a unique address derived from the publisher address and the object seed. + /// Publishes the code passed in the function to the newly created object. + /// The caller must provide package metadata describing the package via `metadata_serialized` and + /// the code to be published via `code`. This contains a vector of modules to be deployed on-chain. + ObjectCodeDeploymentPublish { + metadata_serialized: Vec, + code: Vec>, + }, + + /// Creates a new resource account and rotates the authentication key to either + /// the optional auth key if it is non-empty (though auth keys are 32-bytes) + /// or the source accounts current auth key. + ResourceAccountCreateResourceAccount { + seed: Vec, + optional_auth_key: Vec, + }, + + /// Creates a new resource account, transfer the amount of coins from the origin to the resource + /// account, and rotates the authentication key to either the optional auth key if it is + /// non-empty (though auth keys are 32-bytes) or the source accounts current auth key. Note, + /// this function adds additional resource ownership to the resource account and should only be + /// used for resource accounts that need access to `Coin`. + ResourceAccountCreateResourceAccountAndFund { + seed: Vec, + optional_auth_key: Vec, + fund_amount: u64, + }, + + /// Creates a new resource account, publishes the package under this account transaction under + /// this account and leaves the signer cap readily available for pickup. + ResourceAccountCreateResourceAccountAndPublishPackage { + seed: Vec, + metadata_serialized: Vec, + code: Vec>, + }, + + /// Add `amount` of coins from the `account` owning the StakePool. + StakeAddStake { + amount: u64, + }, + + /// Similar to increase_lockup_with_cap but will use ownership capability from the signing account. + StakeIncreaseLockup {}, + + /// Initialize the validator account and give ownership to the signing account + /// except it leaves the ValidatorConfig to be set by another entity. + /// Note: this triggers setting the operator and owner, set it to the account's address + /// to set later. + StakeInitializeStakeOwner { + initial_stake_amount: u64, + operator: AccountAddress, + voter: AccountAddress, + }, + + /// 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, + }, + + /// This can only called by the operator of the validator/staking pool. + StakeJoinValidatorSet { + pool_address: AccountAddress, + }, + + /// Request to have `pool_address` leave the validator set. The validator is only actually removed from the set when + /// the next epoch starts. + /// The last validator in the set cannot leave. This is an edge case that should never happen as long as the network + /// is still operational. + /// + /// Can only be called by the operator of the validator/staking pool. + StakeLeaveValidatorSet { + pool_address: AccountAddress, + }, + + /// Move `amount` of coins from pending_inactive to active. + StakeReactivateStake { + amount: u64, + }, + + /// Rotate the consensus key of the validator, it'll take effect in next epoch. + StakeRotateConsensusKey { + pool_address: AccountAddress, + new_consensus_pubkey: Vec, + proof_of_possession: Vec, + }, + + /// Allows an owner to change the delegated voter of the stake pool. + StakeSetDelegatedVoter { + new_voter: AccountAddress, + }, + + /// Allows an owner to change the operator of the stake pool. + StakeSetOperator { + new_operator: AccountAddress, + }, + + /// Similar to unlock_with_cap but will use ownership capability from the signing account. + StakeUnlock { + amount: u64, + }, + + /// Update the network and full node addresses of the validator. This only takes effect in the next epoch. + StakeUpdateNetworkAndFullnodeAddresses { + pool_address: AccountAddress, + new_network_addresses: Vec, + new_fullnode_addresses: Vec, + }, + + /// Withdraw from `account`'s inactive stake. + StakeWithdraw { + withdraw_amount: u64, + }, + + /// Add more stake to an existing staking contract. + StakingContractAddStake { + operator: AccountAddress, + amount: u64, + }, + + /// Staker can call this function to create a simple staking contract with a specified operator. + StakingContractCreateStakingContract { + operator: AccountAddress, + voter: AccountAddress, + amount: u64, + commission_percentage: u64, + contract_creation_seed: Vec, + }, + + /// Allow anyone to distribute already unlocked funds. This does not affect reward compounding and therefore does + /// not need to be restricted to just the staker or operator. + StakingContractDistribute { + staker: AccountAddress, + operator: AccountAddress, + }, + + /// Unlock commission amount from the stake pool. Operator needs to wait for the amount to become withdrawable + /// at the end of the stake pool's lockup period before they can actually can withdraw_commission. + /// + /// Only staker, operator or beneficiary can call this. + StakingContractRequestCommission { + staker: AccountAddress, + operator: AccountAddress, + }, + + /// Convenient function to allow the staker to reset their stake pool's lockup period to start now. + StakingContractResetLockup { + operator: AccountAddress, + }, + + /// Allows an operator to change its beneficiary. Any existing unpaid commission rewards will be paid to the new + /// beneficiary. To ensures payment to the current beneficiary, one should first call `distribute` before switching + /// the beneficiary. An operator can set one beneficiary for staking contract pools, not a separate one for each pool. + StakingContractSetBeneficiaryForOperator { + new_beneficiary: AccountAddress, + }, + + /// Allows staker to switch operator without going through the lenghthy process to unstake. + StakingContractSwitchOperator { + old_operator: AccountAddress, + new_operator: AccountAddress, + new_commission_percentage: u64, + }, + + /// Allows staker to switch operator without going through the lenghthy process to unstake, without resetting commission. + StakingContractSwitchOperatorWithSameCommission { + old_operator: AccountAddress, + new_operator: AccountAddress, + }, + + /// Unlock all accumulated rewards since the last recorded principals. + StakingContractUnlockRewards { + operator: AccountAddress, + }, + + /// Staker can call this to request withdrawal of part or all of their staking_contract. + /// This also triggers paying commission to the operator for accounting simplicity. + StakingContractUnlockStake { + operator: AccountAddress, + amount: u64, + }, + + /// Convenience function to allow a staker to update the commission percentage paid to the operator. + /// TODO: fix the typo in function name. commision -> commission + StakingContractUpdateCommision { + operator: AccountAddress, + new_commission_percentage: u64, + }, + + /// Convenient function to allow the staker to update the voter address in a staking contract they made. + StakingContractUpdateVoter { + operator: AccountAddress, + new_voter: AccountAddress, + }, + + StakingProxySetOperator { + old_operator: AccountAddress, + new_operator: AccountAddress, + }, + + StakingProxySetStakePoolOperator { + new_operator: AccountAddress, + }, + + StakingProxySetStakePoolVoter { + new_voter: AccountAddress, + }, + + StakingProxySetStakingContractOperator { + old_operator: AccountAddress, + new_operator: AccountAddress, + }, + + StakingProxySetStakingContractVoter { + operator: AccountAddress, + new_voter: AccountAddress, + }, + + StakingProxySetVestingContractOperator { + old_operator: AccountAddress, + new_operator: AccountAddress, + }, + + StakingProxySetVestingContractVoter { + operator: AccountAddress, + new_voter: AccountAddress, + }, + + StakingProxySetVoter { + operator: AccountAddress, + new_voter: AccountAddress, + }, + + TransactionFeeConvertToAptosFaBurnRef {}, + + /// Used in on-chain governances to update the major version for the next epoch. + /// Example usage: + /// - `aptos_framework::version::set_for_next_epoch(&framework_signer, new_version);` + /// - `aptos_framework::aptos_governance::reconfigure(&framework_signer);` + VersionSetForNextEpoch { + major: u64, + }, + + /// Deprecated by `set_for_next_epoch()`. + /// + /// WARNING: calling this while randomness is enabled will trigger a new epoch without randomness! + /// + /// TODO: update all the tests that reference this function, then disable this function. + VersionSetVersion { + major: u64, + }, + + /// Withdraw all funds to the preset vesting contract's withdrawal address. This can only be called if the contract + /// has already been terminated. + VestingAdminWithdraw { + contract_address: AccountAddress, + }, + + /// Distribute any withdrawable stake from the stake pool. + VestingDistribute { + contract_address: AccountAddress, + }, + + /// Call `distribute` for many vesting contracts. + VestingDistributeMany { + contract_addresses: Vec, + }, + + /// Remove the beneficiary for the given shareholder. All distributions will sent directly to the shareholder + /// account. + VestingResetBeneficiary { + contract_address: AccountAddress, + shareholder: AccountAddress, + }, + + VestingResetLockup { + contract_address: AccountAddress, + }, + + VestingSetBeneficiary { + contract_address: AccountAddress, + shareholder: AccountAddress, + new_beneficiary: AccountAddress, + }, + + /// Set the beneficiary for the operator. + VestingSetBeneficiaryForOperator { + new_beneficiary: AccountAddress, + }, + + VestingSetBeneficiaryResetter { + contract_address: AccountAddress, + beneficiary_resetter: AccountAddress, + }, + + VestingSetManagementRole { + contract_address: AccountAddress, + role: Vec, + role_holder: AccountAddress, + }, + + /// Terminate the vesting contract and send all funds back to the withdrawal address. + VestingTerminateVestingContract { + contract_address: AccountAddress, + }, + + /// Unlock any accumulated rewards. + VestingUnlockRewards { + contract_address: AccountAddress, + }, + + /// Call `unlock_rewards` for many vesting contracts. + VestingUnlockRewardsMany { + contract_addresses: Vec, + }, + + VestingUpdateCommissionPercentage { + contract_address: AccountAddress, + new_commission_percentage: u64, + }, + + VestingUpdateOperator { + contract_address: AccountAddress, + new_operator: AccountAddress, + commission_percentage: u64, + }, + + VestingUpdateOperatorWithSameCommission { + contract_address: AccountAddress, + new_operator: AccountAddress, + }, + + VestingUpdateVoter { + contract_address: AccountAddress, + new_voter: AccountAddress, + }, + + /// Unlock any vested portion of the grant. + VestingVest { + contract_address: AccountAddress, + }, + + /// Call `vest` for many vesting contracts. + VestingVestMany { + contract_addresses: Vec, + }, +} + +impl EntryFunctionCall { + /// Build an Aptos `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, + ), + AccountRotateAuthenticationKeyCall { new_auth_key } => { + account_rotate_authentication_key_call(new_auth_key) + }, + 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, + ), + AptosAccountBatchTransfer { + recipients, + amounts, + } => aptos_account_batch_transfer(recipients, amounts), + AptosAccountBatchTransferCoins { + coin_type, + recipients, + amounts, + } => aptos_account_batch_transfer_coins(coin_type, recipients, amounts), + AptosAccountCreateAccount { auth_key } => aptos_account_create_account(auth_key), + AptosAccountSetAllowDirectCoinTransfers { allow } => { + aptos_account_set_allow_direct_coin_transfers(allow) + }, + AptosAccountTransfer { to, amount } => aptos_account_transfer(to, amount), + AptosAccountTransferCoins { + coin_type, + to, + amount, + } => aptos_account_transfer_coins(coin_type, to, amount), + AptosCoinClaimMintCapability {} => aptos_coin_claim_mint_capability(), + AptosCoinDelegateMintCapability { to } => aptos_coin_delegate_mint_capability(to), + AptosCoinMint { dst_addr, amount } => aptos_coin_mint(dst_addr, amount), + AptosGovernanceAddApprovedScriptHashScript { proposal_id } => { + aptos_governance_add_approved_script_hash_script(proposal_id) + }, + AptosGovernanceBatchPartialVote { + stake_pools, + proposal_id, + voting_power, + should_pass, + } => aptos_governance_batch_partial_vote( + stake_pools, + proposal_id, + voting_power, + should_pass, + ), + AptosGovernanceBatchVote { + stake_pools, + proposal_id, + should_pass, + } => aptos_governance_batch_vote(stake_pools, proposal_id, should_pass), + AptosGovernanceCreateProposal { + stake_pool, + execution_hash, + metadata_location, + metadata_hash, + } => aptos_governance_create_proposal( + stake_pool, + execution_hash, + metadata_location, + metadata_hash, + ), + AptosGovernanceCreateProposalV2 { + stake_pool, + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + } => aptos_governance_create_proposal_v2( + stake_pool, + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + ), + AptosGovernanceForceEndEpoch {} => aptos_governance_force_end_epoch(), + AptosGovernanceForceEndEpochTestOnly {} => aptos_governance_force_end_epoch_test_only(), + AptosGovernancePartialVote { + stake_pool, + proposal_id, + voting_power, + should_pass, + } => aptos_governance_partial_vote(stake_pool, proposal_id, voting_power, should_pass), + AptosGovernanceReconfigure {} => aptos_governance_reconfigure(), + AptosGovernanceVote { + stake_pool, + proposal_id, + should_pass, + } => aptos_governance_vote(stake_pool, proposal_id, should_pass), + CodePublishPackageTxn { + metadata_serialized, + code, + } => code_publish_package_txn(metadata_serialized, code), + CoinCreateCoinConversionMap {} => coin_create_coin_conversion_map(), + CoinCreatePairing { coin_type } => coin_create_pairing(coin_type), + CoinMigrateToFungibleStore { coin_type } => coin_migrate_to_fungible_store(coin_type), + CoinTransfer { + coin_type, + to, + amount, + } => coin_transfer(coin_type, to, amount), + CoinUpgradeSupply { coin_type } => coin_upgrade_supply(coin_type), + DelegationPoolAddStake { + pool_address, + amount, + } => delegation_pool_add_stake(pool_address, amount), + DelegationPoolAllowlistDelegator { delegator_address } => { + delegation_pool_allowlist_delegator(delegator_address) + }, + DelegationPoolCreateProposal { + pool_address, + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + } => delegation_pool_create_proposal( + pool_address, + execution_hash, + metadata_location, + metadata_hash, + is_multi_step_proposal, + ), + DelegationPoolDelegateVotingPower { + pool_address, + new_voter, + } => delegation_pool_delegate_voting_power(pool_address, new_voter), + DelegationPoolDisableDelegatorsAllowlisting {} => { + delegation_pool_disable_delegators_allowlisting() + }, + DelegationPoolEnableDelegatorsAllowlisting {} => { + delegation_pool_enable_delegators_allowlisting() + }, + DelegationPoolEnablePartialGovernanceVoting { pool_address } => { + delegation_pool_enable_partial_governance_voting(pool_address) + }, + DelegationPoolEvictDelegator { delegator_address } => { + delegation_pool_evict_delegator(delegator_address) + }, + DelegationPoolInitializeDelegationPool { + operator_commission_percentage, + delegation_pool_creation_seed, + } => delegation_pool_initialize_delegation_pool( + operator_commission_percentage, + delegation_pool_creation_seed, + ), + DelegationPoolReactivateStake { + pool_address, + amount, + } => delegation_pool_reactivate_stake(pool_address, amount), + DelegationPoolRemoveDelegatorFromAllowlist { delegator_address } => { + delegation_pool_remove_delegator_from_allowlist(delegator_address) + }, + DelegationPoolSetBeneficiaryForOperator { new_beneficiary } => { + delegation_pool_set_beneficiary_for_operator(new_beneficiary) + }, + DelegationPoolSetDelegatedVoter { new_voter } => { + delegation_pool_set_delegated_voter(new_voter) + }, + DelegationPoolSetOperator { new_operator } => { + delegation_pool_set_operator(new_operator) + }, + DelegationPoolSynchronizeDelegationPool { pool_address } => { + delegation_pool_synchronize_delegation_pool(pool_address) + }, + DelegationPoolUnlock { + pool_address, + amount, + } => delegation_pool_unlock(pool_address, amount), + DelegationPoolUpdateCommissionPercentage { + new_commission_percentage, + } => delegation_pool_update_commission_percentage(new_commission_percentage), + DelegationPoolVote { + pool_address, + proposal_id, + voting_power, + should_pass, + } => delegation_pool_vote(pool_address, proposal_id, voting_power, should_pass), + DelegationPoolWithdraw { + pool_address, + amount, + } => delegation_pool_withdraw(pool_address, amount), + ManagedCoinBurn { coin_type, amount } => managed_coin_burn(coin_type, amount), + ManagedCoinInitialize { + coin_type, + name, + symbol, + decimals, + monitor_supply, + } => managed_coin_initialize(coin_type, name, symbol, decimals, monitor_supply), + ManagedCoinMint { + coin_type, + dst_addr, + amount, + } => managed_coin_mint(coin_type, dst_addr, amount), + ManagedCoinRegister { coin_type } => managed_coin_register(coin_type), + MultisigAccountAddOwner { new_owner } => multisig_account_add_owner(new_owner), + MultisigAccountAddOwners { new_owners } => multisig_account_add_owners(new_owners), + MultisigAccountAddOwnersAndUpdateSignaturesRequired { + new_owners, + new_num_signatures_required, + } => multisig_account_add_owners_and_update_signatures_required( + new_owners, + new_num_signatures_required, + ), + 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, + ), + MultisigAccountCreateWithExistingAccountAndRevokeAuthKey { + 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_and_revoke_auth_key( + 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, + ), + MultisigAccountCreateWithOwnersThenRemoveBootstrapper { + owners, + num_signatures_required, + metadata_keys, + metadata_values, + } => multisig_account_create_with_owners_then_remove_bootstrapper( + owners, + num_signatures_required, + metadata_keys, + metadata_values, + ), + MultisigAccountExecuteRejectedTransaction { multisig_account } => { + multisig_account_execute_rejected_transaction(multisig_account) + }, + MultisigAccountExecuteRejectedTransactions { + multisig_account, + final_sequence_number, + } => multisig_account_execute_rejected_transactions( + multisig_account, + final_sequence_number, + ), + 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) + }, + MultisigAccountSwapOwner { + to_swap_in, + to_swap_out, + } => multisig_account_swap_owner(to_swap_in, to_swap_out), + MultisigAccountSwapOwners { + to_swap_in, + to_swap_out, + } => multisig_account_swap_owners(to_swap_in, to_swap_out), + MultisigAccountSwapOwnersAndUpdateSignaturesRequired { + new_owners, + owners_to_remove, + new_num_signatures_required, + } => multisig_account_swap_owners_and_update_signatures_required( + new_owners, + owners_to_remove, + new_num_signatures_required, + ), + MultisigAccountUpdateMetadata { keys, values } => { + multisig_account_update_metadata(keys, values) + }, + MultisigAccountUpdateSignaturesRequired { + new_num_signatures_required, + } => multisig_account_update_signatures_required(new_num_signatures_required), + MultisigAccountVoteTransaction { + multisig_account, + sequence_number, + approved, + } => multisig_account_vote_transaction(multisig_account, sequence_number, approved), + MultisigAccountVoteTransactions { + multisig_account, + starting_sequence_number, + final_sequence_number, + approved, + } => multisig_account_vote_transactions( + multisig_account, + starting_sequence_number, + final_sequence_number, + approved, + ), + MultisigAccountVoteTransanction { + multisig_account, + sequence_number, + approved, + } => multisig_account_vote_transanction(multisig_account, sequence_number, approved), + ObjectTransferCall { object, to } => object_transfer_call(object, to), + ObjectCodeDeploymentPublish { + metadata_serialized, + code, + } => object_code_deployment_publish(metadata_serialized, code), + ResourceAccountCreateResourceAccount { + seed, + optional_auth_key, + } => resource_account_create_resource_account(seed, optional_auth_key), + ResourceAccountCreateResourceAccountAndFund { + seed, + optional_auth_key, + fund_amount, + } => resource_account_create_resource_account_and_fund( + seed, + optional_auth_key, + fund_amount, + ), + ResourceAccountCreateResourceAccountAndPublishPackage { + seed, + metadata_serialized, + code, + } => resource_account_create_resource_account_and_publish_package( + seed, + metadata_serialized, + code, + ), + StakeAddStake { amount } => stake_add_stake(amount), + StakeIncreaseLockup {} => stake_increase_lockup(), + StakeInitializeStakeOwner { + initial_stake_amount, + operator, + voter, + } => stake_initialize_stake_owner(initial_stake_amount, operator, voter), + StakeInitializeValidator { + consensus_pubkey, + proof_of_possession, + network_addresses, + fullnode_addresses, + } => stake_initialize_validator( + consensus_pubkey, + proof_of_possession, + network_addresses, + fullnode_addresses, + ), + StakeJoinValidatorSet { pool_address } => stake_join_validator_set(pool_address), + StakeLeaveValidatorSet { pool_address } => stake_leave_validator_set(pool_address), + StakeReactivateStake { amount } => stake_reactivate_stake(amount), + StakeRotateConsensusKey { + pool_address, + new_consensus_pubkey, + proof_of_possession, + } => { + stake_rotate_consensus_key(pool_address, new_consensus_pubkey, proof_of_possession) + }, + StakeSetDelegatedVoter { new_voter } => stake_set_delegated_voter(new_voter), + StakeSetOperator { new_operator } => stake_set_operator(new_operator), + StakeUnlock { amount } => stake_unlock(amount), + StakeUpdateNetworkAndFullnodeAddresses { + pool_address, + new_network_addresses, + new_fullnode_addresses, + } => stake_update_network_and_fullnode_addresses( + pool_address, + new_network_addresses, + new_fullnode_addresses, + ), + StakeWithdraw { withdraw_amount } => stake_withdraw(withdraw_amount), + StakingContractAddStake { operator, amount } => { + staking_contract_add_stake(operator, amount) + }, + StakingContractCreateStakingContract { + operator, + voter, + amount, + commission_percentage, + contract_creation_seed, + } => staking_contract_create_staking_contract( + operator, + voter, + amount, + commission_percentage, + contract_creation_seed, + ), + StakingContractDistribute { staker, operator } => { + staking_contract_distribute(staker, operator) + }, + StakingContractRequestCommission { staker, operator } => { + staking_contract_request_commission(staker, operator) + }, + StakingContractResetLockup { operator } => staking_contract_reset_lockup(operator), + StakingContractSetBeneficiaryForOperator { new_beneficiary } => { + staking_contract_set_beneficiary_for_operator(new_beneficiary) + }, + StakingContractSwitchOperator { + old_operator, + new_operator, + new_commission_percentage, + } => staking_contract_switch_operator( + old_operator, + new_operator, + new_commission_percentage, + ), + StakingContractSwitchOperatorWithSameCommission { + old_operator, + new_operator, + } => staking_contract_switch_operator_with_same_commission(old_operator, new_operator), + StakingContractUnlockRewards { operator } => staking_contract_unlock_rewards(operator), + StakingContractUnlockStake { operator, amount } => { + staking_contract_unlock_stake(operator, amount) + }, + StakingContractUpdateCommision { + operator, + new_commission_percentage, + } => staking_contract_update_commision(operator, new_commission_percentage), + StakingContractUpdateVoter { + operator, + new_voter, + } => staking_contract_update_voter(operator, new_voter), + StakingProxySetOperator { + old_operator, + new_operator, + } => staking_proxy_set_operator(old_operator, new_operator), + StakingProxySetStakePoolOperator { new_operator } => { + staking_proxy_set_stake_pool_operator(new_operator) + }, + StakingProxySetStakePoolVoter { new_voter } => { + staking_proxy_set_stake_pool_voter(new_voter) + }, + StakingProxySetStakingContractOperator { + old_operator, + new_operator, + } => staking_proxy_set_staking_contract_operator(old_operator, new_operator), + StakingProxySetStakingContractVoter { + operator, + new_voter, + } => staking_proxy_set_staking_contract_voter(operator, new_voter), + StakingProxySetVestingContractOperator { + old_operator, + new_operator, + } => staking_proxy_set_vesting_contract_operator(old_operator, new_operator), + StakingProxySetVestingContractVoter { + operator, + new_voter, + } => staking_proxy_set_vesting_contract_voter(operator, new_voter), + StakingProxySetVoter { + operator, + new_voter, + } => staking_proxy_set_voter(operator, new_voter), + TransactionFeeConvertToAptosFaBurnRef {} => { + transaction_fee_convert_to_aptos_fa_burn_ref() + }, + VersionSetForNextEpoch { major } => version_set_for_next_epoch(major), + VersionSetVersion { major } => version_set_version(major), + VestingAdminWithdraw { contract_address } => vesting_admin_withdraw(contract_address), + VestingDistribute { contract_address } => vesting_distribute(contract_address), + VestingDistributeMany { contract_addresses } => { + vesting_distribute_many(contract_addresses) + }, + VestingResetBeneficiary { + contract_address, + shareholder, + } => vesting_reset_beneficiary(contract_address, shareholder), + VestingResetLockup { contract_address } => vesting_reset_lockup(contract_address), + VestingSetBeneficiary { + contract_address, + shareholder, + new_beneficiary, + } => vesting_set_beneficiary(contract_address, shareholder, new_beneficiary), + VestingSetBeneficiaryForOperator { new_beneficiary } => { + vesting_set_beneficiary_for_operator(new_beneficiary) + }, + VestingSetBeneficiaryResetter { + contract_address, + beneficiary_resetter, + } => vesting_set_beneficiary_resetter(contract_address, beneficiary_resetter), + VestingSetManagementRole { + contract_address, + role, + role_holder, + } => vesting_set_management_role(contract_address, role, role_holder), + VestingTerminateVestingContract { contract_address } => { + vesting_terminate_vesting_contract(contract_address) + }, + VestingUnlockRewards { contract_address } => vesting_unlock_rewards(contract_address), + VestingUnlockRewardsMany { contract_addresses } => { + vesting_unlock_rewards_many(contract_addresses) + }, + VestingUpdateCommissionPercentage { + contract_address, + new_commission_percentage, + } => vesting_update_commission_percentage(contract_address, new_commission_percentage), + VestingUpdateOperator { + contract_address, + new_operator, + commission_percentage, + } => vesting_update_operator(contract_address, new_operator, commission_percentage), + VestingUpdateOperatorWithSameCommission { + contract_address, + new_operator, + } => vesting_update_operator_with_same_commission(contract_address, new_operator), + VestingUpdateVoter { + contract_address, + new_voter, + } => vesting_update_voter(contract_address, new_voter), + VestingVest { contract_address } => vesting_vest(contract_address), + VestingVestMany { contract_addresses } => vesting_vest_many(contract_addresses), + } + } + + /// Try to recognize an Aptos `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(), + ], + )) +} + +/// Private entry function for key rotation that allows the signer to update their authentication key. +/// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it +/// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to +/// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in +/// the format expected in `rotate_authentication_key`. +pub fn account_rotate_authentication_key_call(new_auth_key: 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_call").to_owned(), + vec![], + vec![bcs::to_bytes(&new_auth_key).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(), + ], + )) +} + +/// Batch version of APT transfer. +pub fn aptos_account_batch_transfer( + recipients: Vec, + amounts: 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!("aptos_account").to_owned(), + ), + ident_str!("batch_transfer").to_owned(), + vec![], + vec![ + bcs::to_bytes(&recipients).unwrap(), + bcs::to_bytes(&amounts).unwrap(), + ], + )) +} + +/// Batch version of transfer_coins. +pub fn aptos_account_batch_transfer_coins( + coin_type: TypeTag, + recipients: Vec, + amounts: 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!("aptos_account").to_owned(), + ), + ident_str!("batch_transfer_coins").to_owned(), + vec![coin_type], + vec![ + bcs::to_bytes(&recipients).unwrap(), + bcs::to_bytes(&amounts).unwrap(), + ], + )) +} + +/// Basic account creation methods. +pub fn aptos_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!("aptos_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 aptos_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!("aptos_account").to_owned(), + ), + ident_str!("set_allow_direct_coin_transfers").to_owned(), + vec![], + vec![bcs::to_bytes(&allow).unwrap()], + )) +} + +/// Convenient function to transfer APT to a recipient account that might not exist. +/// This would create the recipient account first, which also registers it to receive APT, before transferring. +pub fn aptos_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!("aptos_account").to_owned(), + ), + ident_str!("transfer").to_owned(), + vec![], + vec![bcs::to_bytes(&to).unwrap(), bcs::to_bytes(&amount).unwrap()], + )) +} + +/// Convenient function to transfer a custom CoinType to a recipient account that might not exist. +/// This would create the recipient account first and register it to receive the CoinType, before transferring. +pub fn aptos_account_transfer_coins( + 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!("aptos_account").to_owned(), + ), + ident_str!("transfer_coins").to_owned(), + vec![coin_type], + vec![bcs::to_bytes(&to).unwrap(), bcs::to_bytes(&amount).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 aptos_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!("aptos_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 aptos_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!("aptos_coin").to_owned(), + ), + ident_str!("delegate_mint_capability").to_owned(), + vec![], + vec![bcs::to_bytes(&to).unwrap()], + )) +} + +/// Only callable in tests and testnets where the core resources account exists. +/// Create new coins and deposit them into dst_addr's account. +pub fn aptos_coin_mint(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!("aptos_coin").to_owned(), + ), + ident_str!("mint").to_owned(), + vec![], + vec![ + bcs::to_bytes(&dst_addr).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +pub fn aptos_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!("aptos_governance").to_owned(), + ), + ident_str!("add_approved_script_hash_script").to_owned(), + vec![], + vec![bcs::to_bytes(&proposal_id).unwrap()], + )) +} + +/// Batch vote on proposal with proposal_id and specified voting power from multiple stake_pools. +pub fn aptos_governance_batch_partial_vote( + stake_pools: Vec, + proposal_id: u64, + voting_power: 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!("aptos_governance").to_owned(), + ), + ident_str!("batch_partial_vote").to_owned(), + vec![], + vec![ + bcs::to_bytes(&stake_pools).unwrap(), + bcs::to_bytes(&proposal_id).unwrap(), + bcs::to_bytes(&voting_power).unwrap(), + bcs::to_bytes(&should_pass).unwrap(), + ], + )) +} + +/// Vote on proposal with proposal_id and all voting power from multiple stake_pools. +pub fn aptos_governance_batch_vote( + stake_pools: Vec, + 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!("aptos_governance").to_owned(), + ), + ident_str!("batch_vote").to_owned(), + vec![], + vec![ + bcs::to_bytes(&stake_pools).unwrap(), + bcs::to_bytes(&proposal_id).unwrap(), + bcs::to_bytes(&should_pass).unwrap(), + ], + )) +} + +/// Create a single-step proposal with the backing `stake_pool`. +/// @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 aptos_governance_create_proposal( + stake_pool: AccountAddress, + execution_hash: Vec, + metadata_location: Vec, + metadata_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!("aptos_governance").to_owned(), + ), + ident_str!("create_proposal").to_owned(), + vec![], + vec![ + bcs::to_bytes(&stake_pool).unwrap(), + bcs::to_bytes(&execution_hash).unwrap(), + bcs::to_bytes(&metadata_location).unwrap(), + bcs::to_bytes(&metadata_hash).unwrap(), + ], + )) +} + +/// Create a single-step or multi-step proposal with the backing `stake_pool`. +/// @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 aptos_governance_create_proposal_v2( + stake_pool: AccountAddress, + 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!("aptos_governance").to_owned(), + ), + ident_str!("create_proposal_v2").to_owned(), + vec![], + vec![ + bcs::to_bytes(&stake_pool).unwrap(), + 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(), + ], + )) +} + +/// Change epoch immediately. +/// If `RECONFIGURE_WITH_DKG` is enabled and we are in the middle of a DKG, +/// stop waiting for DKG and enter the new epoch without randomness. +/// +/// WARNING: currently only used by tests. In most cases you should use `reconfigure()` instead. +/// TODO: migrate these tests to be aware of async reconfiguration. +pub fn aptos_governance_force_end_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!("aptos_governance").to_owned(), + ), + ident_str!("force_end_epoch").to_owned(), + vec![], + vec![], + )) +} + +/// `force_end_epoch()` equivalent but only called in testnet, +/// where the core resources account exists and has been granted power to mint Aptos coins. +pub fn aptos_governance_force_end_epoch_test_only() -> 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!("aptos_governance").to_owned(), + ), + ident_str!("force_end_epoch_test_only").to_owned(), + vec![], + vec![], + )) +} + +/// Vote on proposal with `proposal_id` and specified voting power from `stake_pool`. +pub fn aptos_governance_partial_vote( + stake_pool: AccountAddress, + proposal_id: u64, + voting_power: 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!("aptos_governance").to_owned(), + ), + ident_str!("partial_vote").to_owned(), + vec![], + vec![ + bcs::to_bytes(&stake_pool).unwrap(), + bcs::to_bytes(&proposal_id).unwrap(), + bcs::to_bytes(&voting_power).unwrap(), + bcs::to_bytes(&should_pass).unwrap(), + ], + )) +} + +/// Manually reconfigure. Called at the end of a governance txn that alters on-chain configs. +/// +/// WARNING: this function always ensures a reconfiguration starts, but when the reconfiguration finishes depends. +/// - If feature `RECONFIGURE_WITH_DKG` is disabled, it finishes immediately. +/// - At the end of the calling transaction, we will be in a new epoch. +/// - If feature `RECONFIGURE_WITH_DKG` is enabled, it starts DKG, and the new epoch will start in a block prologue after DKG finishes. +/// +/// This behavior affects when an update of an on-chain config (e.g. `ConsensusConfig`, `Features`) takes effect, +/// since such updates are applied whenever we enter an new epoch. +pub fn aptos_governance_reconfigure() -> 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!("aptos_governance").to_owned(), + ), + ident_str!("reconfigure").to_owned(), + vec![], + vec![], + )) +} + +/// Vote on proposal with `proposal_id` and all voting power from `stake_pool`. +pub fn aptos_governance_vote( + stake_pool: AccountAddress, + 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!("aptos_governance").to_owned(), + ), + ident_str!("vote").to_owned(), + vec![], + vec![ + bcs::to_bytes(&stake_pool).unwrap(), + bcs::to_bytes(&proposal_id).unwrap(), + bcs::to_bytes(&should_pass).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(), + ], + )) +} + +pub fn coin_create_coin_conversion_map() -> 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!("create_coin_conversion_map").to_owned(), + vec![], + vec![], + )) +} + +/// Create APT pairing by passing `AptosCoin`. +pub fn coin_create_pairing(coin_type: TypeTag) -> 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!("create_pairing").to_owned(), + vec![coin_type], + vec![], + )) +} + +/// Voluntarily migrate to fungible store for `CoinType` if not yet. +pub fn coin_migrate_to_fungible_store(coin_type: TypeTag) -> 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!("migrate_to_fungible_store").to_owned(), + vec![coin_type], + vec![], + )) +} + +/// 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()], + )) +} + +/// Upgrade total supply to use a parallelizable implementation if it is +/// available. +pub fn coin_upgrade_supply(coin_type: TypeTag) -> 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!("upgrade_supply").to_owned(), + vec![coin_type], + vec![], + )) +} + +/// Add `amount` of coins to the delegation pool `pool_address`. +pub fn delegation_pool_add_stake(pool_address: 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!("delegation_pool").to_owned(), + ), + ident_str!("add_stake").to_owned(), + vec![], + vec![ + bcs::to_bytes(&pool_address).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Allowlist a delegator as the pool owner. +pub fn delegation_pool_allowlist_delegator( + delegator_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!("delegation_pool").to_owned(), + ), + ident_str!("allowlist_delegator").to_owned(), + vec![], + vec![bcs::to_bytes(&delegator_address).unwrap()], + )) +} + +/// A voter could create a governance proposal by this function. To successfully create a proposal, the voter's +/// voting power in THIS delegation pool must be not less than the minimum required voting power specified in +/// `aptos_governance.move`. +pub fn delegation_pool_create_proposal( + pool_address: AccountAddress, + 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!("delegation_pool").to_owned(), + ), + ident_str!("create_proposal").to_owned(), + vec![], + vec![ + bcs::to_bytes(&pool_address).unwrap(), + 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(), + ], + )) +} + +/// Allows a delegator to delegate its voting power to a voter. If this delegator already has a delegated voter, +/// this change won't take effects until the next lockup period. +pub fn delegation_pool_delegate_voting_power( + pool_address: AccountAddress, + new_voter: 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!("delegation_pool").to_owned(), + ), + ident_str!("delegate_voting_power").to_owned(), + vec![], + vec![ + bcs::to_bytes(&pool_address).unwrap(), + bcs::to_bytes(&new_voter).unwrap(), + ], + )) +} + +/// Disable delegators allowlisting as the pool owner. The existing allowlist will be emptied. +pub fn delegation_pool_disable_delegators_allowlisting() -> 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!("delegation_pool").to_owned(), + ), + ident_str!("disable_delegators_allowlisting").to_owned(), + vec![], + vec![], + )) +} + +/// Enable delegators allowlisting as the pool owner. +pub fn delegation_pool_enable_delegators_allowlisting() -> 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!("delegation_pool").to_owned(), + ), + ident_str!("enable_delegators_allowlisting").to_owned(), + vec![], + vec![], + )) +} + +/// Enable partial governance voting on a stake pool. The voter of this stake pool will be managed by this module. +/// The existing voter will be replaced. The function is permissionless. +pub fn delegation_pool_enable_partial_governance_voting( + pool_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!("delegation_pool").to_owned(), + ), + ident_str!("enable_partial_governance_voting").to_owned(), + vec![], + vec![bcs::to_bytes(&pool_address).unwrap()], + )) +} + +/// Evict a delegator that is not allowlisted by unlocking their entire stake. +pub fn delegation_pool_evict_delegator(delegator_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!("delegation_pool").to_owned(), + ), + ident_str!("evict_delegator").to_owned(), + vec![], + vec![bcs::to_bytes(&delegator_address).unwrap()], + )) +} + +/// Initialize a delegation pool of custom fixed `operator_commission_percentage`. +/// A resource account is created from `owner` signer and its supplied `delegation_pool_creation_seed` +/// to host the delegation pool resource and own the underlying stake pool. +/// Ownership over setting the operator/voter is granted to `owner` who has both roles initially. +pub fn delegation_pool_initialize_delegation_pool( + operator_commission_percentage: u64, + delegation_pool_creation_seed: 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!("delegation_pool").to_owned(), + ), + ident_str!("initialize_delegation_pool").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator_commission_percentage).unwrap(), + bcs::to_bytes(&delegation_pool_creation_seed).unwrap(), + ], + )) +} + +/// Move `amount` of coins from pending_inactive to active. +pub fn delegation_pool_reactivate_stake( + pool_address: 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!("delegation_pool").to_owned(), + ), + ident_str!("reactivate_stake").to_owned(), + vec![], + vec![ + bcs::to_bytes(&pool_address).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Remove a delegator from the allowlist as the pool owner, but do not unlock their stake. +pub fn delegation_pool_remove_delegator_from_allowlist( + delegator_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!("delegation_pool").to_owned(), + ), + ident_str!("remove_delegator_from_allowlist").to_owned(), + vec![], + vec![bcs::to_bytes(&delegator_address).unwrap()], + )) +} + +/// Allows an operator to change its beneficiary. Any existing unpaid commission rewards will be paid to the new +/// beneficiary. To ensure payment to the current beneficiary, one should first call `synchronize_delegation_pool` +/// before switching the beneficiary. An operator can set one beneficiary for delegation pools, not a separate +/// one for each pool. +pub fn delegation_pool_set_beneficiary_for_operator( + new_beneficiary: 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!("delegation_pool").to_owned(), + ), + ident_str!("set_beneficiary_for_operator").to_owned(), + vec![], + vec![bcs::to_bytes(&new_beneficiary).unwrap()], + )) +} + +/// Allows an owner to change the delegated voter of the underlying stake pool. +pub fn delegation_pool_set_delegated_voter(new_voter: 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!("delegation_pool").to_owned(), + ), + ident_str!("set_delegated_voter").to_owned(), + vec![], + vec![bcs::to_bytes(&new_voter).unwrap()], + )) +} + +/// Allows an owner to change the operator of the underlying stake pool. +pub fn delegation_pool_set_operator(new_operator: 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!("delegation_pool").to_owned(), + ), + ident_str!("set_operator").to_owned(), + vec![], + vec![bcs::to_bytes(&new_operator).unwrap()], + )) +} + +/// Synchronize delegation and stake pools: distribute yet-undetected rewards to the corresponding internal +/// shares pools, assign commission to operator and eventually prepare delegation pool for a new lockup cycle. +pub fn delegation_pool_synchronize_delegation_pool( + pool_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!("delegation_pool").to_owned(), + ), + ident_str!("synchronize_delegation_pool").to_owned(), + vec![], + vec![bcs::to_bytes(&pool_address).unwrap()], + )) +} + +/// Unlock `amount` from the active + pending_active stake of `delegator` or +/// at most how much active stake there is on the stake pool. +pub fn delegation_pool_unlock(pool_address: 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!("delegation_pool").to_owned(), + ), + ident_str!("unlock").to_owned(), + vec![], + vec![ + bcs::to_bytes(&pool_address).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Allows an owner to update the commission percentage for the operator of the underlying stake pool. +pub fn delegation_pool_update_commission_percentage( + new_commission_percentage: 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!("delegation_pool").to_owned(), + ), + ident_str!("update_commission_percentage").to_owned(), + vec![], + vec![bcs::to_bytes(&new_commission_percentage).unwrap()], + )) +} + +/// Vote on a proposal with a voter's voting power. To successfully vote, the following conditions must be met: +/// 1. The voting period of the proposal hasn't ended. +/// 2. The delegation pool's lockup period ends after the voting period of the proposal. +/// 3. The voter still has spare voting power on this proposal. +/// 4. The delegation pool never votes on the proposal before enabling partial governance voting. +pub fn delegation_pool_vote( + pool_address: AccountAddress, + proposal_id: u64, + voting_power: 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!("delegation_pool").to_owned(), + ), + ident_str!("vote").to_owned(), + vec![], + vec![ + bcs::to_bytes(&pool_address).unwrap(), + bcs::to_bytes(&proposal_id).unwrap(), + bcs::to_bytes(&voting_power).unwrap(), + bcs::to_bytes(&should_pass).unwrap(), + ], + )) +} + +/// Withdraw `amount` of owned inactive stake from the delegation pool at `pool_address`. +pub fn delegation_pool_withdraw(pool_address: 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!("delegation_pool").to_owned(), + ), + ident_str!("withdraw").to_owned(), + vec![], + vec![ + bcs::to_bytes(&pool_address).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Withdraw an `amount` of coin `CoinType` from `account` and burn it. +pub fn managed_coin_burn(coin_type: TypeTag, 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!("managed_coin").to_owned(), + ), + ident_str!("burn").to_owned(), + vec![coin_type], + vec![bcs::to_bytes(&amount).unwrap()], + )) +} + +/// Initialize new coin `CoinType` in Aptos Blockchain. +/// Mint and Burn Capabilities will be stored under `account` in `Capabilities` resource. +pub fn managed_coin_initialize( + coin_type: TypeTag, + name: Vec, + symbol: Vec, + decimals: u8, + monitor_supply: 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!("managed_coin").to_owned(), + ), + ident_str!("initialize").to_owned(), + vec![coin_type], + vec![ + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&symbol).unwrap(), + bcs::to_bytes(&decimals).unwrap(), + bcs::to_bytes(&monitor_supply).unwrap(), + ], + )) +} + +/// Create new coins `CoinType` and deposit them into dst_addr's account. +pub fn managed_coin_mint( + coin_type: TypeTag, + 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!("managed_coin").to_owned(), + ), + ident_str!("mint").to_owned(), + vec![coin_type], + vec![ + bcs::to_bytes(&dst_addr).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Creating a resource that stores balance of `CoinType` on user's account, withdraw and deposit event handlers. +/// Required if user wants to start accepting deposits of `CoinType` in his account. +pub fn managed_coin_register(coin_type: TypeTag) -> 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!("managed_coin").to_owned(), + ), + ident_str!("register").to_owned(), + vec![coin_type], + vec![], + )) +} + +/// 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()], + )) +} + +/// Add owners then update number of signatures required, in a single operation. +pub fn multisig_account_add_owners_and_update_signatures_required( + new_owners: Vec, + 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!("add_owners_and_update_signatures_required").to_owned(), + vec![], + vec![ + bcs::to_bytes(&new_owners).unwrap(), + bcs::to_bytes(&new_num_signatures_required).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). +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. +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. +/// +/// Note that this does not revoke auth key-based control over the account. Owners should separately rotate the auth +/// key after they are fully migrated to the new multisig account. Alternatively, they can call +/// create_with_existing_account_and_revoke_auth_key instead. +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 on top of an existing account and immediately rotate the origin auth key to 0x0. +/// +/// Note: If the original account is a resource account, this does not revoke all control over it as if any +/// SignerCapability of the resource account still exists, it can still be used to generate the signer for the +/// account. +pub fn multisig_account_create_with_existing_account_and_revoke_auth_key( + 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_and_revoke_auth_key").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(), + ], + )) +} + +/// Like `create_with_owners`, but removes the calling account after creation. +/// +/// This is for creating a vanity multisig account from a bootstrapping account that should not +/// be an owner after the vanity multisig address has been secured. +pub fn multisig_account_create_with_owners_then_remove_bootstrapper( + 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_then_remove_bootstrapper").to_owned(), + vec![], + vec![ + bcs::to_bytes(&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()], + )) +} + +/// Remove the next transactions until the final_sequence_number if they have sufficient owner rejections. +pub fn multisig_account_execute_rejected_transactions( + multisig_account: AccountAddress, + final_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!("execute_rejected_transactions").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&final_sequence_number).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()], + )) +} + +/// Swap an owner in for an old one, without changing required signatures. +pub fn multisig_account_swap_owner( + to_swap_in: AccountAddress, + to_swap_out: 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!("swap_owner").to_owned(), + vec![], + vec![ + bcs::to_bytes(&to_swap_in).unwrap(), + bcs::to_bytes(&to_swap_out).unwrap(), + ], + )) +} + +/// Swap owners in and out, without changing required signatures. +pub fn multisig_account_swap_owners( + to_swap_in: Vec, + to_swap_out: 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!("swap_owners").to_owned(), + vec![], + vec![ + bcs::to_bytes(&to_swap_in).unwrap(), + bcs::to_bytes(&to_swap_out).unwrap(), + ], + )) +} + +/// Swap owners in and out, updating number of required signatures. +pub fn multisig_account_swap_owners_and_update_signatures_required( + new_owners: Vec, + owners_to_remove: Vec, + 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!("swap_owners_and_update_signatures_required").to_owned(), + vec![], + vec![ + bcs::to_bytes(&new_owners).unwrap(), + bcs::to_bytes(&owners_to_remove).unwrap(), + bcs::to_bytes(&new_num_signatures_required).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_transaction( + 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_transaction").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&sequence_number).unwrap(), + bcs::to_bytes(&approved).unwrap(), + ], + )) +} + +/// Generic function that can be used to either approve or reject a batch of transactions within a specified range. +pub fn multisig_account_vote_transactions( + multisig_account: AccountAddress, + starting_sequence_number: u64, + final_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_transactions").to_owned(), + vec![], + vec![ + bcs::to_bytes(&multisig_account).unwrap(), + bcs::to_bytes(&starting_sequence_number).unwrap(), + bcs::to_bytes(&final_sequence_number).unwrap(), + bcs::to_bytes(&approved).unwrap(), + ], + )) +} + +/// Generic function that can be used to either approve or reject a multisig transaction +/// Retained for backward compatibility: the function with the typographical error in its name +/// will continue to be an accessible entry point. +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()], + )) +} + +/// Creates a new object with a unique address derived from the publisher address and the object seed. +/// Publishes the code passed in the function to the newly created object. +/// The caller must provide package metadata describing the package via `metadata_serialized` and +/// the code to be published via `code`. This contains a vector of modules to be deployed on-chain. +pub fn object_code_deployment_publish( + 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!("object_code_deployment").to_owned(), + ), + ident_str!("publish").to_owned(), + vec![], + vec![ + bcs::to_bytes(&metadata_serialized).unwrap(), + bcs::to_bytes(&code).unwrap(), + ], + )) +} + +/// Creates a new resource account and rotates the authentication key to either +/// the optional auth key if it is non-empty (though auth keys are 32-bytes) +/// or the source accounts current auth key. +pub fn resource_account_create_resource_account( + seed: Vec, + optional_auth_key: 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!("resource_account").to_owned(), + ), + ident_str!("create_resource_account").to_owned(), + vec![], + vec![ + bcs::to_bytes(&seed).unwrap(), + bcs::to_bytes(&optional_auth_key).unwrap(), + ], + )) +} + +/// Creates a new resource account, transfer the amount of coins from the origin to the resource +/// account, and rotates the authentication key to either the optional auth key if it is +/// non-empty (though auth keys are 32-bytes) or the source accounts current auth key. Note, +/// this function adds additional resource ownership to the resource account and should only be +/// used for resource accounts that need access to `Coin`. +pub fn resource_account_create_resource_account_and_fund( + seed: Vec, + optional_auth_key: Vec, + fund_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!("resource_account").to_owned(), + ), + ident_str!("create_resource_account_and_fund").to_owned(), + vec![], + vec![ + bcs::to_bytes(&seed).unwrap(), + bcs::to_bytes(&optional_auth_key).unwrap(), + bcs::to_bytes(&fund_amount).unwrap(), + ], + )) +} + +/// Creates a new resource account, publishes the package under this account transaction under +/// this account and leaves the signer cap readily available for pickup. +pub fn resource_account_create_resource_account_and_publish_package( + seed: Vec, + 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!("resource_account").to_owned(), + ), + ident_str!("create_resource_account_and_publish_package").to_owned(), + vec![], + vec![ + bcs::to_bytes(&seed).unwrap(), + bcs::to_bytes(&metadata_serialized).unwrap(), + bcs::to_bytes(&code).unwrap(), + ], + )) +} + +/// Add `amount` of coins from the `account` owning the StakePool. +pub fn stake_add_stake(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!("stake").to_owned(), + ), + ident_str!("add_stake").to_owned(), + vec![], + vec![bcs::to_bytes(&amount).unwrap()], + )) +} + +/// Similar to increase_lockup_with_cap but will use ownership capability from the signing account. +pub fn stake_increase_lockup() -> 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!("increase_lockup").to_owned(), + vec![], + vec![], + )) +} + +/// Initialize the validator account and give ownership to the signing account +/// except it leaves the ValidatorConfig to be set by another entity. +/// Note: this triggers setting the operator and owner, set it to the account's address +/// to set later. +pub fn stake_initialize_stake_owner( + initial_stake_amount: u64, + operator: AccountAddress, + voter: 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!("stake").to_owned(), + ), + ident_str!("initialize_stake_owner").to_owned(), + vec![], + vec![ + bcs::to_bytes(&initial_stake_amount).unwrap(), + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&voter).unwrap(), + ], + )) +} + +/// 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(), + ], + )) +} + +/// This can only called by the operator of the validator/staking pool. +pub fn stake_join_validator_set(pool_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!("stake").to_owned(), + ), + ident_str!("join_validator_set").to_owned(), + vec![], + vec![bcs::to_bytes(&pool_address).unwrap()], + )) +} + +/// Request to have `pool_address` leave the validator set. The validator is only actually removed from the set when +/// the next epoch starts. +/// The last validator in the set cannot leave. This is an edge case that should never happen as long as the network +/// is still operational. +/// +/// Can only be called by the operator of the validator/staking pool. +pub fn stake_leave_validator_set(pool_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!("stake").to_owned(), + ), + ident_str!("leave_validator_set").to_owned(), + vec![], + vec![bcs::to_bytes(&pool_address).unwrap()], + )) +} + +/// Move `amount` of coins from pending_inactive to active. +pub fn stake_reactivate_stake(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!("stake").to_owned(), + ), + ident_str!("reactivate_stake").to_owned(), + vec![], + vec![bcs::to_bytes(&amount).unwrap()], + )) +} + +/// Rotate the consensus key of the validator, it'll take effect in next epoch. +pub fn stake_rotate_consensus_key( + pool_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(&pool_address).unwrap(), + bcs::to_bytes(&new_consensus_pubkey).unwrap(), + bcs::to_bytes(&proof_of_possession).unwrap(), + ], + )) +} + +/// Allows an owner to change the delegated voter of the stake pool. +pub fn stake_set_delegated_voter(new_voter: 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!("stake").to_owned(), + ), + ident_str!("set_delegated_voter").to_owned(), + vec![], + vec![bcs::to_bytes(&new_voter).unwrap()], + )) +} + +/// Allows an owner to change the operator of the stake pool. +pub fn stake_set_operator(new_operator: 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!("stake").to_owned(), + ), + ident_str!("set_operator").to_owned(), + vec![], + vec![bcs::to_bytes(&new_operator).unwrap()], + )) +} + +/// Similar to unlock_with_cap but will use ownership capability from the signing account. +pub fn stake_unlock(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!("stake").to_owned(), + ), + ident_str!("unlock").to_owned(), + vec![], + vec![bcs::to_bytes(&amount).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( + pool_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(&pool_address).unwrap(), + bcs::to_bytes(&new_network_addresses).unwrap(), + bcs::to_bytes(&new_fullnode_addresses).unwrap(), + ], + )) +} + +/// Withdraw from `account`'s inactive stake. +pub fn stake_withdraw(withdraw_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!("stake").to_owned(), + ), + ident_str!("withdraw").to_owned(), + vec![], + vec![bcs::to_bytes(&withdraw_amount).unwrap()], + )) +} + +/// Add more stake to an existing staking contract. +pub fn staking_contract_add_stake(operator: 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!("staking_contract").to_owned(), + ), + ident_str!("add_stake").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Staker can call this function to create a simple staking contract with a specified operator. +pub fn staking_contract_create_staking_contract( + operator: AccountAddress, + voter: AccountAddress, + amount: u64, + commission_percentage: u64, + contract_creation_seed: 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!("staking_contract").to_owned(), + ), + ident_str!("create_staking_contract").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&voter).unwrap(), + bcs::to_bytes(&amount).unwrap(), + bcs::to_bytes(&commission_percentage).unwrap(), + bcs::to_bytes(&contract_creation_seed).unwrap(), + ], + )) +} + +/// Allow anyone to distribute already unlocked funds. This does not affect reward compounding and therefore does +/// not need to be restricted to just the staker or operator. +pub fn staking_contract_distribute( + staker: AccountAddress, + operator: 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!("staking_contract").to_owned(), + ), + ident_str!("distribute").to_owned(), + vec![], + vec![ + bcs::to_bytes(&staker).unwrap(), + bcs::to_bytes(&operator).unwrap(), + ], + )) +} + +/// Unlock commission amount from the stake pool. Operator needs to wait for the amount to become withdrawable +/// at the end of the stake pool's lockup period before they can actually can withdraw_commission. +/// +/// Only staker, operator or beneficiary can call this. +pub fn staking_contract_request_commission( + staker: AccountAddress, + operator: 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!("staking_contract").to_owned(), + ), + ident_str!("request_commission").to_owned(), + vec![], + vec![ + bcs::to_bytes(&staker).unwrap(), + bcs::to_bytes(&operator).unwrap(), + ], + )) +} + +/// Convenient function to allow the staker to reset their stake pool's lockup period to start now. +pub fn staking_contract_reset_lockup(operator: 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!("staking_contract").to_owned(), + ), + ident_str!("reset_lockup").to_owned(), + vec![], + vec![bcs::to_bytes(&operator).unwrap()], + )) +} + +/// Allows an operator to change its beneficiary. Any existing unpaid commission rewards will be paid to the new +/// beneficiary. To ensures payment to the current beneficiary, one should first call `distribute` before switching +/// the beneficiary. An operator can set one beneficiary for staking contract pools, not a separate one for each pool. +pub fn staking_contract_set_beneficiary_for_operator( + new_beneficiary: 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!("staking_contract").to_owned(), + ), + ident_str!("set_beneficiary_for_operator").to_owned(), + vec![], + vec![bcs::to_bytes(&new_beneficiary).unwrap()], + )) +} + +/// Allows staker to switch operator without going through the lenghthy process to unstake. +pub fn staking_contract_switch_operator( + old_operator: AccountAddress, + new_operator: AccountAddress, + new_commission_percentage: 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!("staking_contract").to_owned(), + ), + ident_str!("switch_operator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&old_operator).unwrap(), + bcs::to_bytes(&new_operator).unwrap(), + bcs::to_bytes(&new_commission_percentage).unwrap(), + ], + )) +} + +/// Allows staker to switch operator without going through the lenghthy process to unstake, without resetting commission. +pub fn staking_contract_switch_operator_with_same_commission( + old_operator: AccountAddress, + new_operator: 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!("staking_contract").to_owned(), + ), + ident_str!("switch_operator_with_same_commission").to_owned(), + vec![], + vec![ + bcs::to_bytes(&old_operator).unwrap(), + bcs::to_bytes(&new_operator).unwrap(), + ], + )) +} + +/// Unlock all accumulated rewards since the last recorded principals. +pub fn staking_contract_unlock_rewards(operator: 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!("staking_contract").to_owned(), + ), + ident_str!("unlock_rewards").to_owned(), + vec![], + vec![bcs::to_bytes(&operator).unwrap()], + )) +} + +/// Staker can call this to request withdrawal of part or all of their staking_contract. +/// This also triggers paying commission to the operator for accounting simplicity. +pub fn staking_contract_unlock_stake(operator: 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!("staking_contract").to_owned(), + ), + ident_str!("unlock_stake").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Convenience function to allow a staker to update the commission percentage paid to the operator. +/// TODO: fix the typo in function name. commision -> commission +pub fn staking_contract_update_commision( + operator: AccountAddress, + new_commission_percentage: 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!("staking_contract").to_owned(), + ), + ident_str!("update_commision").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&new_commission_percentage).unwrap(), + ], + )) +} + +/// Convenient function to allow the staker to update the voter address in a staking contract they made. +pub fn staking_contract_update_voter( + operator: AccountAddress, + new_voter: 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!("staking_contract").to_owned(), + ), + ident_str!("update_voter").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&new_voter).unwrap(), + ], + )) +} + +pub fn staking_proxy_set_operator( + old_operator: AccountAddress, + new_operator: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_operator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&old_operator).unwrap(), + bcs::to_bytes(&new_operator).unwrap(), + ], + )) +} + +pub fn staking_proxy_set_stake_pool_operator(new_operator: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_stake_pool_operator").to_owned(), + vec![], + vec![bcs::to_bytes(&new_operator).unwrap()], + )) +} + +pub fn staking_proxy_set_stake_pool_voter(new_voter: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_stake_pool_voter").to_owned(), + vec![], + vec![bcs::to_bytes(&new_voter).unwrap()], + )) +} + +pub fn staking_proxy_set_staking_contract_operator( + old_operator: AccountAddress, + new_operator: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_staking_contract_operator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&old_operator).unwrap(), + bcs::to_bytes(&new_operator).unwrap(), + ], + )) +} + +pub fn staking_proxy_set_staking_contract_voter( + operator: AccountAddress, + new_voter: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_staking_contract_voter").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&new_voter).unwrap(), + ], + )) +} + +pub fn staking_proxy_set_vesting_contract_operator( + old_operator: AccountAddress, + new_operator: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_vesting_contract_operator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&old_operator).unwrap(), + bcs::to_bytes(&new_operator).unwrap(), + ], + )) +} + +pub fn staking_proxy_set_vesting_contract_voter( + operator: AccountAddress, + new_voter: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_vesting_contract_voter").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&new_voter).unwrap(), + ], + )) +} + +pub fn staking_proxy_set_voter( + operator: AccountAddress, + new_voter: 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!("staking_proxy").to_owned(), + ), + ident_str!("set_voter").to_owned(), + vec![], + vec![ + bcs::to_bytes(&operator).unwrap(), + bcs::to_bytes(&new_voter).unwrap(), + ], + )) +} + +pub fn transaction_fee_convert_to_aptos_fa_burn_ref() -> 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!("transaction_fee").to_owned(), + ), + ident_str!("convert_to_aptos_fa_burn_ref").to_owned(), + vec![], + vec![], + )) +} + +/// Used in on-chain governances to update the major version for the next epoch. +/// Example usage: +/// - `aptos_framework::version::set_for_next_epoch(&framework_signer, new_version);` +/// - `aptos_framework::aptos_governance::reconfigure(&framework_signer);` +pub fn version_set_for_next_epoch(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_for_next_epoch").to_owned(), + vec![], + vec![bcs::to_bytes(&major).unwrap()], + )) +} + +/// Deprecated by `set_for_next_epoch()`. +/// +/// WARNING: calling this while randomness is enabled will trigger a new epoch without randomness! +/// +/// TODO: update all the tests that reference this function, then disable this function. +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()], + )) +} + +/// Withdraw all funds to the preset vesting contract's withdrawal address. This can only be called if the contract +/// has already been terminated. +pub fn vesting_admin_withdraw(contract_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!("vesting").to_owned(), + ), + ident_str!("admin_withdraw").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_address).unwrap()], + )) +} + +/// Distribute any withdrawable stake from the stake pool. +pub fn vesting_distribute(contract_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!("vesting").to_owned(), + ), + ident_str!("distribute").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_address).unwrap()], + )) +} + +/// Call `distribute` for many vesting contracts. +pub fn vesting_distribute_many(contract_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!("vesting").to_owned(), + ), + ident_str!("distribute_many").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_addresses).unwrap()], + )) +} + +/// Remove the beneficiary for the given shareholder. All distributions will sent directly to the shareholder +/// account. +pub fn vesting_reset_beneficiary( + contract_address: AccountAddress, + shareholder: 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!("vesting").to_owned(), + ), + ident_str!("reset_beneficiary").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&shareholder).unwrap(), + ], + )) +} + +pub fn vesting_reset_lockup(contract_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!("vesting").to_owned(), + ), + ident_str!("reset_lockup").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_address).unwrap()], + )) +} + +pub fn vesting_set_beneficiary( + contract_address: AccountAddress, + shareholder: AccountAddress, + new_beneficiary: 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!("vesting").to_owned(), + ), + ident_str!("set_beneficiary").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&shareholder).unwrap(), + bcs::to_bytes(&new_beneficiary).unwrap(), + ], + )) +} + +/// Set the beneficiary for the operator. +pub fn vesting_set_beneficiary_for_operator(new_beneficiary: 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!("vesting").to_owned(), + ), + ident_str!("set_beneficiary_for_operator").to_owned(), + vec![], + vec![bcs::to_bytes(&new_beneficiary).unwrap()], + )) +} + +pub fn vesting_set_beneficiary_resetter( + contract_address: AccountAddress, + beneficiary_resetter: 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!("vesting").to_owned(), + ), + ident_str!("set_beneficiary_resetter").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&beneficiary_resetter).unwrap(), + ], + )) +} + +pub fn vesting_set_management_role( + contract_address: AccountAddress, + role: Vec, + role_holder: 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!("vesting").to_owned(), + ), + ident_str!("set_management_role").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&role).unwrap(), + bcs::to_bytes(&role_holder).unwrap(), + ], + )) +} + +/// Terminate the vesting contract and send all funds back to the withdrawal address. +pub fn vesting_terminate_vesting_contract(contract_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!("vesting").to_owned(), + ), + ident_str!("terminate_vesting_contract").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_address).unwrap()], + )) +} + +/// Unlock any accumulated rewards. +pub fn vesting_unlock_rewards(contract_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!("vesting").to_owned(), + ), + ident_str!("unlock_rewards").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_address).unwrap()], + )) +} + +/// Call `unlock_rewards` for many vesting contracts. +pub fn vesting_unlock_rewards_many(contract_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!("vesting").to_owned(), + ), + ident_str!("unlock_rewards_many").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_addresses).unwrap()], + )) +} + +pub fn vesting_update_commission_percentage( + contract_address: AccountAddress, + new_commission_percentage: 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!("vesting").to_owned(), + ), + ident_str!("update_commission_percentage").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&new_commission_percentage).unwrap(), + ], + )) +} + +pub fn vesting_update_operator( + contract_address: AccountAddress, + new_operator: AccountAddress, + commission_percentage: 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!("vesting").to_owned(), + ), + ident_str!("update_operator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&new_operator).unwrap(), + bcs::to_bytes(&commission_percentage).unwrap(), + ], + )) +} + +pub fn vesting_update_operator_with_same_commission( + contract_address: AccountAddress, + new_operator: 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!("vesting").to_owned(), + ), + ident_str!("update_operator_with_same_commission").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&new_operator).unwrap(), + ], + )) +} + +pub fn vesting_update_voter( + contract_address: AccountAddress, + new_voter: 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!("vesting").to_owned(), + ), + ident_str!("update_voter").to_owned(), + vec![], + vec![ + bcs::to_bytes(&contract_address).unwrap(), + bcs::to_bytes(&new_voter).unwrap(), + ], + )) +} + +/// Unlock any vested portion of the grant. +pub fn vesting_vest(contract_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!("vesting").to_owned(), + ), + ident_str!("vest").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_address).unwrap()], + )) +} + +/// Call `vest` for many vesting contracts. +pub fn vesting_vest_many(contract_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!("vesting").to_owned(), + ), + ident_str!("vest_many").to_owned(), + vec![], + vec![bcs::to_bytes(&contract_addresses).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().get(0)?).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().get(0)?).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().get(0)?).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().get(0)?).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().get(0)?).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_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AccountRotateAuthenticationKeyCall { + new_auth_key: bcs::from_bytes(script.args().get(0)?).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().get(0)?).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 aptos_account_batch_transfer(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosAccountBatchTransfer { + recipients: bcs::from_bytes(script.args().get(0)?).ok()?, + amounts: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_account_batch_transfer_coins( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosAccountBatchTransferCoins { + coin_type: script.ty_args().get(0)?.clone(), + recipients: bcs::from_bytes(script.args().get(0)?).ok()?, + amounts: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_account_create_account(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosAccountCreateAccount { + auth_key: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_account_set_allow_direct_coin_transfers( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosAccountSetAllowDirectCoinTransfers { + allow: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_account_transfer(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosAccountTransfer { + to: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_account_transfer_coins(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosAccountTransferCoins { + coin_type: script.ty_args().get(0)?.clone(), + to: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_coin_claim_mint_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::AptosCoinClaimMintCapability {}) + } else { + None + } + } + + pub fn aptos_coin_delegate_mint_capability( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosCoinDelegateMintCapability { + to: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_coin_mint(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosCoinMint { + dst_addr: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_governance_add_approved_script_hash_script( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::AptosGovernanceAddApprovedScriptHashScript { + proposal_id: bcs::from_bytes(script.args().get(0)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn aptos_governance_batch_partial_vote( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosGovernanceBatchPartialVote { + stake_pools: bcs::from_bytes(script.args().get(0)?).ok()?, + proposal_id: bcs::from_bytes(script.args().get(1)?).ok()?, + voting_power: bcs::from_bytes(script.args().get(2)?).ok()?, + should_pass: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_governance_batch_vote(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosGovernanceBatchVote { + stake_pools: bcs::from_bytes(script.args().get(0)?).ok()?, + proposal_id: bcs::from_bytes(script.args().get(1)?).ok()?, + should_pass: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_governance_create_proposal( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosGovernanceCreateProposal { + stake_pool: bcs::from_bytes(script.args().get(0)?).ok()?, + execution_hash: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_location: bcs::from_bytes(script.args().get(2)?).ok()?, + metadata_hash: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_governance_create_proposal_v2( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosGovernanceCreateProposalV2 { + stake_pool: bcs::from_bytes(script.args().get(0)?).ok()?, + execution_hash: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_location: bcs::from_bytes(script.args().get(2)?).ok()?, + metadata_hash: bcs::from_bytes(script.args().get(3)?).ok()?, + is_multi_step_proposal: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_governance_force_end_epoch( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::AptosGovernanceForceEndEpoch {}) + } else { + None + } + } + + pub fn aptos_governance_force_end_epoch_test_only( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::AptosGovernanceForceEndEpochTestOnly {}) + } else { + None + } + } + + pub fn aptos_governance_partial_vote( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosGovernancePartialVote { + stake_pool: bcs::from_bytes(script.args().get(0)?).ok()?, + proposal_id: bcs::from_bytes(script.args().get(1)?).ok()?, + voting_power: bcs::from_bytes(script.args().get(2)?).ok()?, + should_pass: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_governance_reconfigure(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::AptosGovernanceReconfigure {}) + } else { + None + } + } + + pub fn aptos_governance_vote(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosGovernanceVote { + stake_pool: bcs::from_bytes(script.args().get(0)?).ok()?, + proposal_id: bcs::from_bytes(script.args().get(1)?).ok()?, + should_pass: bcs::from_bytes(script.args().get(2)?).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().get(0)?).ok()?, + code: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn coin_create_coin_conversion_map( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::CoinCreateCoinConversionMap {}) + } else { + None + } + } + + pub fn coin_create_pairing(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CoinCreatePairing { + coin_type: script.ty_args().get(0)?.clone(), + }) + } else { + None + } + } + + pub fn coin_migrate_to_fungible_store( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CoinMigrateToFungibleStore { + coin_type: script.ty_args().get(0)?.clone(), + }) + } else { + None + } + } + + pub fn coin_transfer(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CoinTransfer { + coin_type: script.ty_args().get(0)?.clone(), + to: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn coin_upgrade_supply(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CoinUpgradeSupply { + coin_type: script.ty_args().get(0)?.clone(), + }) + } else { + None + } + } + + pub fn delegation_pool_add_stake(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolAddStake { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_allowlist_delegator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolAllowlistDelegator { + delegator_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_create_proposal( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolCreateProposal { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + execution_hash: bcs::from_bytes(script.args().get(1)?).ok()?, + metadata_location: bcs::from_bytes(script.args().get(2)?).ok()?, + metadata_hash: bcs::from_bytes(script.args().get(3)?).ok()?, + is_multi_step_proposal: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_delegate_voting_power( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolDelegateVotingPower { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + new_voter: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_disable_delegators_allowlisting( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::DelegationPoolDisableDelegatorsAllowlisting {}) + } else { + None + } + } + + pub fn delegation_pool_enable_delegators_allowlisting( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::DelegationPoolEnableDelegatorsAllowlisting {}) + } else { + None + } + } + + pub fn delegation_pool_enable_partial_governance_voting( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::DelegationPoolEnablePartialGovernanceVoting { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn delegation_pool_evict_delegator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolEvictDelegator { + delegator_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_initialize_delegation_pool( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolInitializeDelegationPool { + operator_commission_percentage: bcs::from_bytes(script.args().get(0)?).ok()?, + delegation_pool_creation_seed: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_reactivate_stake( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolReactivateStake { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_remove_delegator_from_allowlist( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::DelegationPoolRemoveDelegatorFromAllowlist { + delegator_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn delegation_pool_set_beneficiary_for_operator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolSetBeneficiaryForOperator { + new_beneficiary: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_set_delegated_voter( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolSetDelegatedVoter { + new_voter: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_set_operator(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolSetOperator { + new_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_synchronize_delegation_pool( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolSynchronizeDelegationPool { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_unlock(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolUnlock { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_update_commission_percentage( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::DelegationPoolUpdateCommissionPercentage { + new_commission_percentage: bcs::from_bytes(script.args().get(0)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn delegation_pool_vote(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolVote { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + proposal_id: bcs::from_bytes(script.args().get(1)?).ok()?, + voting_power: bcs::from_bytes(script.args().get(2)?).ok()?, + should_pass: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn delegation_pool_withdraw(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::DelegationPoolWithdraw { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn managed_coin_burn(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ManagedCoinBurn { + coin_type: script.ty_args().get(0)?.clone(), + amount: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn managed_coin_initialize(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ManagedCoinInitialize { + coin_type: script.ty_args().get(0)?.clone(), + name: bcs::from_bytes(script.args().get(0)?).ok()?, + symbol: bcs::from_bytes(script.args().get(1)?).ok()?, + decimals: bcs::from_bytes(script.args().get(2)?).ok()?, + monitor_supply: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn managed_coin_mint(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ManagedCoinMint { + coin_type: script.ty_args().get(0)?.clone(), + dst_addr: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn managed_coin_register(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ManagedCoinRegister { + coin_type: script.ty_args().get(0)?.clone(), + }) + } 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().get(0)?).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().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_add_owners_and_update_signatures_required( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountAddOwnersAndUpdateSignaturesRequired { + new_owners: bcs::from_bytes(script.args().get(0)?).ok()?, + new_num_signatures_required: bcs::from_bytes(script.args().get(1)?).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().get(0)?).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().get(0)?).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().get(0)?).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().get(0)?).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().get(0)?).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_existing_account_and_revoke_auth_key( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountCreateWithExistingAccountAndRevokeAuthKey { + multisig_address: bcs::from_bytes(script.args().get(0)?).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().get(0)?).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_create_with_owners_then_remove_bootstrapper( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountCreateWithOwnersThenRemoveBootstrapper { + owners: bcs::from_bytes(script.args().get(0)?).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().get(0)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn multisig_account_execute_rejected_transactions( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountExecuteRejectedTransactions { + multisig_account: bcs::from_bytes(script.args().get(0)?).ok()?, + final_sequence_number: bcs::from_bytes(script.args().get(1)?).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().get(0)?).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().get(0)?).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().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_swap_owner(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountSwapOwner { + to_swap_in: bcs::from_bytes(script.args().get(0)?).ok()?, + to_swap_out: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_swap_owners(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountSwapOwners { + to_swap_in: bcs::from_bytes(script.args().get(0)?).ok()?, + to_swap_out: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_swap_owners_and_update_signatures_required( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::MultisigAccountSwapOwnersAndUpdateSignaturesRequired { + new_owners: bcs::from_bytes(script.args().get(0)?).ok()?, + owners_to_remove: bcs::from_bytes(script.args().get(1)?).ok()?, + new_num_signatures_required: bcs::from_bytes(script.args().get(2)?).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().get(0)?).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().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_vote_transaction( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountVoteTransaction { + multisig_account: bcs::from_bytes(script.args().get(0)?).ok()?, + sequence_number: bcs::from_bytes(script.args().get(1)?).ok()?, + approved: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn multisig_account_vote_transactions( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::MultisigAccountVoteTransactions { + multisig_account: bcs::from_bytes(script.args().get(0)?).ok()?, + starting_sequence_number: bcs::from_bytes(script.args().get(1)?).ok()?, + final_sequence_number: bcs::from_bytes(script.args().get(2)?).ok()?, + approved: bcs::from_bytes(script.args().get(3)?).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().get(0)?).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().get(0)?).ok()?, + to: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn object_code_deployment_publish( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ObjectCodeDeploymentPublish { + metadata_serialized: bcs::from_bytes(script.args().get(0)?).ok()?, + code: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn resource_account_create_resource_account( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::ResourceAccountCreateResourceAccount { + seed: bcs::from_bytes(script.args().get(0)?).ok()?, + optional_auth_key: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn resource_account_create_resource_account_and_fund( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::ResourceAccountCreateResourceAccountAndFund { + seed: bcs::from_bytes(script.args().get(0)?).ok()?, + optional_auth_key: bcs::from_bytes(script.args().get(1)?).ok()?, + fund_amount: bcs::from_bytes(script.args().get(2)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn resource_account_create_resource_account_and_publish_package( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::ResourceAccountCreateResourceAccountAndPublishPackage { + seed: bcs::from_bytes(script.args().get(0)?).ok()?, + metadata_serialized: bcs::from_bytes(script.args().get(1)?).ok()?, + code: bcs::from_bytes(script.args().get(2)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn stake_add_stake(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeAddStake { + amount: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_increase_lockup(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::StakeIncreaseLockup {}) + } else { + None + } + } + + pub fn stake_initialize_stake_owner(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeInitializeStakeOwner { + initial_stake_amount: bcs::from_bytes(script.args().get(0)?).ok()?, + operator: bcs::from_bytes(script.args().get(1)?).ok()?, + voter: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } 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().get(0)?).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_join_validator_set(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeJoinValidatorSet { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_leave_validator_set(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeLeaveValidatorSet { + pool_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_reactivate_stake(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeReactivateStake { + amount: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_rotate_consensus_key(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeRotateConsensusKey { + pool_address: bcs::from_bytes(script.args().get(0)?).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_set_delegated_voter(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeSetDelegatedVoter { + new_voter: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_set_operator(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeSetOperator { + new_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_unlock(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeUnlock { + amount: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn stake_update_network_and_fullnode_addresses( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeUpdateNetworkAndFullnodeAddresses { + pool_address: bcs::from_bytes(script.args().get(0)?).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 stake_withdraw(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakeWithdraw { + withdraw_amount: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_add_stake(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractAddStake { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_create_staking_contract( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractCreateStakingContract { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + voter: bcs::from_bytes(script.args().get(1)?).ok()?, + amount: bcs::from_bytes(script.args().get(2)?).ok()?, + commission_percentage: bcs::from_bytes(script.args().get(3)?).ok()?, + contract_creation_seed: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_distribute(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractDistribute { + staker: bcs::from_bytes(script.args().get(0)?).ok()?, + operator: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_request_commission( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractRequestCommission { + staker: bcs::from_bytes(script.args().get(0)?).ok()?, + operator: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_reset_lockup( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractResetLockup { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_set_beneficiary_for_operator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::StakingContractSetBeneficiaryForOperator { + new_beneficiary: bcs::from_bytes(script.args().get(0)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn staking_contract_switch_operator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractSwitchOperator { + old_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_operator: bcs::from_bytes(script.args().get(1)?).ok()?, + new_commission_percentage: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_switch_operator_with_same_commission( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some( + EntryFunctionCall::StakingContractSwitchOperatorWithSameCommission { + old_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_operator: bcs::from_bytes(script.args().get(1)?).ok()?, + }, + ) + } else { + None + } + } + + pub fn staking_contract_unlock_rewards( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractUnlockRewards { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_unlock_stake( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractUnlockStake { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + amount: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_update_commision( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractUpdateCommision { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_commission_percentage: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_contract_update_voter( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingContractUpdateVoter { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_voter: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_operator(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetOperator { + old_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_operator: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_stake_pool_operator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetStakePoolOperator { + new_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_stake_pool_voter( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetStakePoolVoter { + new_voter: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_staking_contract_operator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetStakingContractOperator { + old_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_operator: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_staking_contract_voter( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetStakingContractVoter { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_voter: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_vesting_contract_operator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetVestingContractOperator { + old_operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_operator: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_vesting_contract_voter( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetVestingContractVoter { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_voter: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn staking_proxy_set_voter(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::StakingProxySetVoter { + operator: bcs::from_bytes(script.args().get(0)?).ok()?, + new_voter: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn transaction_fee_convert_to_aptos_fa_burn_ref( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::TransactionFeeConvertToAptosFaBurnRef {}) + } else { + None + } + } + + pub fn version_set_for_next_epoch(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VersionSetForNextEpoch { + major: bcs::from_bytes(script.args().get(0)?).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().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_admin_withdraw(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingAdminWithdraw { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_distribute(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingDistribute { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_distribute_many(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingDistributeMany { + contract_addresses: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_reset_beneficiary(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingResetBeneficiary { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + shareholder: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_reset_lockup(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingResetLockup { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_set_beneficiary(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingSetBeneficiary { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + shareholder: bcs::from_bytes(script.args().get(1)?).ok()?, + new_beneficiary: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_set_beneficiary_for_operator( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingSetBeneficiaryForOperator { + new_beneficiary: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_set_beneficiary_resetter( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingSetBeneficiaryResetter { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + beneficiary_resetter: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_set_management_role(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingSetManagementRole { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + role: bcs::from_bytes(script.args().get(1)?).ok()?, + role_holder: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_terminate_vesting_contract( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingTerminateVestingContract { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_unlock_rewards(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingUnlockRewards { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_unlock_rewards_many(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingUnlockRewardsMany { + contract_addresses: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_update_commission_percentage( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingUpdateCommissionPercentage { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + new_commission_percentage: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_update_operator(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingUpdateOperator { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + new_operator: bcs::from_bytes(script.args().get(1)?).ok()?, + commission_percentage: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_update_operator_with_same_commission( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingUpdateOperatorWithSameCommission { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + new_operator: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_update_voter(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingUpdateVoter { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + new_voter: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_vest(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingVest { + contract_address: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn vesting_vest_many(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::VestingVestMany { + contract_addresses: bcs::from_bytes(script.args().get(0)?).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_call".to_string(), + Box::new(decoder::account_rotate_authentication_key_call), + ); + map.insert( + "account_rotate_authentication_key_with_rotation_capability".to_string(), + Box::new(decoder::account_rotate_authentication_key_with_rotation_capability), + ); + map.insert( + "aptos_account_batch_transfer".to_string(), + Box::new(decoder::aptos_account_batch_transfer), + ); + map.insert( + "aptos_account_batch_transfer_coins".to_string(), + Box::new(decoder::aptos_account_batch_transfer_coins), + ); + map.insert( + "aptos_account_create_account".to_string(), + Box::new(decoder::aptos_account_create_account), + ); + map.insert( + "aptos_account_set_allow_direct_coin_transfers".to_string(), + Box::new(decoder::aptos_account_set_allow_direct_coin_transfers), + ); + map.insert( + "aptos_account_transfer".to_string(), + Box::new(decoder::aptos_account_transfer), + ); + map.insert( + "aptos_account_transfer_coins".to_string(), + Box::new(decoder::aptos_account_transfer_coins), + ); + map.insert( + "aptos_coin_claim_mint_capability".to_string(), + Box::new(decoder::aptos_coin_claim_mint_capability), + ); + map.insert( + "aptos_coin_delegate_mint_capability".to_string(), + Box::new(decoder::aptos_coin_delegate_mint_capability), + ); + map.insert( + "aptos_coin_mint".to_string(), + Box::new(decoder::aptos_coin_mint), + ); + map.insert( + "aptos_governance_add_approved_script_hash_script".to_string(), + Box::new(decoder::aptos_governance_add_approved_script_hash_script), + ); + map.insert( + "aptos_governance_batch_partial_vote".to_string(), + Box::new(decoder::aptos_governance_batch_partial_vote), + ); + map.insert( + "aptos_governance_batch_vote".to_string(), + Box::new(decoder::aptos_governance_batch_vote), + ); + map.insert( + "aptos_governance_create_proposal".to_string(), + Box::new(decoder::aptos_governance_create_proposal), + ); + map.insert( + "aptos_governance_create_proposal_v2".to_string(), + Box::new(decoder::aptos_governance_create_proposal_v2), + ); + map.insert( + "aptos_governance_force_end_epoch".to_string(), + Box::new(decoder::aptos_governance_force_end_epoch), + ); + map.insert( + "aptos_governance_force_end_epoch_test_only".to_string(), + Box::new(decoder::aptos_governance_force_end_epoch_test_only), + ); + map.insert( + "aptos_governance_partial_vote".to_string(), + Box::new(decoder::aptos_governance_partial_vote), + ); + map.insert( + "aptos_governance_reconfigure".to_string(), + Box::new(decoder::aptos_governance_reconfigure), + ); + map.insert( + "aptos_governance_vote".to_string(), + Box::new(decoder::aptos_governance_vote), + ); + map.insert( + "code_publish_package_txn".to_string(), + Box::new(decoder::code_publish_package_txn), + ); + map.insert( + "coin_create_coin_conversion_map".to_string(), + Box::new(decoder::coin_create_coin_conversion_map), + ); + map.insert( + "coin_create_pairing".to_string(), + Box::new(decoder::coin_create_pairing), + ); + map.insert( + "coin_migrate_to_fungible_store".to_string(), + Box::new(decoder::coin_migrate_to_fungible_store), + ); + map.insert( + "coin_transfer".to_string(), + Box::new(decoder::coin_transfer), + ); + map.insert( + "coin_upgrade_supply".to_string(), + Box::new(decoder::coin_upgrade_supply), + ); + map.insert( + "delegation_pool_add_stake".to_string(), + Box::new(decoder::delegation_pool_add_stake), + ); + map.insert( + "delegation_pool_allowlist_delegator".to_string(), + Box::new(decoder::delegation_pool_allowlist_delegator), + ); + map.insert( + "delegation_pool_create_proposal".to_string(), + Box::new(decoder::delegation_pool_create_proposal), + ); + map.insert( + "delegation_pool_delegate_voting_power".to_string(), + Box::new(decoder::delegation_pool_delegate_voting_power), + ); + map.insert( + "delegation_pool_disable_delegators_allowlisting".to_string(), + Box::new(decoder::delegation_pool_disable_delegators_allowlisting), + ); + map.insert( + "delegation_pool_enable_delegators_allowlisting".to_string(), + Box::new(decoder::delegation_pool_enable_delegators_allowlisting), + ); + map.insert( + "delegation_pool_enable_partial_governance_voting".to_string(), + Box::new(decoder::delegation_pool_enable_partial_governance_voting), + ); + map.insert( + "delegation_pool_evict_delegator".to_string(), + Box::new(decoder::delegation_pool_evict_delegator), + ); + map.insert( + "delegation_pool_initialize_delegation_pool".to_string(), + Box::new(decoder::delegation_pool_initialize_delegation_pool), + ); + map.insert( + "delegation_pool_reactivate_stake".to_string(), + Box::new(decoder::delegation_pool_reactivate_stake), + ); + map.insert( + "delegation_pool_remove_delegator_from_allowlist".to_string(), + Box::new(decoder::delegation_pool_remove_delegator_from_allowlist), + ); + map.insert( + "delegation_pool_set_beneficiary_for_operator".to_string(), + Box::new(decoder::delegation_pool_set_beneficiary_for_operator), + ); + map.insert( + "delegation_pool_set_delegated_voter".to_string(), + Box::new(decoder::delegation_pool_set_delegated_voter), + ); + map.insert( + "delegation_pool_set_operator".to_string(), + Box::new(decoder::delegation_pool_set_operator), + ); + map.insert( + "delegation_pool_synchronize_delegation_pool".to_string(), + Box::new(decoder::delegation_pool_synchronize_delegation_pool), + ); + map.insert( + "delegation_pool_unlock".to_string(), + Box::new(decoder::delegation_pool_unlock), + ); + map.insert( + "delegation_pool_update_commission_percentage".to_string(), + Box::new(decoder::delegation_pool_update_commission_percentage), + ); + map.insert( + "delegation_pool_vote".to_string(), + Box::new(decoder::delegation_pool_vote), + ); + map.insert( + "delegation_pool_withdraw".to_string(), + Box::new(decoder::delegation_pool_withdraw), + ); + map.insert( + "managed_coin_burn".to_string(), + Box::new(decoder::managed_coin_burn), + ); + map.insert( + "managed_coin_initialize".to_string(), + Box::new(decoder::managed_coin_initialize), + ); + map.insert( + "managed_coin_mint".to_string(), + Box::new(decoder::managed_coin_mint), + ); + map.insert( + "managed_coin_register".to_string(), + Box::new(decoder::managed_coin_register), + ); + 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_add_owners_and_update_signatures_required".to_string(), + Box::new(decoder::multisig_account_add_owners_and_update_signatures_required), + ); + 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_existing_account_and_revoke_auth_key".to_string(), + Box::new(decoder::multisig_account_create_with_existing_account_and_revoke_auth_key), + ); + map.insert( + "multisig_account_create_with_owners".to_string(), + Box::new(decoder::multisig_account_create_with_owners), + ); + map.insert( + "multisig_account_create_with_owners_then_remove_bootstrapper".to_string(), + Box::new(decoder::multisig_account_create_with_owners_then_remove_bootstrapper), + ); + map.insert( + "multisig_account_execute_rejected_transaction".to_string(), + Box::new(decoder::multisig_account_execute_rejected_transaction), + ); + map.insert( + "multisig_account_execute_rejected_transactions".to_string(), + Box::new(decoder::multisig_account_execute_rejected_transactions), + ); + 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_swap_owner".to_string(), + Box::new(decoder::multisig_account_swap_owner), + ); + map.insert( + "multisig_account_swap_owners".to_string(), + Box::new(decoder::multisig_account_swap_owners), + ); + map.insert( + "multisig_account_swap_owners_and_update_signatures_required".to_string(), + Box::new(decoder::multisig_account_swap_owners_and_update_signatures_required), + ); + 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_transaction".to_string(), + Box::new(decoder::multisig_account_vote_transaction), + ); + map.insert( + "multisig_account_vote_transactions".to_string(), + Box::new(decoder::multisig_account_vote_transactions), + ); + 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( + "object_code_deployment_publish".to_string(), + Box::new(decoder::object_code_deployment_publish), + ); + map.insert( + "resource_account_create_resource_account".to_string(), + Box::new(decoder::resource_account_create_resource_account), + ); + map.insert( + "resource_account_create_resource_account_and_fund".to_string(), + Box::new(decoder::resource_account_create_resource_account_and_fund), + ); + map.insert( + "resource_account_create_resource_account_and_publish_package".to_string(), + Box::new(decoder::resource_account_create_resource_account_and_publish_package), + ); + map.insert( + "stake_add_stake".to_string(), + Box::new(decoder::stake_add_stake), + ); + map.insert( + "stake_increase_lockup".to_string(), + Box::new(decoder::stake_increase_lockup), + ); + map.insert( + "stake_initialize_stake_owner".to_string(), + Box::new(decoder::stake_initialize_stake_owner), + ); + map.insert( + "stake_initialize_validator".to_string(), + Box::new(decoder::stake_initialize_validator), + ); + map.insert( + "stake_join_validator_set".to_string(), + Box::new(decoder::stake_join_validator_set), + ); + map.insert( + "stake_leave_validator_set".to_string(), + Box::new(decoder::stake_leave_validator_set), + ); + map.insert( + "stake_reactivate_stake".to_string(), + Box::new(decoder::stake_reactivate_stake), + ); + map.insert( + "stake_rotate_consensus_key".to_string(), + Box::new(decoder::stake_rotate_consensus_key), + ); + map.insert( + "stake_set_delegated_voter".to_string(), + Box::new(decoder::stake_set_delegated_voter), + ); + map.insert( + "stake_set_operator".to_string(), + Box::new(decoder::stake_set_operator), + ); + map.insert("stake_unlock".to_string(), Box::new(decoder::stake_unlock)); + map.insert( + "stake_update_network_and_fullnode_addresses".to_string(), + Box::new(decoder::stake_update_network_and_fullnode_addresses), + ); + map.insert( + "stake_withdraw".to_string(), + Box::new(decoder::stake_withdraw), + ); + map.insert( + "staking_contract_add_stake".to_string(), + Box::new(decoder::staking_contract_add_stake), + ); + map.insert( + "staking_contract_create_staking_contract".to_string(), + Box::new(decoder::staking_contract_create_staking_contract), + ); + map.insert( + "staking_contract_distribute".to_string(), + Box::new(decoder::staking_contract_distribute), + ); + map.insert( + "staking_contract_request_commission".to_string(), + Box::new(decoder::staking_contract_request_commission), + ); + map.insert( + "staking_contract_reset_lockup".to_string(), + Box::new(decoder::staking_contract_reset_lockup), + ); + map.insert( + "staking_contract_set_beneficiary_for_operator".to_string(), + Box::new(decoder::staking_contract_set_beneficiary_for_operator), + ); + map.insert( + "staking_contract_switch_operator".to_string(), + Box::new(decoder::staking_contract_switch_operator), + ); + map.insert( + "staking_contract_switch_operator_with_same_commission".to_string(), + Box::new(decoder::staking_contract_switch_operator_with_same_commission), + ); + map.insert( + "staking_contract_unlock_rewards".to_string(), + Box::new(decoder::staking_contract_unlock_rewards), + ); + map.insert( + "staking_contract_unlock_stake".to_string(), + Box::new(decoder::staking_contract_unlock_stake), + ); + map.insert( + "staking_contract_update_commision".to_string(), + Box::new(decoder::staking_contract_update_commision), + ); + map.insert( + "staking_contract_update_voter".to_string(), + Box::new(decoder::staking_contract_update_voter), + ); + map.insert( + "staking_proxy_set_operator".to_string(), + Box::new(decoder::staking_proxy_set_operator), + ); + map.insert( + "staking_proxy_set_stake_pool_operator".to_string(), + Box::new(decoder::staking_proxy_set_stake_pool_operator), + ); + map.insert( + "staking_proxy_set_stake_pool_voter".to_string(), + Box::new(decoder::staking_proxy_set_stake_pool_voter), + ); + map.insert( + "staking_proxy_set_staking_contract_operator".to_string(), + Box::new(decoder::staking_proxy_set_staking_contract_operator), + ); + map.insert( + "staking_proxy_set_staking_contract_voter".to_string(), + Box::new(decoder::staking_proxy_set_staking_contract_voter), + ); + map.insert( + "staking_proxy_set_vesting_contract_operator".to_string(), + Box::new(decoder::staking_proxy_set_vesting_contract_operator), + ); + map.insert( + "staking_proxy_set_vesting_contract_voter".to_string(), + Box::new(decoder::staking_proxy_set_vesting_contract_voter), + ); + map.insert( + "staking_proxy_set_voter".to_string(), + Box::new(decoder::staking_proxy_set_voter), + ); + map.insert( + "transaction_fee_convert_to_aptos_fa_burn_ref".to_string(), + Box::new(decoder::transaction_fee_convert_to_aptos_fa_burn_ref), + ); + map.insert( + "version_set_for_next_epoch".to_string(), + Box::new(decoder::version_set_for_next_epoch), + ); + map.insert( + "version_set_version".to_string(), + Box::new(decoder::version_set_version), + ); + map.insert( + "vesting_admin_withdraw".to_string(), + Box::new(decoder::vesting_admin_withdraw), + ); + map.insert( + "vesting_distribute".to_string(), + Box::new(decoder::vesting_distribute), + ); + map.insert( + "vesting_distribute_many".to_string(), + Box::new(decoder::vesting_distribute_many), + ); + map.insert( + "vesting_reset_beneficiary".to_string(), + Box::new(decoder::vesting_reset_beneficiary), + ); + map.insert( + "vesting_reset_lockup".to_string(), + Box::new(decoder::vesting_reset_lockup), + ); + map.insert( + "vesting_set_beneficiary".to_string(), + Box::new(decoder::vesting_set_beneficiary), + ); + map.insert( + "vesting_set_beneficiary_for_operator".to_string(), + Box::new(decoder::vesting_set_beneficiary_for_operator), + ); + map.insert( + "vesting_set_beneficiary_resetter".to_string(), + Box::new(decoder::vesting_set_beneficiary_resetter), + ); + map.insert( + "vesting_set_management_role".to_string(), + Box::new(decoder::vesting_set_management_role), + ); + map.insert( + "vesting_terminate_vesting_contract".to_string(), + Box::new(decoder::vesting_terminate_vesting_contract), + ); + map.insert( + "vesting_unlock_rewards".to_string(), + Box::new(decoder::vesting_unlock_rewards), + ); + map.insert( + "vesting_unlock_rewards_many".to_string(), + Box::new(decoder::vesting_unlock_rewards_many), + ); + map.insert( + "vesting_update_commission_percentage".to_string(), + Box::new(decoder::vesting_update_commission_percentage), + ); + map.insert( + "vesting_update_operator".to_string(), + Box::new(decoder::vesting_update_operator), + ); + map.insert( + "vesting_update_operator_with_same_commission".to_string(), + Box::new(decoder::vesting_update_operator_with_same_commission), + ); + map.insert( + "vesting_update_voter".to_string(), + Box::new(decoder::vesting_update_voter), + ); + map.insert("vesting_vest".to_string(), Box::new(decoder::vesting_vest)); + map.insert( + "vesting_vest_many".to_string(), + Box::new(decoder::vesting_vest_many), + ); + map + }); diff --git a/vm/framework/cached-packages/src/starcoin_stdlib.rs b/vm/framework/cached-packages/src/starcoin_stdlib.rs new file mode 100644 index 0000000000..c2b5294c23 --- /dev/null +++ b/vm/framework/cached-packages/src/starcoin_stdlib.rs @@ -0,0 +1,84 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +#![allow(unused_imports)] + +pub use crate::{ + starcoin_framework_sdk_builder::*, starcoin_token_objects_sdk_builder as aptos_token_objects_stdlib, + starcoin_token_sdk_builder as aptos_token_stdlib, +}; +use starcoin_framework::{BuildOptions, BuiltPackage}; +use starcoin_package_builder::PackageBuilder; +use starcoin_vm_types::{ + account_address::AccountAddress, + transaction::{EntryFunction, TransactionPayload}, +}; +use move_core_types::{ident_str, language_storage::ModuleId}; + +pub fn starcoin_coin_transfer(to: AccountAddress, amount: u64) -> TransactionPayload { + coin_transfer( + starcoin_vm_types::utility_coin::APTOS_COIN_TYPE.clone(), + to, + amount, + ) +} + +pub fn publish_module_source(module_name: &str, module_src: &str) -> TransactionPayload { + let mut builder = PackageBuilder::new("tmp"); + builder.add_source(module_name, module_src); + + let tmp_dir = builder.write_to_temp().unwrap(); + let package = BuiltPackage::build(tmp_dir.path().to_path_buf(), BuildOptions::default()) + .expect("Should be able to build a package"); + let code = package.extract_code(); + let metadata = package + .extract_metadata() + .expect("Should be able to extract metadata"); + let metadata_serialized = + bcs::to_bytes(&metadata).expect("Should be able to serialize metadata"); + code_publish_package_txn(metadata_serialized, code) +} + +/// Temporary workaround as `Object` as a function argument is not recognised +/// when auto generating move transaction payloads. Will address in separate PR. +pub fn object_code_deployment_upgrade( + metadata_serialized: Vec, + code: Vec>, + code_object: 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_code_deployment").to_owned(), + ), + ident_str!("upgrade").to_owned(), + vec![], + vec![ + bcs::to_bytes(&metadata_serialized).unwrap(), + bcs::to_bytes(&code).unwrap(), + bcs::to_bytes(&code_object).unwrap(), + ], + )) +} + +/// Temporary workaround as `Object` as a function argument is not recognised +/// when auto generating move transaction payloads. Will address in separate PR. +pub fn object_code_deployment_freeze_code_object( + code_object: 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_code_deployment").to_owned(), + ), + ident_str!("freeze_code_object").to_owned(), + vec![], + vec![bcs::to_bytes(&code_object).unwrap()], + )) +} diff --git a/vm/framework/cached-packages/src/starcoin_token_objects_sdk_builder.rs b/vm/framework/cached-packages/src/starcoin_token_objects_sdk_builder.rs new file mode 100644 index 0000000000..670ed8a4da --- /dev/null +++ b/vm/framework/cached-packages/src/starcoin_token_objects_sdk_builder.rs @@ -0,0 +1,380 @@ +// Copyright © Aptos 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 Aptos transactions (`Script`). +// +// This code was generated by compiling known Script interfaces ("ABIs") with the tool `aptos-sdk-builder`. + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::arc_with_non_send_sync)] +#![allow(clippy::get_first)] +use starcoin_vm_types::{ + account_address::AccountAddress, + transaction::{ScriptFunction, 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 { .. } +/// } +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] +#[cfg_attr(feature = "fuzzing", proptest(no_params))] +pub enum EntryFunctionCall { + /// Create a new collection + AptosTokenCreateCollection { + description: Vec, + max_supply: u64, + name: Vec, + uri: Vec, + mutable_description: bool, + mutable_royalty: bool, + mutable_uri: bool, + mutable_token_description: bool, + mutable_token_name: bool, + mutable_token_properties: bool, + mutable_token_uri: bool, + tokens_burnable_by_creator: bool, + tokens_freezable_by_creator: bool, + royalty_numerator: u64, + royalty_denominator: u64, + }, + + /// With an existing collection, directly mint a viable token into the creators account. + AptosTokenMint { + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, + }, + + /// With an existing collection, directly mint a soul bound token into the recipient's account. + AptosTokenMintSoulBound { + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, + soul_bound_to: AccountAddress, + }, +} + +impl EntryFunctionCall { + /// Build an Aptos `TransactionPayload` from a structured object `EntryFunctionCall`. + pub fn encode(self) -> TransactionPayload { + use EntryFunctionCall::*; + match self { + AptosTokenCreateCollection { + description, + max_supply, + name, + uri, + mutable_description, + mutable_royalty, + mutable_uri, + mutable_token_description, + mutable_token_name, + mutable_token_properties, + mutable_token_uri, + tokens_burnable_by_creator, + tokens_freezable_by_creator, + royalty_numerator, + royalty_denominator, + } => aptos_token_create_collection( + description, + max_supply, + name, + uri, + mutable_description, + mutable_royalty, + mutable_uri, + mutable_token_description, + mutable_token_name, + mutable_token_properties, + mutable_token_uri, + tokens_burnable_by_creator, + tokens_freezable_by_creator, + royalty_numerator, + royalty_denominator, + ), + AptosTokenMint { + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + } => aptos_token_mint( + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + ), + AptosTokenMintSoulBound { + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + soul_bound_to, + } => aptos_token_mint_soul_bound( + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + soul_bound_to, + ), + } + } + + /// Try to recognize an Aptos `TransactionPayload` and convert it into a structured object `EntryFunctionCall`. + pub fn decode(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + match SCRIPT_FUNCTION_DECODER_MAP.get(&format!( + "{}_{}", + script.module().name(), + script.function() + )) { + Some(decoder) => decoder(payload), + None => None, + } + } else { + None + } + } +} + +/// Create a new collection +pub fn aptos_token_create_collection( + description: Vec, + max_supply: u64, + name: Vec, + uri: Vec, + mutable_description: bool, + mutable_royalty: bool, + mutable_uri: bool, + mutable_token_description: bool, + mutable_token_name: bool, + mutable_token_properties: bool, + mutable_token_uri: bool, + tokens_burnable_by_creator: bool, + tokens_freezable_by_creator: bool, + royalty_numerator: u64, + royalty_denominator: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("create_collection").to_owned(), + vec![], + vec![ + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&max_supply).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&mutable_description).unwrap(), + bcs::to_bytes(&mutable_royalty).unwrap(), + bcs::to_bytes(&mutable_uri).unwrap(), + bcs::to_bytes(&mutable_token_description).unwrap(), + bcs::to_bytes(&mutable_token_name).unwrap(), + bcs::to_bytes(&mutable_token_properties).unwrap(), + bcs::to_bytes(&mutable_token_uri).unwrap(), + bcs::to_bytes(&tokens_burnable_by_creator).unwrap(), + bcs::to_bytes(&tokens_freezable_by_creator).unwrap(), + bcs::to_bytes(&royalty_numerator).unwrap(), + bcs::to_bytes(&royalty_denominator).unwrap(), + ], + )) +} + +/// With an existing collection, directly mint a viable token into the creators account. +pub fn aptos_token_mint( + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::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, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("mint").to_owned(), + vec![], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&property_keys).unwrap(), + bcs::to_bytes(&property_types).unwrap(), + bcs::to_bytes(&property_values).unwrap(), + ], + )) +} + +/// With an existing collection, directly mint a soul bound token into the recipient's account. +pub fn aptos_token_mint_soul_bound( + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, + soul_bound_to: AccountAddress, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("mint_soul_bound").to_owned(), + vec![], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&property_keys).unwrap(), + bcs::to_bytes(&property_types).unwrap(), + bcs::to_bytes(&property_values).unwrap(), + bcs::to_bytes(&soul_bound_to).unwrap(), + ], + )) +} +mod decoder { + use super::*; + pub fn aptos_token_create_collection( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenCreateCollection { + description: bcs::from_bytes(script.args().get(0)?).ok()?, + max_supply: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + uri: bcs::from_bytes(script.args().get(3)?).ok()?, + mutable_description: bcs::from_bytes(script.args().get(4)?).ok()?, + mutable_royalty: bcs::from_bytes(script.args().get(5)?).ok()?, + mutable_uri: bcs::from_bytes(script.args().get(6)?).ok()?, + mutable_token_description: bcs::from_bytes(script.args().get(7)?).ok()?, + mutable_token_name: bcs::from_bytes(script.args().get(8)?).ok()?, + mutable_token_properties: bcs::from_bytes(script.args().get(9)?).ok()?, + mutable_token_uri: bcs::from_bytes(script.args().get(10)?).ok()?, + tokens_burnable_by_creator: bcs::from_bytes(script.args().get(11)?).ok()?, + tokens_freezable_by_creator: bcs::from_bytes(script.args().get(12)?).ok()?, + royalty_numerator: bcs::from_bytes(script.args().get(13)?).ok()?, + royalty_denominator: bcs::from_bytes(script.args().get(14)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_token_mint(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenMint { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + description: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + uri: bcs::from_bytes(script.args().get(3)?).ok()?, + property_keys: bcs::from_bytes(script.args().get(4)?).ok()?, + property_types: bcs::from_bytes(script.args().get(5)?).ok()?, + property_values: bcs::from_bytes(script.args().get(6)?).ok()?, + }) + } else { + None + } + } + + pub fn aptos_token_mint_soul_bound(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenMintSoulBound { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + description: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + uri: bcs::from_bytes(script.args().get(3)?).ok()?, + property_keys: bcs::from_bytes(script.args().get(4)?).ok()?, + property_types: bcs::from_bytes(script.args().get(5)?).ok()?, + property_values: bcs::from_bytes(script.args().get(6)?).ok()?, + soul_bound_to: bcs::from_bytes(script.args().get(7)?).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( + "aptos_token_create_collection".to_string(), + Box::new(decoder::aptos_token_create_collection), + ); + map.insert( + "aptos_token_mint".to_string(), + Box::new(decoder::aptos_token_mint), + ); + map.insert( + "aptos_token_mint_soul_bound".to_string(), + Box::new(decoder::aptos_token_mint_soul_bound), + ); + map + }); diff --git a/vm/framework/cached-packages/src/starcoin_token_sdk_builder.rs b/vm/framework/cached-packages/src/starcoin_token_sdk_builder.rs new file mode 100644 index 0000000000..85c4ea882b --- /dev/null +++ b/vm/framework/cached-packages/src/starcoin_token_sdk_builder.rs @@ -0,0 +1,1048 @@ +// Copyright © Aptos 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 Aptos transactions (`Script`). +// +// This code was generated by compiling known Script interfaces ("ABIs") with the tool `aptos-sdk-builder`. + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::arc_with_non_send_sync)] +#![allow(clippy::get_first)] +use starcoin_vm_types::{ + account_address::AccountAddress, + transaction::{ScriptFunction, 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 { .. } +/// } +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] +#[cfg_attr(feature = "fuzzing", proptest(no_params))] +pub enum EntryFunctionCall { + /// Burn a token by the token owner + TokenBurn { + creators_address: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, + }, + + /// Burn a token by creator when the token's BURNABLE_BY_CREATOR is true + /// The token is owned at address owner + TokenBurnByCreator { + owner: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, + }, + + /// create a empty token collection with parameters + TokenCreateCollectionScript { + name: Vec, + description: Vec, + uri: Vec, + maximum: u64, + mutate_setting: Vec, + }, + + /// create token with raw inputs + TokenCreateTokenScript { + collection: Vec, + name: Vec, + description: Vec, + balance: u64, + maximum: u64, + uri: Vec, + royalty_payee_address: AccountAddress, + royalty_points_denominator: u64, + royalty_points_numerator: u64, + mutate_setting: Vec, + property_keys: Vec>, + property_values: Vec>, + property_types: Vec>, + }, + + TokenDirectTransferScript { + creators_address: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, + }, + + TokenInitializeTokenScript {}, + + /// Mint more token from an existing token_data. Mint only adds more token to property_version 0 + TokenMintScript { + token_data_address: AccountAddress, + collection: Vec, + name: Vec, + amount: u64, + }, + + /// mutate the token property and save the new property in TokenStore + /// if the token property_version is 0, we will create a new property_version per token to generate a new token_id per token + /// if the token property_version is not 0, we will just update the propertyMap and use the existing token_id (property_version) + TokenMutateTokenProperties { + token_owner: AccountAddress, + creator: AccountAddress, + collection_name: Vec, + token_name: Vec, + token_property_version: u64, + amount: u64, + keys: Vec>, + values: Vec>, + types: Vec>, + }, + + TokenOptInDirectTransfer { + opt_in: bool, + }, + + /// Transfers `amount` of tokens from `from` to `to`. + /// The receiver `to` has to opt-in direct transfer first + TokenTransferWithOptIn { + creator: AccountAddress, + collection_name: Vec, + token_name: Vec, + token_property_version: u64, + to: AccountAddress, + amount: u64, + }, + + /// Token owner lists their token for swapping + TokenCoinSwapListTokenForSwap { + coin_type: TypeTag, + _creators_address: AccountAddress, + _collection: Vec, + _name: Vec, + _property_version: u64, + _token_amount: u64, + _min_coin_per_token: u64, + _locked_until_secs: u64, + }, + + TokenTransfersCancelOfferScript { + receiver: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + }, + + TokenTransfersClaimScript { + sender: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + }, + + TokenTransfersOfferScript { + receiver: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, + }, +} + +impl EntryFunctionCall { + /// Build an Aptos `TransactionPayload` from a structured object `EntryFunctionCall`. + pub fn encode(self) -> TransactionPayload { + use EntryFunctionCall::*; + match self { + TokenBurn { + creators_address, + collection, + name, + property_version, + amount, + } => token_burn(creators_address, collection, name, property_version, amount), + TokenBurnByCreator { + owner, + collection, + name, + property_version, + amount, + } => token_burn_by_creator(owner, collection, name, property_version, amount), + TokenCreateCollectionScript { + name, + description, + uri, + maximum, + mutate_setting, + } => token_create_collection_script(name, description, uri, maximum, mutate_setting), + TokenCreateTokenScript { + collection, + name, + description, + balance, + maximum, + uri, + royalty_payee_address, + royalty_points_denominator, + royalty_points_numerator, + mutate_setting, + property_keys, + property_values, + property_types, + } => token_create_token_script( + collection, + name, + description, + balance, + maximum, + uri, + royalty_payee_address, + royalty_points_denominator, + royalty_points_numerator, + mutate_setting, + property_keys, + property_values, + property_types, + ), + TokenDirectTransferScript { + creators_address, + collection, + name, + property_version, + amount, + } => token_direct_transfer_script( + creators_address, + collection, + name, + property_version, + amount, + ), + TokenInitializeTokenScript {} => token_initialize_token_script(), + TokenMintScript { + token_data_address, + collection, + name, + amount, + } => token_mint_script(token_data_address, collection, name, amount), + TokenMutateTokenProperties { + token_owner, + creator, + collection_name, + token_name, + token_property_version, + amount, + keys, + values, + types, + } => token_mutate_token_properties( + token_owner, + creator, + collection_name, + token_name, + token_property_version, + amount, + keys, + values, + types, + ), + TokenOptInDirectTransfer { opt_in } => token_opt_in_direct_transfer(opt_in), + TokenTransferWithOptIn { + creator, + collection_name, + token_name, + token_property_version, + to, + amount, + } => token_transfer_with_opt_in( + creator, + collection_name, + token_name, + token_property_version, + to, + amount, + ), + TokenCoinSwapListTokenForSwap { + coin_type, + _creators_address, + _collection, + _name, + _property_version, + _token_amount, + _min_coin_per_token, + _locked_until_secs, + } => token_coin_swap_list_token_for_swap( + coin_type, + _creators_address, + _collection, + _name, + _property_version, + _token_amount, + _min_coin_per_token, + _locked_until_secs, + ), + TokenTransfersCancelOfferScript { + receiver, + creator, + collection, + name, + property_version, + } => token_transfers_cancel_offer_script( + receiver, + creator, + collection, + name, + property_version, + ), + TokenTransfersClaimScript { + sender, + creator, + collection, + name, + property_version, + } => token_transfers_claim_script(sender, creator, collection, name, property_version), + TokenTransfersOfferScript { + receiver, + creator, + collection, + name, + property_version, + amount, + } => token_transfers_offer_script( + receiver, + creator, + collection, + name, + property_version, + amount, + ), + } + } + + /// Try to recognize an Aptos `TransactionPayload` and convert it into a structured object `EntryFunctionCall`. + pub fn decode(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + match SCRIPT_FUNCTION_DECODER_MAP.get(&format!( + "{}_{}", + script.module().name(), + script.function() + )) { + Some(decoder) => decoder(payload), + None => None, + } + } else { + None + } + } +} + +/// Burn a token by the token owner +pub fn token_burn( + creators_address: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("burn").to_owned(), + vec![], + vec![ + bcs::to_bytes(&creators_address).unwrap(), + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&property_version).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Burn a token by creator when the token's BURNABLE_BY_CREATOR is true +/// The token is owned at address owner +pub fn token_burn_by_creator( + owner: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("burn_by_creator").to_owned(), + vec![], + vec![ + bcs::to_bytes(&owner).unwrap(), + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&property_version).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// create a empty token collection with parameters +pub fn token_create_collection_script( + name: Vec, + description: Vec, + uri: Vec, + maximum: u64, + mutate_setting: Vec, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::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, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("create_collection_script").to_owned(), + vec![], + vec![ + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&maximum).unwrap(), + bcs::to_bytes(&mutate_setting).unwrap(), + ], + )) +} + +/// create token with raw inputs +pub fn token_create_token_script( + collection: Vec, + name: Vec, + description: Vec, + balance: u64, + maximum: u64, + uri: Vec, + royalty_payee_address: AccountAddress, + royalty_points_denominator: u64, + royalty_points_numerator: u64, + mutate_setting: Vec, + property_keys: Vec>, + property_values: Vec>, + property_types: Vec>, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::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, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("create_token_script").to_owned(), + vec![], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&balance).unwrap(), + bcs::to_bytes(&maximum).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&royalty_payee_address).unwrap(), + bcs::to_bytes(&royalty_points_denominator).unwrap(), + bcs::to_bytes(&royalty_points_numerator).unwrap(), + bcs::to_bytes(&mutate_setting).unwrap(), + bcs::to_bytes(&property_keys).unwrap(), + bcs::to_bytes(&property_values).unwrap(), + bcs::to_bytes(&property_types).unwrap(), + ], + )) +} + +pub fn token_direct_transfer_script( + creators_address: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("direct_transfer_script").to_owned(), + vec![], + vec![ + bcs::to_bytes(&creators_address).unwrap(), + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&property_version).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +pub fn token_initialize_token_script() -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::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, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("initialize_token_script").to_owned(), + vec![], + vec![], + )) +} + +/// Mint more token from an existing token_data. Mint only adds more token to property_version 0 +pub fn token_mint_script( + token_data_address: AccountAddress, + collection: Vec, + name: Vec, + amount: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("mint_script").to_owned(), + vec![], + vec![ + bcs::to_bytes(&token_data_address).unwrap(), + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// mutate the token property and save the new property in TokenStore +/// if the token property_version is 0, we will create a new property_version per token to generate a new token_id per token +/// if the token property_version is not 0, we will just update the propertyMap and use the existing token_id (property_version) +pub fn token_mutate_token_properties( + token_owner: AccountAddress, + creator: AccountAddress, + collection_name: Vec, + token_name: Vec, + token_property_version: u64, + amount: u64, + keys: Vec>, + values: Vec>, + types: Vec>, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::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, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("mutate_token_properties").to_owned(), + vec![], + vec![ + bcs::to_bytes(&token_owner).unwrap(), + bcs::to_bytes(&creator).unwrap(), + bcs::to_bytes(&collection_name).unwrap(), + bcs::to_bytes(&token_name).unwrap(), + bcs::to_bytes(&token_property_version).unwrap(), + bcs::to_bytes(&amount).unwrap(), + bcs::to_bytes(&keys).unwrap(), + bcs::to_bytes(&values).unwrap(), + bcs::to_bytes(&types).unwrap(), + ], + )) +} + +pub fn token_opt_in_direct_transfer(opt_in: bool) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::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, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("opt_in_direct_transfer").to_owned(), + vec![], + vec![bcs::to_bytes(&opt_in).unwrap()], + )) +} + +/// Transfers `amount` of tokens from `from` to `to`. +/// The receiver `to` has to opt-in direct transfer first +pub fn token_transfer_with_opt_in( + creator: AccountAddress, + collection_name: Vec, + token_name: Vec, + token_property_version: u64, + to: AccountAddress, + amount: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token").to_owned(), + ), + ident_str!("transfer_with_opt_in").to_owned(), + vec![], + vec![ + bcs::to_bytes(&creator).unwrap(), + bcs::to_bytes(&collection_name).unwrap(), + bcs::to_bytes(&token_name).unwrap(), + bcs::to_bytes(&token_property_version).unwrap(), + bcs::to_bytes(&to).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + +/// Token owner lists their token for swapping +pub fn token_coin_swap_list_token_for_swap( + coin_type: TypeTag, + _creators_address: AccountAddress, + _collection: Vec, + _name: Vec, + _property_version: u64, + _token_amount: u64, + _min_coin_per_token: u64, + _locked_until_secs: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token_coin_swap").to_owned(), + ), + ident_str!("list_token_for_swap").to_owned(), + vec![coin_type], + vec![ + bcs::to_bytes(&_creators_address).unwrap(), + bcs::to_bytes(&_collection).unwrap(), + bcs::to_bytes(&_name).unwrap(), + bcs::to_bytes(&_property_version).unwrap(), + bcs::to_bytes(&_token_amount).unwrap(), + bcs::to_bytes(&_min_coin_per_token).unwrap(), + bcs::to_bytes(&_locked_until_secs).unwrap(), + ], + )) +} + +pub fn token_transfers_cancel_offer_script( + receiver: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token_transfers").to_owned(), + ), + ident_str!("cancel_offer_script").to_owned(), + vec![], + vec![ + bcs::to_bytes(&receiver).unwrap(), + bcs::to_bytes(&creator).unwrap(), + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&property_version).unwrap(), + ], + )) +} + +pub fn token_transfers_claim_script( + sender: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token_transfers").to_owned(), + ), + ident_str!("claim_script").to_owned(), + vec![], + vec![ + bcs::to_bytes(&sender).unwrap(), + bcs::to_bytes(&creator).unwrap(), + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&property_version).unwrap(), + ], + )) +} + +pub fn token_transfers_offer_script( + receiver: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, +) -> TransactionPayload { + TransactionPayload::ScriptFunction(ScriptFunction::new( + ModuleId::new( + AccountAddress::new([ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + ]), + ident_str!("token_transfers").to_owned(), + ), + ident_str!("offer_script").to_owned(), + vec![], + vec![ + bcs::to_bytes(&receiver).unwrap(), + bcs::to_bytes(&creator).unwrap(), + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&property_version).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} +mod decoder { + use super::*; + pub fn token_burn(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenBurn { + creators_address: bcs::from_bytes(script.args().get(0)?).ok()?, + collection: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + property_version: bcs::from_bytes(script.args().get(3)?).ok()?, + amount: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn token_burn_by_creator(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenBurnByCreator { + owner: bcs::from_bytes(script.args().get(0)?).ok()?, + collection: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + property_version: bcs::from_bytes(script.args().get(3)?).ok()?, + amount: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn token_create_collection_script( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenCreateCollectionScript { + name: bcs::from_bytes(script.args().get(0)?).ok()?, + description: bcs::from_bytes(script.args().get(1)?).ok()?, + uri: bcs::from_bytes(script.args().get(2)?).ok()?, + maximum: bcs::from_bytes(script.args().get(3)?).ok()?, + mutate_setting: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn token_create_token_script(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenCreateTokenScript { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + description: bcs::from_bytes(script.args().get(2)?).ok()?, + balance: bcs::from_bytes(script.args().get(3)?).ok()?, + maximum: bcs::from_bytes(script.args().get(4)?).ok()?, + uri: bcs::from_bytes(script.args().get(5)?).ok()?, + royalty_payee_address: bcs::from_bytes(script.args().get(6)?).ok()?, + royalty_points_denominator: bcs::from_bytes(script.args().get(7)?).ok()?, + royalty_points_numerator: bcs::from_bytes(script.args().get(8)?).ok()?, + mutate_setting: bcs::from_bytes(script.args().get(9)?).ok()?, + property_keys: bcs::from_bytes(script.args().get(10)?).ok()?, + property_values: bcs::from_bytes(script.args().get(11)?).ok()?, + property_types: bcs::from_bytes(script.args().get(12)?).ok()?, + }) + } else { + None + } + } + + pub fn token_direct_transfer_script(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenDirectTransferScript { + creators_address: bcs::from_bytes(script.args().get(0)?).ok()?, + collection: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + property_version: bcs::from_bytes(script.args().get(3)?).ok()?, + amount: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn token_initialize_token_script( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::ScriptFunction(_script) = payload { + Some(EntryFunctionCall::TokenInitializeTokenScript {}) + } else { + None + } + } + + pub fn token_mint_script(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenMintScript { + token_data_address: bcs::from_bytes(script.args().get(0)?).ok()?, + collection: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + amount: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } + } + + pub fn token_mutate_token_properties( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenMutateTokenProperties { + token_owner: bcs::from_bytes(script.args().get(0)?).ok()?, + creator: bcs::from_bytes(script.args().get(1)?).ok()?, + collection_name: bcs::from_bytes(script.args().get(2)?).ok()?, + token_name: bcs::from_bytes(script.args().get(3)?).ok()?, + token_property_version: bcs::from_bytes(script.args().get(4)?).ok()?, + amount: bcs::from_bytes(script.args().get(5)?).ok()?, + keys: bcs::from_bytes(script.args().get(6)?).ok()?, + values: bcs::from_bytes(script.args().get(7)?).ok()?, + types: bcs::from_bytes(script.args().get(8)?).ok()?, + }) + } else { + None + } + } + + pub fn token_opt_in_direct_transfer(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenOptInDirectTransfer { + opt_in: bcs::from_bytes(script.args().get(0)?).ok()?, + }) + } else { + None + } + } + + pub fn token_transfer_with_opt_in(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenTransferWithOptIn { + creator: bcs::from_bytes(script.args().get(0)?).ok()?, + collection_name: bcs::from_bytes(script.args().get(1)?).ok()?, + token_name: bcs::from_bytes(script.args().get(2)?).ok()?, + token_property_version: bcs::from_bytes(script.args().get(3)?).ok()?, + to: bcs::from_bytes(script.args().get(4)?).ok()?, + amount: bcs::from_bytes(script.args().get(5)?).ok()?, + }) + } else { + None + } + } + + pub fn token_coin_swap_list_token_for_swap( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenCoinSwapListTokenForSwap { + coin_type: script.ty_args().get(0)?.clone(), + _creators_address: bcs::from_bytes(script.args().get(0)?).ok()?, + _collection: bcs::from_bytes(script.args().get(1)?).ok()?, + _name: bcs::from_bytes(script.args().get(2)?).ok()?, + _property_version: bcs::from_bytes(script.args().get(3)?).ok()?, + _token_amount: bcs::from_bytes(script.args().get(4)?).ok()?, + _min_coin_per_token: bcs::from_bytes(script.args().get(5)?).ok()?, + _locked_until_secs: bcs::from_bytes(script.args().get(6)?).ok()?, + }) + } else { + None + } + } + + pub fn token_transfers_cancel_offer_script( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenTransfersCancelOfferScript { + receiver: bcs::from_bytes(script.args().get(0)?).ok()?, + creator: bcs::from_bytes(script.args().get(1)?).ok()?, + collection: bcs::from_bytes(script.args().get(2)?).ok()?, + name: bcs::from_bytes(script.args().get(3)?).ok()?, + property_version: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn token_transfers_claim_script(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenTransfersClaimScript { + sender: bcs::from_bytes(script.args().get(0)?).ok()?, + creator: bcs::from_bytes(script.args().get(1)?).ok()?, + collection: bcs::from_bytes(script.args().get(2)?).ok()?, + name: bcs::from_bytes(script.args().get(3)?).ok()?, + property_version: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } + } + + pub fn token_transfers_offer_script(payload: &TransactionPayload) -> Option { + if let TransactionPayload::ScriptFunction(script) = payload { + Some(EntryFunctionCall::TokenTransfersOfferScript { + receiver: bcs::from_bytes(script.args().get(0)?).ok()?, + creator: bcs::from_bytes(script.args().get(1)?).ok()?, + collection: bcs::from_bytes(script.args().get(2)?).ok()?, + name: bcs::from_bytes(script.args().get(3)?).ok()?, + property_version: bcs::from_bytes(script.args().get(4)?).ok()?, + amount: bcs::from_bytes(script.args().get(5)?).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("token_burn".to_string(), Box::new(decoder::token_burn)); + map.insert( + "token_burn_by_creator".to_string(), + Box::new(decoder::token_burn_by_creator), + ); + map.insert( + "token_create_collection_script".to_string(), + Box::new(decoder::token_create_collection_script), + ); + map.insert( + "token_create_token_script".to_string(), + Box::new(decoder::token_create_token_script), + ); + map.insert( + "token_direct_transfer_script".to_string(), + Box::new(decoder::token_direct_transfer_script), + ); + map.insert( + "token_initialize_token_script".to_string(), + Box::new(decoder::token_initialize_token_script), + ); + map.insert( + "token_mint_script".to_string(), + Box::new(decoder::token_mint_script), + ); + map.insert( + "token_mutate_token_properties".to_string(), + Box::new(decoder::token_mutate_token_properties), + ); + map.insert( + "token_opt_in_direct_transfer".to_string(), + Box::new(decoder::token_opt_in_direct_transfer), + ); + map.insert( + "token_transfer_with_opt_in".to_string(), + Box::new(decoder::token_transfer_with_opt_in), + ); + map.insert( + "token_coin_swap_list_token_for_swap".to_string(), + Box::new(decoder::token_coin_swap_list_token_for_swap), + ); + map.insert( + "token_transfers_cancel_offer_script".to_string(), + Box::new(decoder::token_transfers_cancel_offer_script), + ); + map.insert( + "token_transfers_claim_script".to_string(), + Box::new(decoder::token_transfers_claim_script), + ); + map.insert( + "token_transfers_offer_script".to_string(), + Box::new(decoder::token_transfers_offer_script), + ); + map + }); diff --git a/vm/framework/src/built_package.rs b/vm/framework/src/built_package.rs index 3a8c182311..ca5233ad60 100644 --- a/vm/framework/src/built_package.rs +++ b/vm/framework/src/built_package.rs @@ -1,566 +1,514 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -// -// use crate::{ -// docgen::{get_docgen_output_dir, DocgenOptions}, -// extended_checks, -// natives::code::{ModuleMetadata, MoveOption, PackageDep, PackageMetadata, UpgradePolicy}, -// zip_metadata, zip_metadata_str, RuntimeModuleMetadataV1, APTOS_METADATA_KEY, -// APTOS_METADATA_KEY_V1, METADATA_V1_MIN_FILE_FORMAT_VERSION, -// }; -// use anyhow::bail; -// use starcoin_types::{account_address::AccountAddress, transaction::EntryABI}; -// use clap::Parser; -// use codespan_reporting::{ -// diagnostic::Severity, -// term::termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}, -// }; -// use itertools::Itertools; -// use move_binary_format::{file_format_common::VERSION_7, CompiledModule}; -// use move_command_line_common::files::MOVE_COMPILED_EXTENSION; -// use move_compiler::compiled_unit::{CompiledUnit, NamedCompiledModule}; -// use move_compiler_v2::{options::Options, Experiment}; -// use move_core_types::{language_storage::ModuleId, metadata::Metadata}; -// use move_model::{ -// metadata::{CompilerVersion, LanguageVersion}, -// model::GlobalEnv, -// }; -// use move_package::{ -// compilation::{compiled_package::CompiledPackage, package_layout::CompiledPackageLayout}, -// source_package::{ -// manifest_parser::{parse_move_manifest_string, parse_source_manifest}, -// std_lib::StdVersion, -// }, -// BuildConfig, CompilerConfig, ModelConfig, -// }; -// use serde::{Deserialize, Serialize}; -// use std::{ -// collections::{BTreeMap, BTreeSet}, -// io::{stderr, Write}, -// path::{Path, PathBuf}, -// }; -// -// pub const METADATA_FILE_NAME: &str = "package-metadata.bcs"; -// pub const UPGRADE_POLICY_CUSTOM_FIELD: &str = "upgrade_policy"; -// -// pub const STARCOIN_PACKAGES: [&str; 5] = [ -// "AptosFramework", -// "MoveStdlib", -// "AptosStdlib", -// "AptosToken", -// "AptosTokenObjects", -// ]; -// -// /// Represents a set of options for building artifacts from Move. -// #[derive(Debug, Clone, Parser, Serialize, Deserialize)] -// pub struct BuildOptions { -// /// Enables dev mode, which uses all dev-addresses and dev-dependencies -// /// -// /// Dev mode allows for changing dependencies and addresses to the preset [dev-addresses] and -// /// [dev-dependencies] fields. This works both inside and out of tests for using preset values. -// /// -// /// Currently, it also additionally pulls in all test compilation artifacts -// #[clap(long)] -// pub dev: bool, -// #[clap(long)] -// pub with_srcs: bool, -// #[clap(long)] -// pub with_abis: bool, -// #[clap(long)] -// pub with_source_maps: bool, -// #[clap(long, default_value_t = true)] -// pub with_error_map: bool, -// #[clap(long)] -// pub with_docs: bool, -// /// Installation directory for compiled artifacts. Defaults to `/build`. -// #[clap(long, value_parser)] -// pub install_dir: Option, -// #[clap(skip)] // TODO: have a parser for this; there is one in the CLI buts its downstream -// pub named_addresses: BTreeMap, -// /// Whether to override the standard library with the given version. -// #[clap(long, value_parser)] -// pub override_std: Option, -// #[clap(skip)] -// pub docgen_options: Option, -// #[clap(long)] -// pub skip_fetch_latest_git_deps: bool, -// #[clap(long, default_value_if("move_2", "true", "7"))] -// pub bytecode_version: Option, -// #[clap(long, value_parser = clap::value_parser!(CompilerVersion), -// default_value_if("move_2", "true", "2.0"))] -// pub compiler_version: Option, -// #[clap(long, value_parser = clap::value_parser!(LanguageVersion), -// default_value_if("move_2", "true", "2.0"))] -// pub language_version: Option, -// #[clap(long)] -// pub skip_attribute_checks: bool, -// #[clap(long)] -// pub check_test_code: bool, -// #[clap(skip)] -// pub known_attributes: BTreeSet, -// #[clap(skip)] -// pub experiments: Vec, -// /// Select bytecode, language, compiler for Move 2 -// #[clap(long)] -// pub move_2: bool, -// } -// -// // Because named_addresses has no parser, we can't use clap's default impl. This must be aligned -// // with defaults above. -// impl Default for BuildOptions { -// fn default() -> Self { -// Self { -// dev: false, -// with_srcs: false, -// with_abis: false, -// with_source_maps: false, -// with_error_map: true, -// with_docs: false, -// install_dir: None, -// named_addresses: Default::default(), -// override_std: None, -// docgen_options: None, -// // This is false by default, because it could accidentally pull new dependencies -// // while in a test (and cause some havoc) -// skip_fetch_latest_git_deps: false, -// bytecode_version: None, -// compiler_version: None, -// language_version: None, -// skip_attribute_checks: false, -// check_test_code: false, -// known_attributes: extended_checks::get_all_attribute_names().clone(), -// experiments: vec![], -// move_2: false, -// } -// } -// } -// -// impl BuildOptions { -// pub fn move_2() -> Self { -// BuildOptions { -// bytecode_version: Some(VERSION_7), -// language_version: Some(LanguageVersion::V2_0), -// compiler_version: Some(CompilerVersion::V2_0), -// ..Self::default() -// } -// } -// -// pub fn inferred_bytecode_version(&self) -> u32 { -// self.language_version -// .unwrap_or_default() -// .infer_bytecode_version(self.bytecode_version) -// } -// -// pub fn with_experiment(mut self, exp: &str) -> Self { -// self.experiments.push(exp.to_string()); -// self -// } -// } -// -// /// Represents a built package. It allows to extract `PackageMetadata`. Can also be used to -// /// just build Move code and related artifacts. -// pub struct BuiltPackage { -// options: BuildOptions, -// package_path: PathBuf, -// pub package: CompiledPackage, -// } -// -// pub fn build_model( -// dev_mode: bool, -// package_path: &Path, -// additional_named_addresses: BTreeMap, -// target_filter: Option, -// bytecode_version: Option, -// compiler_version: Option, -// language_version: Option, -// skip_attribute_checks: bool, -// known_attributes: BTreeSet, -// experiments: Vec, -// ) -> anyhow::Result { -// let bytecode_version = Some( -// language_version -// .unwrap_or_default() -// .infer_bytecode_version(bytecode_version), -// ); -// let build_config = BuildConfig { -// dev_mode, -// additional_named_addresses, -// architecture: None, -// generate_abis: false, -// generate_docs: false, -// generate_move_model: false, -// full_model_generation: false, -// install_dir: None, -// test_mode: false, -// override_std: None, -// force_recompilation: false, -// fetch_deps_only: false, -// skip_fetch_latest_git_deps: true, -// compiler_config: CompilerConfig { -// bytecode_version, -// compiler_version, -// language_version, -// skip_attribute_checks, -// known_attributes, -// experiments, -// }, -// }; -// let compiler_version = compiler_version.unwrap_or_default(); -// let language_version = language_version.unwrap_or_default(); -// compiler_version.check_language_support(language_version)?; -// build_config.move_model_for_package(package_path, ModelConfig { -// target_filter, -// all_files_as_targets: false, -// compiler_version, -// language_version, -// }) -// } -// -// impl BuiltPackage { -// /// Builds the package and on success delivers a `BuiltPackage`. -// /// -// /// This function currently reports all Move compilation errors and warnings to stdout, -// /// and is not `Ok` if there was an error among those. -// pub fn build(package_path: PathBuf, options: BuildOptions) -> anyhow::Result { -// let bytecode_version = Some(options.inferred_bytecode_version()); -// let compiler_version = options.compiler_version; -// let language_version = options.language_version; -// Self::check_versions(&compiler_version, &language_version)?; -// let skip_attribute_checks = options.skip_attribute_checks; -// let build_config = BuildConfig { -// dev_mode: options.dev, -// additional_named_addresses: options.named_addresses.clone(), -// architecture: None, -// generate_abis: options.with_abis, -// generate_docs: false, -// generate_move_model: true, -// full_model_generation: options.check_test_code, -// install_dir: options.install_dir.clone(), -// test_mode: false, -// override_std: options.override_std.clone(), -// force_recompilation: false, -// fetch_deps_only: false, -// skip_fetch_latest_git_deps: options.skip_fetch_latest_git_deps, -// compiler_config: CompilerConfig { -// bytecode_version, -// compiler_version, -// language_version, -// skip_attribute_checks, -// known_attributes: options.known_attributes.clone(), -// experiments: options.experiments.clone(), -// }, -// }; -// -// eprintln!("Compiling, may take a little while to download git dependencies..."); -// let (mut package, model_opt) = -// build_config.compile_package_no_exit(&package_path, &mut stderr())?; -// -// // Run extended checks as well derive runtime metadata -// let model = &model_opt.expect("move model"); -// -// if let Some(model_options) = model.get_extension::() { -// if model_options.experiment_on(Experiment::STOP_BEFORE_EXTENDED_CHECKS) { -// std::process::exit(0) -// } -// } -// -// let runtime_metadata = extended_checks::run_extended_checks(model); -// if model.diag_count(Severity::Warning) > 0 { -// let mut error_writer = StandardStream::stderr(ColorChoice::Auto); -// model.report_diag(&mut error_writer, Severity::Warning); -// if model.has_errors() { -// bail!("extended checks failed") -// } -// } -// -// if let Some(model_options) = model.get_extension::() { -// if model_options.experiment_on(Experiment::STOP_AFTER_EXTENDED_CHECKS) { -// std::process::exit(0) -// } -// } -// -// let compiled_pkg_path = package -// .compiled_package_info -// .build_flags -// .install_dir -// .as_ref() -// .unwrap_or(&package_path) -// .join(CompiledPackageLayout::Root.path()) -// .join(package.compiled_package_info.package_name.as_str()); -// inject_runtime_metadata( -// compiled_pkg_path, -// &mut package, -// runtime_metadata, -// bytecode_version, -// )?; -// -// // If enabled generate docs. -// if options.with_docs { -// let docgen = if let Some(opts) = options.docgen_options.clone() { -// opts -// } else { -// DocgenOptions::default() -// }; -// let dep_paths = package -// .deps_compiled_units -// .iter() -// .map(|(_, u)| { -// u.source_path -// .parent() -// .unwrap() -// .parent() -// .unwrap() -// .join(get_docgen_output_dir()) -// .display() -// .to_string() -// }) -// .unique() -// .collect::>(); -// docgen.run(package_path.display().to_string(), dep_paths, model)? -// } -// -// Ok(Self { -// options, -// package_path, -// package, -// }) -// } -// -// // Check versions and warn user if using unstable ones. -// fn check_versions( -// compiler_version: &Option, -// language_version: &Option, -// ) -> anyhow::Result<()> { -// let effective_compiler_version = compiler_version.unwrap_or_default(); -// let effective_language_version = language_version.unwrap_or_default(); -// let mut error_writer = StandardStream::stderr(ColorChoice::Auto); -// if effective_compiler_version.unstable() { -// error_writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; -// writeln!( -// &mut error_writer, -// "Warning: compiler version `{}` is experimental \ -// and should not be used in production", -// effective_compiler_version -// )?; -// error_writer.reset()?; -// } -// if effective_language_version.unstable() { -// error_writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; -// writeln!( -// &mut error_writer, -// "Warning: language version `{}` is experimental \ -// and should not be used in production", -// effective_language_version -// )?; -// error_writer.reset()?; -// } -// effective_compiler_version.check_language_support(effective_language_version)?; -// Ok(()) -// } -// -// /// Returns the name of this package. -// pub fn name(&self) -> &str { -// self.package.compiled_package_info.package_name.as_str() -// } -// -// pub fn package_path(&self) -> &Path { -// self.package_path.as_path() -// } -// -// pub fn package_artifacts_path(&self) -> PathBuf { -// self.package_path -// .join(CompiledPackageLayout::Root.path()) -// .join(self.name()) -// } -// -// /// Extracts the bytecode for the modules of the built package. -// pub fn extract_code(&self) -> Vec> { -// self.package -// .root_modules() -// .map(|unit_with_source| { -// let bytecode_version = self.options.inferred_bytecode_version(); -// unit_with_source.unit.serialize(Some(bytecode_version)) -// }) -// .collect() -// } -// -// /// Returns the abis for this package, if available. -// pub fn extract_abis(&self) -> Option> { -// self.package.compiled_abis.as_ref().map(|abis| { -// abis.iter() -// .map(|(_, bytes)| bcs::from_bytes::(bytes.as_slice()).unwrap()) -// .collect() -// }) -// } -// -// /// Returns an iterator for all compiled proper (non-script) modules. -// pub fn modules(&self) -> impl Iterator { -// self.package -// .root_modules() -// .filter_map(|unit| match &unit.unit { -// CompiledUnit::Module(NamedCompiledModule { module, .. }) => Some(module), -// CompiledUnit::Script(_) => None, -// }) -// } -// -// /// Returns an iterator for all compiled proper (non-script) modules, including -// /// modules that are dependencies of the root modules. -// pub fn all_modules(&self) -> impl Iterator { -// self.package -// .all_modules() -// .filter_map(|unit| match &unit.unit { -// CompiledUnit::Module(NamedCompiledModule { module, .. }) => Some(module), -// CompiledUnit::Script(_) => None, -// }) -// } -// -// /// Returns the number of scripts in the package. -// pub fn script_count(&self) -> usize { -// self.package.scripts().count() -// } -// -// /// Returns the serialized bytecode of the scripts in the package. -// pub fn extract_script_code(&self) -> Vec> { -// self.package -// .scripts() -// .map(|unit_with_source| { -// unit_with_source -// .unit -// .serialize(Some(self.options.inferred_bytecode_version())) -// }) -// .collect() -// } -// -// /// Extracts metadata, as needed for releasing a package, from the built package. -// pub fn extract_metadata(&self) -> anyhow::Result { -// let source_digest = self -// .package -// .compiled_package_info -// .source_digest -// .map(|s| s.to_string()) -// .unwrap_or_default(); -// let manifest_file = self.package_path.join("Move.toml"); -// let manifest = std::fs::read_to_string(manifest_file)?; -// let custom_props = extract_custom_fields(&manifest)?; -// let manifest = zip_metadata_str(&manifest)?; -// let upgrade_policy = if let Some(val) = custom_props.get(UPGRADE_POLICY_CUSTOM_FIELD) { -// str::parse::(val.as_ref())? -// } else { -// UpgradePolicy::compat() -// }; -// let mut modules = vec![]; -// for u in self.package.root_modules() { -// let name = u.unit.name().to_string(); -// let source = if self.options.with_srcs { -// zip_metadata_str(&std::fs::read_to_string(&u.source_path)?)? -// } else { -// vec![] -// }; -// let source_map = if self.options.with_source_maps { -// zip_metadata(&u.unit.serialize_source_map())? -// } else { -// vec![] -// }; -// modules.push(ModuleMetadata { -// name, -// source, -// source_map, -// extension: MoveOption::default(), -// }) -// } -// let deps = self -// .package -// .deps_compiled_units -// .iter() -// .map(|(name, unit)| { -// let package_name = name.as_str().to_string(); -// let account = match &unit.unit { -// CompiledUnit::Module(m) => AccountAddress::new(m.address.into_bytes()), -// _ => panic!("script not a dependency"), -// }; -// PackageDep { -// account, -// package_name, -// } -// }) -// .collect::>() -// .into_iter() -// .collect(); -// Ok(PackageMetadata { -// name: self.name().to_string(), -// upgrade_policy, -// upgrade_number: 0, -// source_digest, -// manifest, -// modules, -// deps, -// extension: MoveOption::none(), -// }) -// } -// -// pub fn extract_metadata_and_save(&self) -> anyhow::Result<()> { -// let data = self.extract_metadata()?; -// let path = self.package_artifacts_path(); -// std::fs::create_dir_all(&path)?; -// std::fs::write(path.join(METADATA_FILE_NAME), bcs::to_bytes(&data)?)?; -// Ok(()) -// } -// } -// -// fn extract_custom_fields(toml: &str) -> anyhow::Result> { -// let manifest = parse_source_manifest(parse_move_manifest_string(toml.to_owned())?)?; -// Ok(manifest -// .package -// .custom_properties -// .iter() -// .map(|(s, v)| (s.to_string(), v.to_string())) -// .collect()) -// } -// -// fn inject_runtime_metadata( -// package_path: PathBuf, -// pack: &mut CompiledPackage, -// metadata: BTreeMap, -// bytecode_version: Option, -// ) -> anyhow::Result<()> { -// for unit_with_source in pack.root_compiled_units.iter_mut() { -// match &mut unit_with_source.unit { -// CompiledUnit::Module(named_module) => { -// if let Some(module_metadata) = metadata.get(&named_module.module.self_id()) { -// if !module_metadata.is_empty() { -// if bytecode_version.unwrap_or(METADATA_V1_MIN_FILE_FORMAT_VERSION) -// >= METADATA_V1_MIN_FILE_FORMAT_VERSION -// { -// let serialized_metadata = bcs::to_bytes(&module_metadata) -// .expect("BCS for RuntimeModuleMetadata"); -// named_module.module.metadata.push(Metadata { -// key: APTOS_METADATA_KEY_V1.to_vec(), -// value: serialized_metadata, -// }); -// } else { -// let serialized_metadata = -// bcs::to_bytes(&module_metadata.clone().downgrade()) -// .expect("BCS for RuntimeModuleMetadata"); -// named_module.module.metadata.push(Metadata { -// key: APTOS_METADATA_KEY.to_vec(), -// value: serialized_metadata, -// }); -// } -// -// // Also need to update the .mv file on disk. -// let path = package_path -// .join(CompiledPackageLayout::CompiledModules.path()) -// .join(named_module.name.as_str()) -// .with_extension(MOVE_COMPILED_EXTENSION); -// if path.is_file() { -// let bytes = unit_with_source.unit.serialize(bytecode_version); -// std::fs::write(path, bytes)?; -// } -// } -// } -// }, -// CompiledUnit::Script(_) => {}, -// } -// } -// Ok(()) -// } + +use crate::{ + docgen::DocgenOptions, + extended_checks, + natives::code::{ModuleMetadata, MoveOption, PackageDep, PackageMetadata, UpgradePolicy}, + zip_metadata, zip_metadata_str, RuntimeModuleMetadataV1, APTOS_METADATA_KEY, + APTOS_METADATA_KEY_V1, METADATA_V1_MIN_FILE_FORMAT_VERSION, +}; +use anyhow::bail; +use starcoin_vm_types::{account_address::AccountAddress, transaction::EntryABI}; +use clap::Parser; +use codespan_reporting::{ + diagnostic::Severity, + term::termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}, +}; +use itertools::Itertools; +use move_binary_format::CompiledModule; +use move_command_line_common::files::MOVE_COMPILED_EXTENSION; +use move_compiler::compiled_unit::{CompiledUnit, NamedCompiledModule}; +use move_core_types::{language_storage::ModuleId, metadata::Metadata}; +use move_model::{ + metadata::{CompilerVersion, LanguageVersion}, + model::GlobalEnv, +}; +use move_package::{ + compilation::{compiled_package::CompiledPackage, package_layout::CompiledPackageLayout}, + source_package::{ + manifest_parser::{parse_move_manifest_string, parse_source_manifest}, + std_lib::StdVersion, + }, + BuildConfig, CompilerConfig, ModelConfig, +}; +use serde::{Deserialize, Serialize}; +use std::{ + collections::{BTreeMap, BTreeSet}, + io::{stderr, Write}, + path::{Path, PathBuf}, +}; + +pub const METADATA_FILE_NAME: &str = "package-metadata.bcs"; +pub const UPGRADE_POLICY_CUSTOM_FIELD: &str = "upgrade_policy"; + +pub const APTOS_PACKAGES: [&str; 5] = [ + "AptosFramework", + "MoveStdlib", + "AptosStdlib", + "AptosToken", + "AptosTokenObjects", +]; + +/// Represents a set of options for building artifacts from Move. +#[derive(Debug, Clone, Parser, Serialize, Deserialize)] +pub struct BuildOptions { + /// Enables dev mode, which uses all dev-addresses and dev-dependencies + /// + /// Dev mode allows for changing dependencies and addresses to the preset [dev-addresses] and + /// [dev-dependencies] fields. This works both inside and out of tests for using preset values. + /// + /// Currently, it also additionally pulls in all test compilation artifacts + #[clap(long)] + pub dev: bool, + #[clap(long)] + pub with_srcs: bool, + #[clap(long)] + pub with_abis: bool, + #[clap(long)] + pub with_source_maps: bool, + #[clap(long, default_value_t = true)] + pub with_error_map: bool, + #[clap(long)] + pub with_docs: bool, + /// Installation directory for compiled artifacts. Defaults to `/build`. + #[clap(long, value_parser)] + pub install_dir: Option, + #[clap(skip)] // TODO: have a parser for this; there is one in the CLI buts its downstream + pub named_addresses: BTreeMap, + /// Whether to override the standard library with the given version. + #[clap(long, value_parser)] + pub override_std: Option, + #[clap(skip)] + pub docgen_options: Option, + #[clap(long)] + pub skip_fetch_latest_git_deps: bool, + #[clap(long)] + pub bytecode_version: Option, + #[clap(long, value_parser = clap::value_parser!(CompilerVersion))] + pub compiler_version: Option, + #[clap(long, value_parser = clap::value_parser!(LanguageVersion))] + pub language_version: Option, + #[clap(long)] + pub skip_attribute_checks: bool, + #[clap(long)] + pub check_test_code: bool, + #[clap(skip)] + pub known_attributes: BTreeSet, +} + +// Because named_addresses has no parser, we can't use clap's default impl. This must be aligned +// with defaults above. +impl Default for BuildOptions { + fn default() -> Self { + Self { + dev: false, + with_srcs: false, + with_abis: false, + with_source_maps: false, + with_error_map: true, + with_docs: false, + install_dir: None, + named_addresses: Default::default(), + override_std: None, + docgen_options: None, + // This is false by default, because it could accidentally pull new dependencies + // while in a test (and cause some havoc) + skip_fetch_latest_git_deps: false, + bytecode_version: None, + compiler_version: None, + language_version: None, + skip_attribute_checks: false, + check_test_code: false, + known_attributes: extended_checks::get_all_attribute_names().clone(), + } + } +} + +/// Represents a built package. It allows to extract `PackageMetadata`. Can also be used to +/// just build Move code and related artifacts. +pub struct BuiltPackage { + options: BuildOptions, + package_path: PathBuf, + pub package: CompiledPackage, +} + +pub fn build_model( + dev_mode: bool, + package_path: &Path, + additional_named_addresses: BTreeMap, + target_filter: Option, + bytecode_version: Option, + compiler_version: Option, + language_version: Option, + skip_attribute_checks: bool, + known_attributes: BTreeSet, +) -> anyhow::Result { + let build_config = BuildConfig { + dev_mode, + additional_named_addresses, + architecture: None, + generate_abis: false, + generate_docs: false, + generate_move_model: false, + full_model_generation: false, + install_dir: None, + test_mode: false, + override_std: None, + force_recompilation: false, + fetch_deps_only: false, + skip_fetch_latest_git_deps: true, + compiler_config: CompilerConfig { + bytecode_version, + compiler_version, + language_version, + skip_attribute_checks, + known_attributes, + }, + }; + let compiler_version = compiler_version.unwrap_or_default(); + let language_version = language_version.unwrap_or_default(); + compiler_version.check_language_support(language_version)?; + build_config.move_model_for_package(package_path, ModelConfig { + target_filter, + all_files_as_targets: false, + compiler_version, + language_version, + }) +} + +impl BuiltPackage { + /// Builds the package and on success delivers a `BuiltPackage`. + /// + /// This function currently reports all Move compilation errors and warnings to stdout, + /// and is not `Ok` if there was an error among those. + pub fn build(package_path: PathBuf, options: BuildOptions) -> anyhow::Result { + let bytecode_version = options.bytecode_version; + let compiler_version = options.compiler_version; + let language_version = options.language_version; + Self::check_versions(&compiler_version, &language_version)?; + let skip_attribute_checks = options.skip_attribute_checks; + let build_config = BuildConfig { + dev_mode: options.dev, + additional_named_addresses: options.named_addresses.clone(), + architecture: None, + generate_abis: options.with_abis, + generate_docs: false, + generate_move_model: true, + full_model_generation: options.check_test_code, + install_dir: options.install_dir.clone(), + test_mode: false, + override_std: options.override_std.clone(), + force_recompilation: false, + fetch_deps_only: false, + skip_fetch_latest_git_deps: options.skip_fetch_latest_git_deps, + compiler_config: CompilerConfig { + bytecode_version, + compiler_version, + language_version, + skip_attribute_checks, + known_attributes: options.known_attributes.clone(), + }, + }; + + eprintln!("Compiling, may take a little while to download git dependencies..."); + let (mut package, model_opt) = + build_config.compile_package_no_exit(&package_path, &mut stderr())?; + + // Run extended checks as well derive runtime metadata + let model = &model_opt.expect("move model"); + let runtime_metadata = extended_checks::run_extended_checks(model); + if model.diag_count(Severity::Warning) > 0 { + let mut error_writer = StandardStream::stderr(ColorChoice::Auto); + model.report_diag(&mut error_writer, Severity::Warning); + if model.has_errors() { + bail!("extended checks failed") + } + } + + let compiled_pkg_path = package + .compiled_package_info + .build_flags + .install_dir + .as_ref() + .unwrap_or(&package_path) + .join(CompiledPackageLayout::Root.path()) + .join(package.compiled_package_info.package_name.as_str()); + inject_runtime_metadata( + compiled_pkg_path, + &mut package, + runtime_metadata, + bytecode_version, + )?; + + // If enabled generate docs. + if options.with_docs { + let docgen = if let Some(opts) = options.docgen_options.clone() { + opts + } else { + DocgenOptions::default() + }; + let dep_paths = package + .deps_compiled_units + .iter() + .map(|(_, u)| { + u.source_path + .parent() + .unwrap() + .parent() + .unwrap() + .join("doc") + .display() + .to_string() + }) + .unique() + .collect::>(); + docgen.run(package_path.display().to_string(), dep_paths, model)? + } + + Ok(Self { + options, + package_path, + package, + }) + } + + // Check versions and warn user if using unstable ones. + fn check_versions( + compiler_version: &Option, + language_version: &Option, + ) -> anyhow::Result<()> { + let effective_compiler_version = compiler_version.unwrap_or_default(); + let effective_language_version = language_version.unwrap_or_default(); + let mut error_writer = StandardStream::stderr(ColorChoice::Auto); + if effective_compiler_version.unstable() { + error_writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + writeln!( + &mut error_writer, + "Warning: compiler version `{}` is experimental \ + and should not be used in production", + effective_compiler_version + )?; + error_writer.reset()?; + } + if effective_language_version.unstable() { + error_writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + writeln!( + &mut error_writer, + "Warning: language version `{}` is experimental \ + and should not be used in production", + effective_language_version + )?; + error_writer.reset()?; + } + effective_compiler_version.check_language_support(effective_language_version)?; + Ok(()) + } + + /// Returns the name of this package. + pub fn name(&self) -> &str { + self.package.compiled_package_info.package_name.as_str() + } + + pub fn package_path(&self) -> &Path { + self.package_path.as_path() + } + + pub fn package_artifacts_path(&self) -> PathBuf { + self.package_path + .join(CompiledPackageLayout::Root.path()) + .join(self.name()) + } + + /// Extracts the bytecode for the modules of the built package. + pub fn extract_code(&self) -> Vec> { + self.package + .root_modules() + .map(|unit_with_source| { + unit_with_source + .unit + .serialize(self.options.bytecode_version) + }) + .collect() + } + + /// Returns the abis for this package, if available. + pub fn extract_abis(&self) -> Option> { + self.package.compiled_abis.as_ref().map(|abis| { + abis.iter() + .map(|(_, bytes)| bcs::from_bytes::(bytes.as_slice()).unwrap()) + .collect() + }) + } + + /// Returns an iterator for all compiled proper (non-script) modules. + pub fn modules(&self) -> impl Iterator { + self.package + .root_modules() + .filter_map(|unit| match &unit.unit { + CompiledUnit::Module(NamedCompiledModule { module, .. }) => Some(module), + CompiledUnit::Script(_) => None, + }) + } + + /// Returns an iterator for all compiled proper (non-script) modules, including + /// modules that are dependencies of the root modules. + pub fn all_modules(&self) -> impl Iterator { + self.package + .all_modules() + .filter_map(|unit| match &unit.unit { + CompiledUnit::Module(NamedCompiledModule { module, .. }) => Some(module), + CompiledUnit::Script(_) => None, + }) + } + + /// Returns the number of scripts in the package. + pub fn script_count(&self) -> usize { + self.package.scripts().count() + } + + /// Returns the serialized bytecode of the scripts in the package. + pub fn extract_script_code(&self) -> Vec> { + self.package + .scripts() + .map(|unit_with_source| { + unit_with_source + .unit + .serialize(self.options.bytecode_version) + }) + .collect() + } + + /// Extracts metadata, as needed for releasing a package, from the built package. + pub fn extract_metadata(&self) -> anyhow::Result { + let source_digest = self + .package + .compiled_package_info + .source_digest + .map(|s| s.to_string()) + .unwrap_or_default(); + let manifest_file = self.package_path.join("Move.toml"); + let manifest = std::fs::read_to_string(manifest_file)?; + let custom_props = extract_custom_fields(&manifest)?; + let manifest = zip_metadata_str(&manifest)?; + let upgrade_policy = if let Some(val) = custom_props.get(UPGRADE_POLICY_CUSTOM_FIELD) { + str::parse::(val.as_ref())? + } else { + UpgradePolicy::compat() + }; + let mut modules = vec![]; + for u in self.package.root_modules() { + let name = u.unit.name().to_string(); + let source = if self.options.with_srcs { + zip_metadata_str(&std::fs::read_to_string(&u.source_path)?)? + } else { + vec![] + }; + let source_map = if self.options.with_source_maps { + zip_metadata(&u.unit.serialize_source_map())? + } else { + vec![] + }; + modules.push(ModuleMetadata { + name, + source, + source_map, + extension: MoveOption::default(), + }) + } + let deps = self + .package + .deps_compiled_units + .iter() + .map(|(name, unit)| { + let package_name = name.as_str().to_string(); + let account = match &unit.unit { + CompiledUnit::Module(m) => AccountAddress::new(m.address.into_bytes()), + _ => panic!("script not a dependency"), + }; + PackageDep { + account, + package_name, + } + }) + .collect::>() + .into_iter() + .collect(); + Ok(PackageMetadata { + name: self.name().to_string(), + upgrade_policy, + upgrade_number: 0, + source_digest, + manifest, + modules, + deps, + extension: MoveOption::none(), + }) + } + + pub fn extract_metadata_and_save(&self) -> anyhow::Result<()> { + let data = self.extract_metadata()?; + let path = self.package_artifacts_path(); + std::fs::create_dir_all(&path)?; + std::fs::write(path.join(METADATA_FILE_NAME), bcs::to_bytes(&data)?)?; + Ok(()) + } +} + +fn extract_custom_fields(toml: &str) -> anyhow::Result> { + let manifest = parse_source_manifest(parse_move_manifest_string(toml.to_owned())?)?; + Ok(manifest + .package + .custom_properties + .iter() + .map(|(s, v)| (s.to_string(), v.to_string())) + .collect()) +} + +fn inject_runtime_metadata( + package_path: PathBuf, + pack: &mut CompiledPackage, + metadata: BTreeMap, + bytecode_version: Option, +) -> anyhow::Result<()> { + for unit_with_source in pack.root_compiled_units.iter_mut() { + match &mut unit_with_source.unit { + CompiledUnit::Module(named_module) => { + if let Some(module_metadata) = metadata.get(&named_module.module.self_id()) { + if !module_metadata.is_empty() { + if bytecode_version.unwrap_or(METADATA_V1_MIN_FILE_FORMAT_VERSION) + >= METADATA_V1_MIN_FILE_FORMAT_VERSION + { + let serialized_metadata = bcs::to_bytes(&module_metadata) + .expect("BCS for RuntimeModuleMetadata"); + named_module.module.metadata.push(Metadata { + key: APTOS_METADATA_KEY_V1.to_vec(), + value: serialized_metadata, + }); + } else { + let serialized_metadata = + bcs::to_bytes(&module_metadata.clone().downgrade()) + .expect("BCS for RuntimeModuleMetadata"); + named_module.module.metadata.push(Metadata { + key: APTOS_METADATA_KEY.to_vec(), + value: serialized_metadata, + }); + } + + // Also need to update the .mv file on disk. + let path = package_path + .join(CompiledPackageLayout::CompiledModules.path()) + .join(named_module.name.as_str()) + .with_extension(MOVE_COMPILED_EXTENSION); + if path.is_file() { + let bytes = unit_with_source.unit.serialize(bytecode_version); + std::fs::write(path, bytes)?; + } + } + } + }, + CompiledUnit::Script(_) => {}, + } + } + Ok(()) +} diff --git a/vm/framework/src/docgen.rs b/vm/framework/src/docgen.rs index 7b15f234d3..f083489831 100644 --- a/vm/framework/src/docgen.rs +++ b/vm/framework/src/docgen.rs @@ -10,11 +10,6 @@ use move_docgen::OutputFormat; use move_model::model::GlobalEnv; use std::{path::PathBuf, sync::Mutex}; -pub fn get_docgen_output_dir() -> String { - const MVC_DOCGEN_OUTPUT_DIR: &str = "MVC_DOCGEN_OUTPUT_DIR"; - std::env::var(MVC_DOCGEN_OUTPUT_DIR).unwrap_or_else(|_| "doc".to_owned()) -} - #[derive(Debug, Clone, clap::Parser, serde::Serialize, serde::Deserialize, Default)] pub struct DocgenOptions { /// Whether to include private declarations and implementations into the generated @@ -75,7 +70,7 @@ impl DocgenOptions { let _lock = MUTEX.lock(); let current_dir = std::env::current_dir()?.canonicalize()?; std::env::set_current_dir(&package_path)?; - let output_directory = PathBuf::from(get_docgen_output_dir()); + let output_directory = PathBuf::from("doc"); let doc_path = doc_path .into_iter() .filter_map(|s| { diff --git a/vm/framework/src/lib.rs b/vm/framework/src/lib.rs index c624c1b9e1..19e814fc03 100644 --- a/vm/framework/src/lib.rs +++ b/vm/framework/src/lib.rs @@ -9,8 +9,8 @@ mod starcoin; pub use starcoin::*; use std::io::{Read, Write}; -// mod built_package; -// pub use built_package::*; +mod built_package; +pub use built_package::*; mod module_metadata; pub use module_metadata::*; diff --git a/vm/framework/src/module_metadata.rs b/vm/framework/src/module_metadata.rs index 6cf9514046..0c9b50df1e 100644 --- a/vm/framework/src/module_metadata.rs +++ b/vm/framework/src/module_metadata.rs @@ -3,21 +3,22 @@ use crate::extended_checks::ResourceGroupScope; use starcoin_vm_types::{ - on_chain_config::{FeatureFlag, Features, TimedFeatureFlag, TimedFeatures}, + on_chain_config::{FeatureFlag, Features, TimedFeatures}, transaction::AbortInfo, }; use lru::LruCache; use move_binary_format::{ access::ModuleAccess, file_format::{ - Ability, AbilitySet, CompiledScript, FunctionDefinition, FunctionHandle, IdentifierIndex, - SignatureToken, StructDefinition, StructFieldInformation, StructHandle, TableIndex, + Ability, AbilitySet, CompiledScript, IdentifierIndex, SignatureToken, + StructFieldInformation, TableIndex, }, + normalized::{Function, Struct}, CompiledModule, }; use move_core_types::{ errmap::ErrorDescription, - identifier::{IdentStr, Identifier}, + identifier::Identifier, language_storage::{ModuleId, StructTag}, metadata::Metadata, }; @@ -312,17 +313,6 @@ pub fn get_compilation_metadata_from_compiled_module( } } -/// Extract compilation metadata from a compiled script -pub fn get_compilation_metadata_from_compiled_script( - module: &CompiledScript, -) -> Option { - if let Some(data) = find_metadata_in_script(module, COMPILATION_METADATA_KEY) { - bcs::from_bytes::(&data.value).ok() - } else { - None - } -} - // This is mostly a copy paste of the existing function // get_metadata_from_compiled_module. In the API types there is a unifying trait for // modules and scripts called Bytecode that could help eliminate this duplication, @@ -398,12 +388,12 @@ pub struct AttributeValidationError { } pub fn is_valid_unbiasable_function( - functions: &BTreeMap<&IdentStr, (&FunctionHandle, &FunctionDefinition)>, + functions: &BTreeMap, fun: &str, ) -> Result<(), AttributeValidationError> { if let Ok(ident_fun) = Identifier::new(fun) { - if let Some((_func_handle, func_def)) = functions.get(ident_fun.as_ident_str()) { - if func_def.is_entry && !func_def.visibility.is_public() { + if let Some(f) = functions.get(&ident_fun) { + if f.is_entry && !f.visibility.is_public() { return Ok(()); } } @@ -416,14 +406,12 @@ pub fn is_valid_unbiasable_function( } pub fn is_valid_view_function( - module: &CompiledModule, - functions: &BTreeMap<&IdentStr, (&FunctionHandle, &FunctionDefinition)>, + functions: &BTreeMap, fun: &str, ) -> Result<(), AttributeValidationError> { if let Ok(ident_fun) = Identifier::new(fun) { - if let Some((func_handle, _func_def)) = functions.get(ident_fun.as_ident_str()) { - let sig = module.signature_at(func_handle.return_); - if !sig.0.is_empty() { + if let Some(mod_fun) = functions.get(&ident_fun) { + if !mod_fun.return_.is_empty() { return Ok(()); } } @@ -436,18 +424,14 @@ pub fn is_valid_view_function( } pub fn is_valid_resource_group( - structs: &BTreeMap<&IdentStr, (&StructHandle, &StructDefinition)>, + structs: &BTreeMap, struct_: &str, ) -> Result<(), AttributeValidationError> { if let Ok(ident_struct) = Identifier::new(struct_) { - if let Some((struct_handle, struct_def)) = structs.get(ident_struct.as_ident_str()) { - let num_fields = match &struct_def.field_information { - StructFieldInformation::Native | StructFieldInformation::DeclaredVariants(_) => 0, - StructFieldInformation::Declared(fields) => fields.len(), - }; - if struct_handle.abilities == AbilitySet::EMPTY - && struct_handle.type_parameters.is_empty() - && num_fields == 1 + if let Some(mod_struct) = structs.get(&ident_struct) { + if mod_struct.abilities == AbilitySet::EMPTY + && mod_struct.type_parameters.is_empty() + && mod_struct.fields.len() == 1 { return Ok(()); } @@ -461,12 +445,12 @@ pub fn is_valid_resource_group( } pub fn is_valid_resource_group_member( - structs: &BTreeMap<&IdentStr, (&StructHandle, &StructDefinition)>, + structs: &BTreeMap, struct_: &str, ) -> Result<(), AttributeValidationError> { if let Ok(ident_struct) = Identifier::new(struct_) { - if let Some((struct_handle, _struct_def)) = structs.get(ident_struct.as_ident_str()) { - if struct_handle.abilities.has_ability(Ability::Key) { + if let Some(mod_struct) = structs.get(&ident_struct) { + if mod_struct.abilities.has_ability(Ability::Key) { return Ok(()); } } @@ -481,11 +465,9 @@ pub fn is_valid_resource_group_member( pub fn verify_module_metadata( module: &CompiledModule, features: &Features, - timed_features: &TimedFeatures, + _timed_features: &TimedFeatures, ) -> Result<(), MetaDataValidationError> { - if features.is_enabled(FeatureFlag::SAFER_METADATA) - && timed_features.is_enabled(TimedFeatureFlag::ModuleComplexityCheck) - { + if features.is_enabled(FeatureFlag::SAFER_METADATA) { check_module_complexity(module)?; } @@ -501,17 +483,13 @@ pub fn verify_module_metadata( let functions = module .function_defs .iter() - .map(|func_def| { - let func_handle = module.function_handle_at(func_def.function); - let name = module.identifier_at(func_handle.name); - (name, (func_handle, func_def)) - }) + .map(|func_def| Function::new(module, func_def)) .collect::>(); for (fun, attrs) in &metadata.fun_attributes { for attr in attrs { if attr.is_view_function() { - is_valid_view_function(module, &functions, fun)?; + is_valid_view_function(&functions, fun)?; } else if attr.is_randomness() { is_valid_unbiasable_function(&functions, fun)?; } else { @@ -527,11 +505,7 @@ pub fn verify_module_metadata( let structs = module .struct_defs .iter() - .map(|struct_def| { - let struct_handle = module.struct_handle_at(struct_def.struct_handle); - let name = module.identifier_at(struct_handle.name); - (name, (struct_handle, struct_def)) - }) + .map(|d| Struct::new(module, d)) .collect::>(); for (struct_, attrs) in &metadata.struct_attributes { diff --git a/vm/framework/src/prover.rs b/vm/framework/src/prover.rs index f2c84a28ff..9d44c27e8e 100644 --- a/vm/framework/src/prover.rs +++ b/vm/framework/src/prover.rs @@ -123,7 +123,6 @@ impl ProverOptions { language_version: Option, skip_attribute_checks: bool, known_attributes: &BTreeSet, - experiments: &[String], ) -> anyhow::Result<()> { let now = Instant::now(); let for_test = self.for_test; @@ -137,7 +136,6 @@ impl ProverOptions { language_version, skip_attribute_checks, known_attributes.clone(), - experiments.to_vec(), )?; let mut options = self.convert_options(); // Need to ensure a distinct output.bpl file for concurrent execution. In non-test diff --git a/vm/framework/src/release_builder.rs b/vm/framework/src/release_builder.rs index 14c88f16be..135566a3d2 100644 --- a/vm/framework/src/release_builder.rs +++ b/vm/framework/src/release_builder.rs @@ -7,7 +7,7 @@ use crate::{ release_bundle::{ReleaseBundle, ReleasePackage}, }; use anyhow::{anyhow, Context}; -use aptos_sdk_builder::rust; +use starcoin_sdk_builder::rust; use starcoin_vm_types::transaction::EntryABI; use clap::Parser; use std::path::{Path, PathBuf}; diff --git a/vm/starcoin-aggregator/src/tests/types.rs b/vm/starcoin-aggregator/src/tests/types.rs index c5ee60bbb4..8f710f7346 100644 --- a/vm/starcoin-aggregator/src/tests/types.rs +++ b/vm/starcoin-aggregator/src/tests/types.rs @@ -10,13 +10,18 @@ use crate::{ code_invariant_error, expect_ok, DelayedFieldValue, DelayedFieldsSpeculativeError, PanicOr, }, }; + use starcoin_types::{ delayed_fields::PanicError, +}; + +use starcoin_vm_types::{ state_store::{ state_key::StateKey, state_value::{StateValue, StateValueMetadata}, }, }; + use move_binary_format::errors::PartialVMResult; use move_core_types::{language_storage::StructTag, value::MoveTypeLayout}; use move_vm_types::delayed_values::delayed_field_id::{DelayedFieldID, ExtractUniqueIndex}; diff --git a/vm/starcoin-sdk-builder/Cargo.toml b/vm/starcoin-sdk-builder/Cargo.toml new file mode 100644 index 0000000000..7dde32305f --- /dev/null +++ b/vm/starcoin-sdk-builder/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "starcoin-sdk-builder" +description = "Starcoin transaction-builder" +version = "0.2.0" + +# Workspace inherited keys +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +publish = { workspace = true } +repository = { workspace = true } +rust-version = { workspace = true } + +[dependencies] +anyhow = { workspace = true } +starcoin-vm-types = { workspace = true } +bcs = { workspace = true } +clap = { workspace = true } +heck = { workspace = true } +move-core-types = { workspace = true } +once_cell = { workspace = true } +serde-generate = { workspace = true } +serde-reflection = { workspace = true } +serde_yaml = { workspace = true } +textwrap = { workspace = true } + +[dev-dependencies] +starcoin-cached-packages = { workspace = true } +starcoin-framework = { workspace = true } +tempfile = { workspace = true } +which = { workspace = true } + +[features] +default = [] diff --git a/vm/starcoin-sdk-builder/README.md b/vm/starcoin-sdk-builder/README.md new file mode 100644 index 0000000000..86de18f67b --- /dev/null +++ b/vm/starcoin-sdk-builder/README.md @@ -0,0 +1,33 @@ +--- +id: aptos-sdk-builder +title: Aptos SDK Builder +custom_edit_url: https://github.com/aptos-labs/aptos-core/edit/main/language/aptos-sdk-builder/README.md +--- + +# Aptos SDK Builder + +A *transaction builder* is a helper function that converts its arguments into the payload of an Aptos transaction calling a particular Move script. + +In Rust, the signature of such a function typically looks like this: +```rust +pub fn encode_peer_to_peer_with_metadata_script( + token: TypeTag, + payee: AccountAddress, + amount: u64, + metadata: Vec, + metadata_signature: Vec, +) -> Script; +``` + +This crate provide a library to generate transaction builders in one programming language. + +The tool will also generate and install type definitions for Aptos types such as `TypeTag`, `AccountAddress`, and `Script`. + +In practice, hashing and signing Aptos transactions additionally requires a runtime library for Binary Canonical Serialization ("BCS"). +Such a library will be installed together with the Aptos types. + + +## Supported Languages + +The following languages are currently supported: +* Rust diff --git a/vm/starcoin-sdk-builder/examples/golang/Makefile b/vm/starcoin-sdk-builder/examples/golang/Makefile new file mode 100644 index 0000000000..20d68e7348 --- /dev/null +++ b/vm/starcoin-sdk-builder/examples/golang/Makefile @@ -0,0 +1,21 @@ +#Copyright © Aptos Foundation +# SPDX-License-Identifier: Apache-2.0 + +clean: + - rm -rf go.mod go.sum aptosstdlib aptostypes + +test: + cargo run -p aptos-framework release + cargo run -p aptos-sdk-builder -- \ + --language go --module-name aptosstdlib \ + --package-name testing \ + --with-aptos-types "../../../../testsuite/generate-format/tests/staged/aptos.yaml" \ + --target-source-dir . \ + "../../../framework/aptos-framework/build/AptosFramework" + - go mod init testing + go mod edit -replace testing=`pwd` + go get github.com/aptos-labs/serde-reflection/serde-generate/runtime/golang/bcs + go get github.com/aptos-labs/serde-reflection/serde-generate/runtime/golang/serde + go run stdlib_demo.go + +.PHONY: clean test diff --git a/vm/starcoin-sdk-builder/examples/golang/stdlib_demo.go b/vm/starcoin-sdk-builder/examples/golang/stdlib_demo.go new file mode 100644 index 0000000000..b64fe7209f --- /dev/null +++ b/vm/starcoin-sdk-builder/examples/golang/stdlib_demo.go @@ -0,0 +1,53 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "fmt" + stdlib "testing/aptosstdlib" + aptos "testing/aptostypes" +) + +func demo_coin_transfer() { + token := &aptos.TypeTag__Struct{ + Value: aptos.StructTag{ + Address: aptos.AccountAddress( + [32]uint8{0, 0, 0, 0, 0, 0, 0, 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}, + ), + Module: aptos.Identifier("aptos_coin"), + Name: aptos.Identifier("AptosCoin"), + }, + } + + to := aptos.AccountAddress( + [32]uint8{0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, + ) + + amount := uint64(1_234_567) + payload := stdlib.EncodeCoinTransfer(token, to, amount) + + call, err := stdlib.DecodeEntryFunctionPayload(payload) + if err != nil { + panic(fmt.Sprintf("failed to decode script: %v", err)) + } + payment := call.(*stdlib.EntryFunctionCall__CoinTransfer) + if payment.Amount != amount || payment.To != to { + panic("wrong script content") + } + + bytes, err := payload.BcsSerialize() + if err != nil { + panic("failed to serialize") + } + for _, b := range bytes { + fmt.Printf("%d ", b) + } + fmt.Printf("\n") +} + +func main() { + demo_coin_transfer() +} diff --git a/vm/starcoin-sdk-builder/examples/rust/script_fun_demo.rs b/vm/starcoin-sdk-builder/examples/rust/script_fun_demo.rs new file mode 100644 index 0000000000..522d073508 --- /dev/null +++ b/vm/starcoin-sdk-builder/examples/rust/script_fun_demo.rs @@ -0,0 +1,36 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use aptos_framework::{aptos_coin_transfer, EntryFunctionCall}; +use aptos_types::AccountAddress; + +fn demo_p2p_entry_function() { + let payee = AccountAddress([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, + ]); + let amount = 1234567; + + // Now encode and decode a peer to peer transaction entry function. + let payload = aptos_coin_transfer(payee.clone(), amount); + let function_call = EntryFunctionCall::decode(&payload); + match function_call { + Some(EntryFunctionCall::AptosCoinTransfer { amount: a, to: p }) => { + assert_eq!(a, amount); + assert_eq!(p, payee.clone()); + } + _ => panic!("unexpected type of entry function"), + }; + + let output = bcs::to_bytes(&payload).unwrap(); + for o in output { + print!("{} ", o); + } + println!(); +} + +fn main() { + demo_p2p_entry_function(); +} diff --git a/vm/starcoin-sdk-builder/src/common.rs b/vm/starcoin-sdk-builder/src/common.rs new file mode 100644 index 0000000000..236bab41fb --- /dev/null +++ b/vm/starcoin-sdk-builder/src/common.rs @@ -0,0 +1,183 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use starcoin_vm_types::transaction::{ + ArgumentABI, EntryABI, EntryFunctionABI, TransactionScriptABI, TypeArgumentABI, +}; +use heck::ToUpperCamelCase; +use move_core_types::language_storage::{StructTag, TypeTag}; +use once_cell::sync::Lazy; +use serde_reflection::{ContainerFormat, Format, Named, VariantFormat}; +use std::{ + collections::{BTreeMap, BTreeSet}, + str::FromStr, +}; + +/// Useful error message. +pub(crate) fn type_not_allowed(type_tag: &TypeTag) -> ! { + panic!( + "Transaction scripts cannot take arguments of type {}.", + type_tag + ); +} + +/// Clean up doc comments extracter by the Move prover. +pub(crate) fn prepare_doc_string(doc: &str) -> String { + doc.replace("\n ", "\n").trim().to_string() +} + +fn quote_type_as_format(type_tag: &TypeTag) -> Format { + use TypeTag::*; + let str_tag: Lazy = + Lazy::new(|| StructTag::from_str("0x1::string::String").unwrap()); + match type_tag { + Bool => Format::Bool, + U8 => Format::U8, + U16 => Format::U16, + U32 => Format::U32, + U64 => Format::U64, + U128 => Format::U128, + U256 => Format::TypeName("U256".into()), + Address => Format::TypeName("AccountAddress".into()), + Vector(type_tag) => Format::Seq(Box::new(quote_type_as_format(type_tag))), + Struct(tag) => match tag { + tag if &**tag == Lazy::force(&str_tag) => Format::Seq(Box::new(Format::U8)), + _ => type_not_allowed(type_tag), + }, + Signer => type_not_allowed(type_tag), + } +} + +fn quote_type_parameter_as_field(ty_arg: &TypeArgumentABI) -> Named { + Named { + name: ty_arg.name().to_string(), + value: Format::TypeName("TypeTag".into()), + } +} + +fn quote_parameter_as_field(arg: &ArgumentABI) -> Named { + Named { + name: arg.name().to_string(), + value: quote_type_as_format(arg.type_tag()), + } +} + +pub(crate) fn make_abi_enum_container(abis: &[EntryABI]) -> ContainerFormat { + let mut variants = BTreeMap::new(); + for (index, abi) in abis.iter().enumerate() { + let mut fields = Vec::new(); + for ty_arg in abi.ty_args() { + fields.push(quote_type_parameter_as_field(ty_arg)); + } + for arg in abi.args() { + fields.push(quote_parameter_as_field(arg)); + } + + let name = match abi { + EntryABI::EntryFunction(sf) => { + format!( + "{}{}", + sf.module_name().name().to_string().to_upper_camel_case(), + abi.name().to_upper_camel_case() + ) + }, + _ => abi.name().to_upper_camel_case(), + }; + + variants.insert(index as u32, Named { + name, + value: VariantFormat::Struct(fields), + }); + } + ContainerFormat::Enum(variants) +} + +pub(crate) fn mangle_type(type_tag: &TypeTag) -> String { + use TypeTag::*; + let str_tag: Lazy = + Lazy::new(|| StructTag::from_str("0x1::string::String").unwrap()); + + match type_tag { + Bool => "bool".into(), + U8 => "u8".into(), + U16 => "u16".into(), + U32 => "u32".into(), + U64 => "u64".into(), + U128 => "u128".into(), + U256 => "u256".into(), + Address => "address".into(), + Vector(type_tag) => match type_tag.as_ref() { + U8 => "u8vector".into(), + Vector(type_tag) => { + if type_tag.as_ref() == &U8 { + "vecbytes".into() + } else { + type_not_allowed(type_tag) + } + }, + _ => format!("vec{}", mangle_type(type_tag)), + }, + Struct(tag) => match tag { + tag if &**tag == Lazy::force(&str_tag) => "string".into(), + _ => type_not_allowed(type_tag), + }, + Signer => type_not_allowed(type_tag), + } +} + +pub(crate) fn get_external_definitions(aptos_types: &str) -> serde_generate::ExternalDefinitions { + let definitions = vec![(aptos_types, vec![ + "AccountAddress", + "TypeTag", + "Script", + "TransactionArgument", + ])]; + definitions + .into_iter() + .map(|(module, defs)| { + ( + module.to_string(), + defs.into_iter().map(String::from).collect(), + ) + }) + .collect() +} + +pub(crate) fn get_required_helper_types(abis: &[EntryABI]) -> BTreeSet<&TypeTag> { + let mut required_types = BTreeSet::new(); + for abi in abis { + for arg in abi.args() { + let type_tag = arg.type_tag(); + required_types.insert(type_tag); + } + } + required_types +} + +pub(crate) fn filter_transaction_scripts(abis: &[EntryABI]) -> Vec { + abis.iter() + .filter(|abi| abi.is_transaction_script_abi()) + .cloned() + .collect() +} + +pub(crate) fn transaction_script_abis(abis: &[EntryABI]) -> Vec { + abis.iter() + .cloned() + .filter_map(|abi| match abi { + EntryABI::TransactionScript(abi) => Some(abi), + EntryABI::EntryFunction(_) => None, + }) + .collect::>() +} + +pub(crate) fn entry_function_abis(abis: &[EntryABI]) -> Vec { + abis.iter() + .cloned() + .filter_map(|abi| match abi { + EntryABI::EntryFunction(abi) => Some(abi), + EntryABI::TransactionScript(_) => None, + }) + .collect::>() +} diff --git a/vm/starcoin-sdk-builder/src/golang.rs b/vm/starcoin-sdk-builder/src/golang.rs new file mode 100644 index 0000000000..af8e5e9b03 --- /dev/null +++ b/vm/starcoin-sdk-builder/src/golang.rs @@ -0,0 +1,902 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::common; +use starcoin_types::transaction::{ + ArgumentABI, EntryABI, EntryFunctionABI, TransactionScriptABI, TypeArgumentABI, +}; +use heck::ToUpperCamelCase; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{ModuleId, StructTag, TypeTag}, +}; +use once_cell::sync::Lazy; +use serde_generate::{ + golang, + indent::{IndentConfig, IndentedWriter}, + CodeGeneratorConfig, +}; +use std::{ + collections::BTreeMap, + io::{Result, Write}, + path::PathBuf, + str::FromStr, +}; + +/// Output transaction builders and decoders in Go for the given ABIs. +pub fn output( + out: &mut dyn Write, + serde_module_path: Option, + aptos_module_path: Option, + package_name: String, + abis: &[EntryABI], +) -> Result<()> { + let mut emitter = GoEmitter { + out: IndentedWriter::new(out, IndentConfig::Tab), + serde_module_path, + aptos_module_path, + package_name, + }; + + // Some functions have complex types which are not currently supported in bcs or in this + // generator. Disable those functiosn for now. + let abis_vec = abis + .iter() + .filter(|abi| { + if let EntryABI::EntryFunction(sf) = abi { + sf.module_name().name().as_str() != "code" + && sf.name() != "publish_package_txn" + && sf.module_name().name().as_str() != "aptos_account" + && sf.name() != "batch_transfer" + && sf.module_name().name().as_str() != "aptos_account" + && sf.name() != "batch_transfer_coins" + } else { + true + } + }) + .cloned() + .collect::>(); + + let abis = abis_vec.as_slice(); + emitter.output_script_call_enum_with_imports(abis)?; + + emitter.output_encode_method(abis)?; + emitter.output_transaction_script_decode_method()?; + emitter.output_entry_function_decode_method()?; + + for abi in abis { + match abi { + EntryABI::TransactionScript(abi) => { + emitter.output_transaction_script_encoder_function(abi)? + }, + EntryABI::EntryFunction(abi) => emitter.output_entry_function_encoder_function(abi)?, + }; + } + + for abi in abis { + match abi { + EntryABI::TransactionScript(abi) => { + emitter.output_transaction_script_decoder_function(abi)? + }, + EntryABI::EntryFunction(abi) => emitter.output_entry_function_decoder_function(abi)?, + }; + } + + for abi in abis { + emitter.output_code_constant(abi)?; + } + emitter.output_transaction_script_decoder_map(&common::transaction_script_abis(abis))?; + emitter.output_entry_function_decoder_map(&common::entry_function_abis(abis))?; + + emitter.output_encoding_helpers(abis)?; + emitter.output_decoding_helpers(&common::filter_transaction_scripts(abis))?; + + Ok(()) +} + +/// Shared state for the Go code generator. +struct GoEmitter { + /// Writer. + out: IndentedWriter, + /// Go module path for Serde runtime packages + /// `None` to use the default path. + serde_module_path: Option, + /// Go module path for Aptos types. + /// `None` to use an empty path. + aptos_module_path: Option, + /// Name of the package owning the generated definitions (e.g. "my_package") + package_name: String, +} + +impl GoEmitter +where + T: Write, +{ + fn output_script_call_enum_with_imports(&mut self, abis: &[EntryABI]) -> Result<()> { + let aptos_types_package = match &self.aptos_module_path { + Some(path) => format!("{}/aptostypes", path), + None => "aptostypes".into(), + }; + let mut external_definitions = + crate::common::get_external_definitions(&aptos_types_package); + // We need BCS for argument encoding and decoding + external_definitions.insert( + "github.com/aptos-labs/serde-reflection/serde-generate/runtime/golang/bcs".to_string(), + Vec::new(), + ); + // Add standard imports + external_definitions.insert("fmt".to_string(), Vec::new()); + + let (transaction_script_abis, entry_fun_abis): (Vec<_>, Vec<_>) = abis + .iter() + .cloned() + .partition(|abi| abi.is_transaction_script_abi()); + + // Generate `ScriptCall` enums for all old-style transaction scripts + let mut script_registry: BTreeMap<_, _> = vec![( + "ScriptCall".to_string(), + crate::common::make_abi_enum_container(transaction_script_abis.as_slice()), + )] + .into_iter() + .collect(); + + // Generate `EntryFunctionCall` enums for all new transaction scripts + let mut entry_function_registry: BTreeMap<_, _> = vec![( + "EntryFunctionCall".to_string(), + crate::common::make_abi_enum_container(entry_fun_abis.as_slice()), + )] + .into_iter() + .collect(); + + script_registry.append(&mut entry_function_registry); + + let mut comments: BTreeMap<_, _> = abis + .iter() + .map(|abi| { + ( + vec![ + self.package_name.to_string(), + if abi.is_transaction_script_abi() { + "ScriptCall".to_string() + } else { + "EntryFunctionCall".to_string() + }, + abi.name().to_upper_camel_case(), + ], + crate::common::prepare_doc_string(abi.doc()), + ) + }) + .collect(); + + comments.insert( + vec![self.package_name.to_string(), "ScriptCall".to_string()], + "Structured representation of a call into a known Move transaction script (legacy)." + .into(), + ); + + comments.insert( + vec![ + self.package_name.to_string(), + "EntryFunctionCall".to_string(), + ], + "Structured representation of a call into a known Move entry function.".into(), + ); + + let config = CodeGeneratorConfig::new(self.package_name.to_string()) + .with_comments(comments) + .with_external_definitions(external_definitions) + .with_serialization(false); + let mut generator = golang::CodeGenerator::new(&config); + if let Some(path) = &self.serde_module_path { + generator = generator.with_serde_module_path(path.clone()); + } + generator + .output(&mut self.out, &script_registry) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", err)))?; + Ok(()) + } + + fn output_encode_method(&mut self, abis: &[EntryABI]) -> Result<()> { + let (transaction_script_abis, entry_fun_abis): (Vec<_>, Vec<_>) = abis + .iter() + .cloned() + .partition(|abi| abi.is_transaction_script_abi()); + + if !transaction_script_abis.is_empty() { + writeln!( + self.out, + r#" +// Build an Aptos `Script` from a structured object `ScriptCall`. +func EncodeScript(call ScriptCall) aptostypes.Script {{"# + )?; + self.out.indent(); + writeln!(self.out, "switch call := call.(type) {{")?; + for abi in transaction_script_abis { + if let EntryABI::TransactionScript(abi) = abi { + let params = std::iter::empty() + .chain(abi.ty_args().iter().map(TypeArgumentABI::name)) + .chain(abi.args().iter().map(ArgumentABI::name)) + .map(|name| format!("call.{}", name.to_upper_camel_case())) + .collect::>() + .join(", "); + writeln!( + self.out, + r#"case *ScriptCall__{0}: + return Encode{0}({1})"#, + abi.name().to_upper_camel_case(), + params, + )?; + } + } + writeln!(self.out, "}}")?; + writeln!(self.out, "panic(\"unreachable\")")?; + self.out.unindent(); + writeln!(self.out, "}}")?; + } + + if !entry_fun_abis.is_empty() { + writeln!( + self.out, + r#" +// Build an Aptos `TransactionPayload` from a structured object `EntryFunctionCall`. +func EncodeEntryFunction(call EntryFunctionCall) aptostypes.TransactionPayload {{"# + )?; + self.out.indent(); + writeln!(self.out, "switch call := call.(type) {{")?; + for abi in entry_fun_abis { + if let EntryABI::EntryFunction(abi) = abi { + let params = std::iter::empty() + .chain(abi.ty_args().iter().map(TypeArgumentABI::name)) + .chain(abi.args().iter().map(ArgumentABI::name)) + .map(|name| format!("call.{}", name.to_upper_camel_case())) + .collect::>() + .join(", "); + writeln!( + self.out, + r#"case *EntryFunctionCall__{0}{1}: + return Encode{0}{1}({2})"#, + abi.module_name().name().to_string().to_upper_camel_case(), + abi.name().to_upper_camel_case(), + params, + )?; + } + } + writeln!(self.out, "}}")?; + writeln!(self.out, "panic(\"unreachable\")")?; + self.out.unindent(); + writeln!(self.out, "}}")?; + } + Ok(()) + } + + fn output_transaction_script_decode_method(&mut self) -> Result<()> { + writeln!( + self.out, + r#" +// Try to recognize an Aptos `Script` and convert it into a structured object `ScriptCall`. +func DecodeScript(script *aptostypes.Script) (ScriptCall, error) {{ + if helper := script_decoder_map[string(script.Code)]; helper != nil {{ + val, err := helper(script) + return val, err + }} else {{ + return nil, fmt.Errorf("Unknown script bytecode: %s", string(script.Code)) + }} +}}"# + ) + } + + fn output_entry_function_decode_method(&mut self) -> Result<()> { + writeln!( + self.out, + r#" +// Try to recognize an Aptos `TransactionPayload` and convert it into a structured object `EntryFunctionCall`. +func DecodeEntryFunctionPayload(script aptostypes.TransactionPayload) (EntryFunctionCall, error) {{ + switch script := script.(type) {{ + case *aptostypes.TransactionPayload__EntryFunction: + if helper := entry_function_decoder_map[string(script.Value.Module.Name) + "_" + string(script.Value.Function)]; helper != nil {{ + val, err := helper(script) + return val, err + }} else {{ + return nil, fmt.Errorf("Unknown entry function: %s::%s", script.Value.Module.Name, script.Value.Function) + }} + default: + return nil, fmt.Errorf("Unknown transaction payload encountered when decoding") + }} +}}"# + ) + } + + fn output_transaction_script_encoder_function( + &mut self, + abi: &TransactionScriptABI, + ) -> Result<()> { + writeln!( + self.out, + "\n{}\nfunc Encode{}({}) aptostypes.Script {{", + Self::quote_doc(abi.doc()), + abi.name().to_upper_camel_case(), + [ + Self::quote_type_parameters(abi.ty_args()), + Self::quote_parameters(abi.args()), + ] + .concat() + .join(", ") + )?; + self.out.indent(); + writeln!( + self.out, + r#"return aptostypes.Script {{ + Code: append([]byte(nil), {}_code...), + TyArgs: []aptostypes.TypeTag{{{}}}, + Args: []aptostypes.TransactionArgument{{{}}}, +}}"#, + abi.name(), + Self::quote_type_arguments(abi.ty_args()), + Self::quote_arguments_for_script(abi.args()), + )?; + self.out.unindent(); + writeln!(self.out, "}}") + } + + fn output_entry_function_encoder_function(&mut self, abi: &EntryFunctionABI) -> Result<()> { + writeln!( + self.out, + "\n{}\nfunc Encode{}{}({}) aptostypes.TransactionPayload {{", + Self::quote_doc(abi.doc()), + abi.module_name().name().to_string().to_upper_camel_case(), + abi.name().to_upper_camel_case(), + [ + Self::quote_type_parameters(abi.ty_args()), + Self::quote_parameters(abi.args()), + ] + .concat() + .join(", ") + )?; + self.out.indent(); + writeln!( + self.out, + r#"return &aptostypes.TransactionPayload__EntryFunction {{ + aptostypes.EntryFunction {{ + Module: {}, + Function: {}, + TyArgs: []aptostypes.TypeTag{{{}}}, + Args: [][]byte{{{}}}, + }}, +}}"#, + Self::quote_module_id(abi.module_name()), + Self::quote_identifier(abi.name()), + Self::quote_type_arguments(abi.ty_args()), + Self::quote_arguments(abi.args()), + )?; + self.out.unindent(); + writeln!(self.out, "}}") + } + + fn output_transaction_script_decoder_function( + &mut self, + abi: &TransactionScriptABI, + ) -> Result<()> { + writeln!( + self.out, + "\nfunc decode_{}(script *aptostypes.Script) (ScriptCall, error) {{", + abi.name(), + )?; + self.out.indent(); + writeln!( + self.out, + "if len(script.TyArgs) < {0} {{ return nil, fmt.Errorf(\"Was expecting {0} type arguments\") }}", + abi.ty_args().len(), + )?; + writeln!( + self.out, + "if len(script.Args) < {0} {{ return nil, fmt.Errorf(\"Was expecting {0} regular arguments\") }}", + abi.args().len(), + )?; + writeln!( + self.out, + "var call ScriptCall__{0}", + abi.name().to_upper_camel_case(), + )?; + for (index, ty_arg) in abi.ty_args().iter().enumerate() { + writeln!( + self.out, + "call.{} = script.TyArgs[{}]", + ty_arg.name().to_upper_camel_case(), + index, + )?; + } + for (index, arg) in abi.args().iter().enumerate() { + writeln!( + self.out, + r#"if val, err := decode_{}_argument(script.Args[{}]); err == nil {{ + call.{} = val +}} else {{ + return nil, err +}} +"#, + common::mangle_type(arg.type_tag()), + index, + arg.name().to_upper_camel_case(), + )?; + } + writeln!(self.out, "return &call, nil")?; + self.out.unindent(); + writeln!(self.out, "}}")?; + Ok(()) + } + + fn output_entry_function_decoder_function(&mut self, abi: &EntryFunctionABI) -> Result<()> { + writeln!( + self.out, + "\nfunc decode_{}_{}(script aptostypes.TransactionPayload) (EntryFunctionCall, error) {{", + abi.module_name().name(), + abi.name(), + )?; + self.out.indent(); + writeln!(self.out, "switch script := interface{{}}(script).(type) {{")?; + self.out.indent(); + writeln!( + self.out, + "case *aptostypes.TransactionPayload__EntryFunction:" + )?; + self.out.indent(); + writeln!( + self.out, + "if len(script.Value.TyArgs) < {0} {{ return nil, fmt.Errorf(\"Was expecting {0} type arguments\") }}", + abi.ty_args().len(), + )?; + writeln!( + self.out, + "if len(script.Value.Args) < {0} {{ return nil, fmt.Errorf(\"Was expecting {0} regular arguments\") }}", + abi.args().len(), + )?; + writeln!( + self.out, + "var call EntryFunctionCall__{0}{1}", + abi.module_name().name().to_string().to_upper_camel_case(), + abi.name().to_upper_camel_case(), + )?; + for (index, ty_arg) in abi.ty_args().iter().enumerate() { + writeln!( + self.out, + "call.{} = script.Value.TyArgs[{}]", + ty_arg.name().to_upper_camel_case(), + index, + )?; + } + for (index, arg) in abi.args().iter().enumerate() { + let decoding = match Self::bcs_primitive_type_name(arg.type_tag()) { + None => { + let type_tag_str = format!("{}", (arg.type_tag())); + if "vector<0x1::string::String>".eq(&type_tag_str) { + format!( + "bcs.NewDeserializer(script.Value.Args[{}]).DeserializeVecBytes()", + index, + ) + } else { + let quoted_type = Self::quote_type(arg.type_tag()); + let splits: Vec<_> = quoted_type.rsplitn(2, '.').collect(); + let (left, right) = if splits.len() == 2 { + (splits[1], splits[0]) + } else { + (splits[0], "") + }; + format!( + "{}.BcsDeserialize{}(script.Value.Args[{}])", + left, right, index, + ) + } + }, + Some(type_name) => match type_name { + "VecAddress" => format!( + r#" +var val {0} +if err := deserializer.IncreaseContainerDepth(); err != nil {{ + return ({0})(val), err +}} +length, err := deserializer.DeserializeI8() +if err != nil {{ + return nil, err +}} +var tmp {0} +for i := 0; i < int(length); i++ {{ + if obj, err := deserialize_array32_u8_array(deserializer); err == nil {{ + tmp = obj + }} else {{ + return (({0})(val)), err + }} + val = append(val, tmp) +}} + +deserializer.DecreaseContainerDepth() +call.{1} = val +"#, + Self::quote_type(arg.type_tag()), + arg.name().to_upper_camel_case() + ), + _ => format!( + "bcs.NewDeserializer(script.Value.Args[{}]).Deserialize{}()", + index, type_name + ), + }, + }; + if Self::bcs_primitive_type_name(arg.type_tag()) != Some("VecAddress") { + writeln!( + self.out, + r#" +if val, err := {}; err == nil {{ + call.{} = val +}} else {{ + return nil, err +}} +"#, + decoding, + arg.name().to_upper_camel_case(), + )?; + } + } + writeln!(self.out, "return &call, nil")?; + self.out.unindent(); + writeln!( + self.out, + r#"default: + return nil, fmt.Errorf("Unexpected TransactionPayload encountered when decoding a entry function")"# + )?; + + self.out.unindent(); + writeln!(self.out, "}}")?; + self.out.unindent(); + writeln!(self.out, "}}")?; + Ok(()) + } + + fn output_transaction_script_decoder_map( + &mut self, + abis: &[TransactionScriptABI], + ) -> Result<()> { + writeln!( + self.out, + r#" +var script_decoder_map = map[string]func(*aptostypes.Script) (ScriptCall, error) {{"# + )?; + self.out.indent(); + for abi in abis { + writeln!(self.out, "string({0}_code): decode_{0},", abi.name(),)?; + } + self.out.unindent(); + writeln!(self.out, "}}") + } + + fn output_entry_function_decoder_map(&mut self, abis: &[EntryFunctionABI]) -> Result<()> { + writeln!( + self.out, + r#" +var entry_function_decoder_map = map[string]func(aptostypes.TransactionPayload) (EntryFunctionCall, error) {{"# + )?; + self.out.indent(); + for abi in abis { + writeln!( + self.out, + "\"{0}_{1}\": decode_{0}_{1},", + abi.module_name().name(), + abi.name(), + )?; + } + self.out.unindent(); + writeln!(self.out, "}}") + } + + fn output_encoding_helpers(&mut self, abis: &[EntryABI]) -> Result<()> { + let required_types = common::get_required_helper_types(abis); + for required_type in required_types { + self.output_encoding_helper(required_type)?; + } + Ok(()) + } + + fn output_encoding_helper(&mut self, type_tag: &TypeTag) -> Result<()> { + let encoding = match Self::bcs_primitive_type_name(type_tag) { + None => { + if "vecstring".eq(&common::mangle_type(type_tag)) { + "return encode_vecbytes_argument(arg)".to_string() + } else { + format!( + r#" + if val, err := arg.BcsSerialize(); err == nil {{ + return val; + }} + panic("Unable to serialize argument of type {}"); + "#, + common::mangle_type(type_tag) + ) + } + }, + Some(type_name) => match type_name { + "VecAddress" => r#" + obj := []byte{ } + obj = append(obj, byte(len(arg))) + for _, val := range arg {{ + valBytes := encode_address_argument(val) + obj = append(obj, valBytes...) + }} + return obj"# + .into(), + _ => format!( + r#" + s := bcs.NewSerializer(); + if err := s.Serialize{}(arg); err == nil {{ + return s.GetBytes(); + }} + panic("Unable to serialize argument of type {}"); + "#, + type_name, + common::mangle_type(type_tag) + ), + }, + }; + writeln!( + self.out, + r#" +func encode_{}_argument(arg {}) []byte {{ + {} +}} +"#, + common::mangle_type(type_tag), + Self::quote_type(type_tag), + encoding + ) + } + + fn output_decoding_helpers(&mut self, abis: &[EntryABI]) -> Result<()> { + let required_types = common::get_required_helper_types(abis); + for required_type in required_types { + self.output_decoding_helper(required_type)?; + } + Ok(()) + } + + fn output_decoding_helper(&mut self, type_tag: &TypeTag) -> Result<()> { + use TypeTag::*; + let default_stmt = format!("value = {}(*arg)", Self::quote_type(type_tag)); + let (constructor, stmt) = match type_tag { + Bool => ("Bool", default_stmt), + U8 => ("U8", default_stmt), + U16 => ("U16", default_stmt), + U32 => ("U32", default_stmt), + U64 => ("U64", default_stmt), + U128 => ("U128", default_stmt), + U256 => ("U256", default_stmt), + Address => ("Address", "value = arg.Value".into()), + Vector(type_tag) => match type_tag.as_ref() { + U8 => ("U8Vector", default_stmt), + _ => common::type_not_allowed(type_tag), + }, + Struct(_) | Signer => common::type_not_allowed(type_tag), + }; + writeln!( + self.out, + r#" +func decode_{0}_argument(arg aptostypes.TransactionArgument) (value {1}, err error) {{ + if arg, ok := arg.(*aptostypes.TransactionArgument__{2}); ok {{ + {3} + }} else {{ + err = fmt.Errorf("Was expecting a {2} argument") + }} + return +}} +"#, + common::mangle_type(type_tag), + Self::quote_type(type_tag), + constructor, + stmt, + ) + } + + fn output_code_constant(&mut self, abi: &EntryABI) -> Result<()> { + if let EntryABI::TransactionScript(abi) = abi { + writeln!( + self.out, + "\nvar {}_code = []byte {{{}}};", + abi.name(), + abi.code() + .iter() + .map(|x| format!("{}", x)) + .collect::>() + .join(", ") + )?; + } + Ok(()) + } + + fn quote_identifier(ident: &str) -> String { + format!("\"{}\"", ident) + } + + fn quote_address(address: &AccountAddress) -> String { + format!( + "[32]uint8{{ {} }}", + address + .to_vec() + .iter() + .map(|x| format!("{}", x)) + .collect::>() + .join(", ") + ) + } + + fn quote_module_id(module_id: &ModuleId) -> String { + format!( + "aptostypes.ModuleId {{ Address: {}, Name: {} }}", + Self::quote_address(module_id.address()), + Self::quote_identifier(module_id.name().as_str()), + ) + } + + fn quote_doc(doc: &str) -> String { + let doc = crate::common::prepare_doc_string(doc); + textwrap::indent(&doc, "// ").replace("\n\n", "\n//\n") + } + + fn quote_type_parameters(ty_args: &[TypeArgumentABI]) -> Vec { + ty_args + .iter() + .map(|ty_arg| format!("{} aptostypes.TypeTag", ty_arg.name())) + .collect() + } + + fn quote_parameters(args: &[ArgumentABI]) -> Vec { + args.iter() + .map(|arg| format!("{} {}", arg.name(), Self::quote_type(arg.type_tag()))) + .collect() + } + + fn quote_type_arguments(ty_args: &[TypeArgumentABI]) -> String { + ty_args + .iter() + .map(|ty_arg| ty_arg.name().to_string()) + .collect::>() + .join(", ") + } + + fn quote_arguments(args: &[ArgumentABI]) -> String { + args.iter() + .map(|arg| Self::quote_transaction_argument(arg.type_tag(), arg.name())) + .collect::>() + .join(", ") + } + + fn quote_arguments_for_script(args: &[ArgumentABI]) -> String { + args.iter() + .map(|arg| Self::quote_transaction_argument_for_script(arg.type_tag(), arg.name())) + .collect::>() + .join(", ") + } + + fn quote_type(type_tag: &TypeTag) -> String { + use TypeTag::*; + let str_tag: Lazy = + Lazy::new(|| StructTag::from_str("0x1::string::String").unwrap()); + match type_tag { + Bool => "bool".into(), + U8 => "uint8".into(), + U16 => "uint16".into(), + U32 => "uint32".into(), + U64 => "uint64".into(), + U128 => "serde.Uint128".into(), + U256 => unimplemented!(), + Address => "aptostypes.AccountAddress".into(), + Vector(type_tag) => { + format!("[]{}", Self::quote_type(type_tag)) + }, + Struct(struct_tag) => match struct_tag { + tag if &**tag == Lazy::force(&str_tag) => "[]uint8".into(), + _ => common::type_not_allowed(type_tag), + }, + Signer => common::type_not_allowed(type_tag), + } + } + + fn quote_transaction_argument(type_tag: &TypeTag, name: &str) -> String { + format!( + "encode_{}_argument({})", + common::mangle_type(type_tag), + name + ) + } + + fn quote_transaction_argument_for_script(type_tag: &TypeTag, name: &str) -> String { + use TypeTag::*; + match type_tag { + Bool => format!("(*aptostypes.TransactionArgument__Bool)(&{})", name), + U8 => format!("(*aptostypes.TransactionArgument__U8)(&{})", name), + U16 => format!("(*aptostypes.TransactionArgument__U16)(&{})", name), + U32 => format!("(*aptostypes.TransactionArgument__U32)(&{})", name), + U64 => format!("(*aptostypes.TransactionArgument__U64)(&{})", name), + U128 => format!("(*aptostypes.TransactionArgument__U128)(&{})", name), + U256 => format!("(*aptostypes.TransactionArgument__U256)(&{})", name), + Address => format!("&aptostypes.TransactionArgument__Address{{{}}}", name), + Vector(type_tag) => match type_tag.as_ref() { + U8 => format!("(*aptostypes.TransactionArgument__U8Vector)(&{})", name), + _ => common::type_not_allowed(type_tag), + }, + Struct(_) | Signer => common::type_not_allowed(type_tag), + } + } + + // - if a `type_tag` is a primitive type in BCS, we can call + // `NewSerializer().Serialize(arg)` and `NewDeserializer().Deserialize(arg)` + // to convert into and from `[]byte`. + // - otherwise, we can use `.BcsSerialize()`, `.BcsDeserialize()` to do the work. + fn bcs_primitive_type_name(type_tag: &TypeTag) -> Option<&'static str> { + use TypeTag::*; + let str_tag: Lazy = + Lazy::new(|| StructTag::from_str("0x1::string::String").unwrap()); + match type_tag { + Bool => Some("Bool"), + U8 => Some("U8"), + U16 => Some("U16"), + U32 => Some("U32"), + U64 => Some("U64"), + U128 => Some("U128"), + U256 => None, + Address => None, + Vector(type_tag) => match type_tag.as_ref() { + U8 => Some("Bytes"), + Vector(type_tag) => match type_tag.as_ref() { + U8 => Some("VecBytes"), + type_tag => Self::bcs_primitive_type_name(type_tag).and(None), + }, + Address => Some("VecAddress"), + type_tag => Self::bcs_primitive_type_name(type_tag).and(None), + }, + Struct(struct_tag) => match struct_tag { + tag if &**tag == Lazy::force(&str_tag) => Some("Bytes"), + _ => common::type_not_allowed(type_tag), + }, + Signer => common::type_not_allowed(type_tag), + } + } +} + +pub struct Installer { + install_dir: PathBuf, + serde_module_path: Option, + aptos_module_path: Option, +} + +impl Installer { + pub fn new( + install_dir: PathBuf, + serde_module_path: Option, + aptos_module_path: Option, + ) -> Self { + Installer { + install_dir, + serde_module_path, + aptos_module_path, + } + } +} + +impl crate::SourceInstaller for Installer { + type Error = Box; + + fn install_transaction_builders( + &self, + name: &str, + abis: &[EntryABI], + ) -> std::result::Result<(), Self::Error> { + let dir_path = self.install_dir.join(name); + std::fs::create_dir_all(&dir_path)?; + let mut file = std::fs::File::create(dir_path.join("lib.go"))?; + output( + &mut file, + self.serde_module_path.clone(), + self.aptos_module_path.clone(), + name.to_string(), + abis, + )?; + Ok(()) + } +} diff --git a/vm/starcoin-sdk-builder/src/lib.rs b/vm/starcoin-sdk-builder/src/lib.rs new file mode 100644 index 0000000000..f29e70ce75 --- /dev/null +++ b/vm/starcoin-sdk-builder/src/lib.rs @@ -0,0 +1,69 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use aptos_types::transaction::EntryABI; +use std::{ffi::OsStr, fs, io::Read, path::Path}; + +pub mod golang; +pub mod rust; + +/// Internals shared between languages. +mod common; + +fn get_abi_paths(dir: &Path) -> std::io::Result> { + let mut abi_paths = Vec::new(); + if dir.is_dir() { + for entry in fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + abi_paths.append(&mut get_abi_paths(&path)?); + } else if let Some("abi") = path.extension().and_then(OsStr::to_str) { + abi_paths.push(path.to_str().unwrap().to_string()); + } + } + } + Ok(abi_paths) +} + +/// Read all ABI files the specified directories. This supports both new and old `EntryABI`s. +pub fn read_abis(dir_paths: &[impl AsRef]) -> anyhow::Result> { + let mut abis = Vec::::new(); + for dir in dir_paths.iter() { + for path in get_abi_paths(dir.as_ref())? { + let mut buffer = Vec::new(); + let mut f = std::fs::File::open(path)?; + f.read_to_end(&mut buffer)?; + abis.push(bcs::from_bytes(&buffer)?); + } + } + + // Sort functions by (module, function) lexicographical order + #[allow(clippy::unnecessary_sort_by)] + abis.sort_by(|a, b| { + let a0 = match a { + EntryABI::EntryFunction(sf) => sf.module_name().to_string(), + _ => "".to_owned(), + }; + let b0 = match b { + EntryABI::EntryFunction(sf) => sf.module_name().to_string(), + _ => "".to_owned(), + }; + + (a0, a.name()).cmp(&(b0, b.name())) + }); + Ok(abis) +} + +/// How to copy ABI-generated source code for a given language. +pub trait SourceInstaller { + type Error; + + /// Create a module exposing the transaction builders for the given ABIs. + fn install_transaction_builders( + &self, + name: &str, + abis: &[EntryABI], + ) -> std::result::Result<(), Self::Error>; +} diff --git a/vm/starcoin-sdk-builder/src/main.rs b/vm/starcoin-sdk-builder/src/main.rs new file mode 100644 index 0000000000..8597e7769c --- /dev/null +++ b/vm/starcoin-sdk-builder/src/main.rs @@ -0,0 +1,154 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +//! # Code generator for Move script builders +//! +//! '''bash +//! cargo run -p aptos-sdk-builder -- --help +//! ''' + +use clap::{Parser, ValueEnum}; +use serde_generate as serdegen; +use serde_reflection::Registry; +use std::path::PathBuf; + +#[derive(ValueEnum, Debug, Clone, Copy)] +enum Language { + Rust, + Go, +} + +#[derive(Debug, Parser)] +#[clap(name = "Aptos SDK Builder", about = "Generate boilerplate Aptos SDKs")] +struct Options { + /// Path to the directory containing ABI files in BCS encoding. + abi_directories: Vec, + + /// Language for code generation. + #[clap(long, value_enum, ignore_case = true, default_value_t = Language::Rust)] + language: Language, + + /// Directory where to write generated modules (otherwise print code on stdout). + #[clap(long)] + target_source_dir: Option, + + /// Also install the aptos types described by the given YAML file, along with the BCS runtime. + #[clap(long)] + with_aptos_types: Option, + + /// Module name for the transaction builders installed in the `target_source_dir`. + /// * Rust crates may contain a version number, e.g. "test:1.2.0". + /// * In Java, this is expected to be a package name, e.g. "com.test" to create Java files in `com/test`. + /// * In Go, this is expected to be of the format "go_module/path/go_package_name", + /// and `aptos_types` is assumed to be in "go_module/path/aptos_types". + #[clap(long)] + module_name: Option, + + /// Optional package name (Python) or module path (Go) of the Serde and BCS runtime dependencies. + #[clap(long)] + serde_package_name: Option, + + /// Optional version number for the `aptos_types` module (useful in Rust). + /// If `--with-aptos-types` is passed, this will be the version of the generated `aptos_types` module. + #[clap(long, default_value = "0.1.0")] + aptos_version_number: String, + + /// Optional package name (Python) or module path (Go) of the `aptos_types` dependency. + #[clap(long)] + package_name: Option, +} + +fn main() { + let options = Options::parse(); + let abis = aptos_sdk_builder::read_abis(&options.abi_directories) + .expect("Failed to read ABI in directory"); + + let install_dir = match options.target_source_dir { + None => { + // Nothing to install. Just print to stdout. + let stdout = std::io::stdout(); + let mut out = stdout.lock(); + match options.language { + Language::Rust => { + aptos_sdk_builder::rust::output(&mut out, &abis, /* local types */ true) + .unwrap() + }, + Language::Go => { + aptos_sdk_builder::golang::output( + &mut out, + options.serde_package_name.clone(), + options.package_name.clone(), + options.module_name.as_deref().unwrap_or("main").to_string(), + &abis, + ) + .unwrap(); + }, + } + return; + }, + Some(dir) => dir, + }; + + // Aptos types + if let Some(registry_file) = options.with_aptos_types { + let installer: Box>> = + match options.language { + Language::Rust => Box::new(serdegen::rust::Installer::new(install_dir.clone())), + Language::Go => Box::new(serdegen::golang::Installer::new( + install_dir.clone(), + options.serde_package_name.clone(), + )), + }; + + let content = + std::fs::read_to_string(registry_file).expect("registry file must be readable"); + let mut registry = serde_yaml::from_str::(content.as_str()).unwrap(); + // update the registry to prevent language keyword being used + if let Language::Rust = options.language { + aptos_sdk_builder::rust::replace_keywords(&mut registry) + } + + let (package_name, _package_path) = match options.language { + Language::Rust => ( + if options.aptos_version_number == "0.1.0" { + "aptos-types".to_string() + } else { + format!("aptos-types:{}", options.aptos_version_number) + }, + vec!["aptos-types"], + ), + Language::Go => ("aptostypes".to_string(), vec!["aptostypes"]), + }; + + let config = serdegen::CodeGeneratorConfig::new(package_name) + .with_encodings(vec![serdegen::Encoding::Bcs]); + + installer.install_module(&config, ®istry).unwrap(); + } + + // Transaction builders + let installer: Box>> = + match options.language { + Language::Rust => Box::new(aptos_sdk_builder::rust::Installer::new( + install_dir, + options.aptos_version_number, + )), + Language::Go => Box::new(aptos_sdk_builder::golang::Installer::new( + install_dir, + options.serde_package_name, + options.package_name, + )), + }; + + if let Some(ref name) = options.module_name { + installer + .install_transaction_builders(name, abis.as_slice()) + .unwrap(); + } +} + +#[test] +fn verify_tool() { + use clap::CommandFactory; + Options::command().debug_assert() +} diff --git a/vm/starcoin-sdk-builder/src/rust.rs b/vm/starcoin-sdk-builder/src/rust.rs new file mode 100644 index 0000000000..cc01736cb3 --- /dev/null +++ b/vm/starcoin-sdk-builder/src/rust.rs @@ -0,0 +1,1007 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::common; +use aptos_types::transaction::{ + ArgumentABI, EntryABI, EntryFunctionABI, TransactionScriptABI, TypeArgumentABI, +}; +use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{ModuleId, StructTag, TypeTag}, +}; +use once_cell::sync::Lazy; +use serde_generate::{ + indent::{IndentConfig, IndentedWriter}, + rust, CodeGeneratorConfig, +}; +use serde_reflection::ContainerFormat; +use std::{ + collections::BTreeMap, + io::{Result, Write}, + path::PathBuf, + str::FromStr, +}; + +/// Output transaction builders in Rust for the given ABIs. +/// If `local_types` is true, we generate a file suitable for the Aptos codebase itself +/// rather than using serde-generated, standalone definitions. +pub fn output(out: &mut dyn Write, abis: &[EntryABI], local_types: bool) -> Result<()> { + if abis.is_empty() { + return Ok(()); + } + let mut emitter = RustEmitter { + out: IndentedWriter::new(out, IndentConfig::Space(4)), + local_types, + }; + + emitter.output_preamble()?; + writeln!(emitter.out, "#![allow(dead_code)]")?; + writeln!(emitter.out, "#![allow(unused_imports)]")?; + writeln!(emitter.out, "#![allow(clippy::too_many_arguments)]")?; + writeln!(emitter.out, "#![allow(clippy::arc_with_non_send_sync)]")?; + writeln!(emitter.out, "#![allow(clippy::get_first)]")?; + + emitter.output_script_call_enum_with_imports(abis)?; + + let txn_script_abis = common::transaction_script_abis(abis); + let entry_function_abis = common::entry_function_abis(abis); + + if !txn_script_abis.is_empty() { + emitter.output_transaction_script_impl(&txn_script_abis)?; + } + if !entry_function_abis.is_empty() { + emitter.output_entry_function_impl(&entry_function_abis)?; + } + + for abi in abis { + emitter.output_script_encoder_function(abi)?; + } + + write!(emitter.out, "mod decoder {{")?; + write!(emitter.out, " use super::*;")?; + for abi in abis { + emitter.output_script_decoder_function(abi)?; + } + writeln!(emitter.out, "}}")?; + + if !txn_script_abis.is_empty() { + emitter.output_transaction_script_decoder_map(&txn_script_abis)?; + } + if !entry_function_abis.is_empty() { + emitter.output_entry_function_decoder_map(&entry_function_abis)?; + } + + emitter.output_decoding_helpers(&common::filter_transaction_scripts(abis))?; + + for abi in &txn_script_abis { + emitter.output_code_constant(abi)?; + } + Ok(()) +} + +/// Shared state for the Rust code generator. +struct RustEmitter { + /// Writer. + out: IndentedWriter, + /// Whether we are targeting the Aptos repository itself (as opposed to generated Aptos types). + local_types: bool, +} + +impl RustEmitter +where + T: Write, +{ + fn output_transaction_script_impl( + &mut self, + transaction_script_abis: &[TransactionScriptABI], + ) -> Result<()> { + writeln!(self.out, "\nimpl ScriptCall {{")?; + self.out.indent(); + self.output_transaction_script_encode_method(transaction_script_abis)?; + self.output_transaction_script_decode_method()?; + self.output_transaction_script_name_method(transaction_script_abis)?; + self.out.unindent(); + writeln!(self.out, "\n}}") + } + + fn output_entry_function_impl( + &mut self, + entry_function_abis: &[EntryFunctionABI], + ) -> Result<()> { + writeln!(self.out, "\nimpl EntryFunctionCall {{")?; + self.out.indent(); + self.output_entry_function_encode_method(entry_function_abis)?; + self.output_entry_function_decode_method()?; + self.out.unindent(); + writeln!(self.out, "\n}}") + } + + fn output_preamble(&mut self) -> Result<()> { + if self.local_types { + writeln!( + self.out, + r#" +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +// This file was generated. Do not modify! +// +// To update this code, run: `cargo run --release -p framework`. +"# + )?; + } + writeln!( + self.out, + r#"// Conversion library between a structured representation of a Move script call (`ScriptCall`) and the +// standard BCS-compatible representation used in Aptos transactions (`Script`). +// +// This code was generated by compiling known Script interfaces ("ABIs") with the tool `aptos-sdk-builder`. +"# + ) + } + + fn output_script_call_enum_with_imports(&mut self, abis: &[EntryABI]) -> Result<()> { + let external_definitions = Self::get_external_definitions(self.local_types); + let (transaction_script_abis, entry_fun_abis): (Vec<_>, Vec<_>) = abis + .iter() + .cloned() + .partition(|abi| abi.is_transaction_script_abi()); + + let has_script = !transaction_script_abis.is_empty(); + let mut script_registry: BTreeMap<_, _> = if has_script { + vec![( + "ScriptCall".to_string(), + common::make_abi_enum_container(transaction_script_abis.as_slice()), + )] + .into_iter() + .collect() + } else { + BTreeMap::new() + }; + + let mut entry_function_registry: BTreeMap<_, _> = vec![( + "EntryFunctionCall".to_string(), + common::make_abi_enum_container(entry_fun_abis.as_slice()), + )] + .into_iter() + .collect(); + + script_registry.append(&mut entry_function_registry); + let mut comments: BTreeMap<_, _> = abis + .iter() + .map(|abi| { + ( + vec![ + "crate".to_string(), + if abi.is_transaction_script_abi() { + "ScriptCall" + } else { + "EntryFunctionCall" + } + .to_string(), + match abi { + EntryABI::EntryFunction(sf) => { + format!( + "{}{}", + sf.module_name().name().to_string().to_upper_camel_case(), + abi.name().to_upper_camel_case() + ) + }, + _ => abi.name().to_upper_camel_case(), + }, + ], + common::prepare_doc_string(abi.doc()), + ) + }) + .collect(); + + if has_script { + comments.insert( + vec!["crate".to_string(), "ScriptCall".to_string()], + r#"Structured representation of a call into a known Move script. +```ignore +impl ScriptCall { + pub fn encode(self) -> Script { .. } + pub fn decode(&Script) -> Option { .. } +} +``` +"# + .into(), + ); + } + + comments.insert( + vec!["crate".to_string(), "EntryFunctionCall".to_string()], + r#"Structured representation of a call into a known Move entry function. +```ignore +impl EntryFunctionCall { + pub fn encode(self) -> TransactionPayload { .. } + pub fn decode(&TransactionPayload) -> Option { .. } +} +``` +"# + .into(), + ); + + let custom_derive_block = if self.local_types { + Some( + r#"#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] +#[cfg_attr(feature = "fuzzing", proptest(no_params))]"# + .to_string(), + ) + } else { + None + }; + // Deactivate serialization for local types to force `Bytes = Vec`. + let config = CodeGeneratorConfig::new("crate".to_string()) + .with_comments(comments) + .with_external_definitions(external_definitions) + .with_serialization(!self.local_types); + + // If you get an error here, you may need to add a new type to + // `get_external_definitions` below + rust::CodeGenerator::new(&config) + .with_derive_macros(vec![ + "Clone".to_string(), + "Debug".to_string(), + "PartialEq".to_string(), + "Eq".to_string(), + ]) + .with_custom_derive_block(custom_derive_block) + .output(&mut self.out, &script_registry) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", err)))?; + Ok(()) + } + + fn get_external_definitions(local_types: bool) -> serde_generate::ExternalDefinitions { + let definitions = if local_types { + vec![ + ("move_core_types::language_storage", vec![ + "ModuleId", "TypeTag", + ]), + ("move_core_types", vec!["ident_str"]), + ("aptos_types::transaction", vec![ + "TransactionPayload", + "EntryFunction", + ]), + ("aptos_types::account_address", vec!["AccountAddress"]), + ] + } else { + vec![("aptos_types", vec![ + "AccountAddress", + "TypeTag", + "Script", + "EntryFunction", + "TransactionArgument", + "TransactionPayload", + "ModuleId", + "Identifier", + ])] + }; + + definitions + .into_iter() + .map(|(module, defs)| { + ( + module.to_string(), + defs.into_iter().map(String::from).collect(), + ) + }) + .collect() + } + + fn output_transaction_script_encode_method( + &mut self, + abis: &[TransactionScriptABI], + ) -> Result<()> { + writeln!( + self.out, + r#" +/// Build an Aptos `Script` from a structured object `ScriptCall`. +pub fn encode(self) -> Script {{"# + )?; + self.out.indent(); + writeln!(self.out, "use ScriptCall::*;\nmatch self {{")?; + self.out.indent(); + for abi in abis { + self.output_variant_encoder(&EntryABI::TransactionScript(abi.clone()))?; + } + self.out.unindent(); + writeln!(self.out, "}}")?; + self.out.unindent(); + writeln!(self.out, "}}\n") + } + + fn output_entry_function_encode_method(&mut self, abis: &[EntryFunctionABI]) -> Result<()> { + writeln!( + self.out, + r#" +/// Build an Aptos `TransactionPayload` from a structured object `EntryFunctionCall`. +pub fn encode(self) -> TransactionPayload {{"# + )?; + self.out.indent(); + writeln!(self.out, "use EntryFunctionCall::*;\nmatch self {{")?; + self.out.indent(); + for abi in abis { + self.output_variant_encoder(&EntryABI::EntryFunction(abi.clone()))?; + } + self.out.unindent(); + writeln!(self.out, "}}")?; + self.out.unindent(); + writeln!(self.out, "}}\n") + } + + fn output_variant_encoder(&mut self, abi: &EntryABI) -> Result<()> { + let params = std::iter::empty() + .chain(abi.ty_args().iter().map(TypeArgumentABI::name)) + .chain(abi.args().iter().map(ArgumentABI::name)) + .collect::>() + .join(", "); + + let prefix = if let EntryABI::EntryFunction(sf) = abi { + sf.module_name().name().to_string().to_upper_camel_case() + } else { + String::new() + }; + writeln!( + self.out, + "{5}{0}{{{2}}} => {3}{4}{1}({2}),", + abi.name().to_upper_camel_case(), + abi.name(), + params, + prefix.to_snake_case(), + if prefix.is_empty() { "" } else { "_" }, + prefix, + ) + } + + fn output_transaction_script_decode_method(&mut self) -> Result<()> { + writeln!( + self.out, + r#" +/// Try to recognize an Aptos `Script` and convert it into a structured object `ScriptCall`. +pub fn decode(script: &Script) -> Option {{ + match TRANSACTION_SCRIPT_DECODER_MAP.get({}) {{ + Some(decoder) => decoder(script), + None => None, + }} +}}"#, + if self.local_types { + "script.code()" + } else { + "&script.code.clone().into_vec()" + } + ) + } + + fn output_entry_function_decode_method(&mut self) -> Result<()> { + writeln!( + self.out, + r#" +/// Try to recognize an Aptos `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!("{{}}_{{}}", {}, {})) {{ + Some(decoder) => decoder(payload), + None => None, + }} + }} else {{ + None + }} +}}"#, + if self.local_types { + "script.module().name()" + } else { + "script.module.name.0" + }, + if self.local_types { + "script.function()" + } else { + "script.function.0" + } + ) + } + + fn output_transaction_script_name_method( + &mut self, + abis: &[TransactionScriptABI], + ) -> Result<()> { + writeln!( + self.out, + r#" +/// Return the name of an Aptos `Script` from a structured object `ScriptCall`. +pub fn name(&self) -> &'static str {{"# + )?; + self.out.indent(); + writeln!(self.out, "use ScriptCall::*;\nmatch self {{")?; + self.out.indent(); + for abi in abis { + writeln!( + self.out, + "{} {{ .. }} => \"{}\",", + abi.name().to_upper_camel_case(), + abi.name(), + )?; + } + self.out.unindent(); + writeln!(self.out, "}}")?; + self.out.unindent(); + writeln!(self.out, "}}\n") + } + + fn output_comment(&mut self, indentation: usize, doc: &str) -> std::io::Result<()> { + let prefix = " ".repeat(indentation) + "/// "; + let empty_line = "\n".to_string() + &" ".repeat(indentation) + "///\n"; + let text = textwrap::indent(doc, &prefix).replace("\n\n", &empty_line); + write!(self.out, "\n{}\n", text) + } + + fn emit_transaction_script_encoder_function( + &mut self, + abi: &TransactionScriptABI, + ) -> Result<()> { + write!( + self.out, + "pub fn {}_script({}) -> Script {{", + abi.name(), + [ + Self::quote_type_parameters(abi.ty_args()), + Self::quote_parameters(abi.args(), self.local_types), + ] + .concat() + .join(", ") + )?; + self.out.indent(); + if self.local_types { + writeln!( + self.out, + r#" +Script::new( + {}_CODE.to_vec(), + vec![{}], + vec![{}], +)"#, + abi.name().to_shouty_snake_case(), + Self::quote_type_arguments(abi.ty_args()), + Self::quote_arguments_for_script(abi.args()), + )?; + } else { + writeln!( + self.out, + r#" +Script {{ + code: Bytes::from({}_CODE.to_vec()), + ty_args: vec![{}], + args: vec![{}], +}}"#, + abi.name().to_shouty_snake_case(), + Self::quote_type_arguments(abi.ty_args()), + Self::quote_arguments_for_script(abi.args()), + )?; + } + self.out.unindent(); + writeln!(self.out, "}}")?; + Ok(()) + } + + fn emit_entry_function_encoder_function(&mut self, abi: &EntryFunctionABI) -> Result<()> { + write!( + self.out, + "pub fn {}_{}({}) -> TransactionPayload {{", + abi.module_name().name().to_string().to_snake_case(), + abi.name(), + [ + Self::quote_type_parameters(abi.ty_args()), + Self::quote_parameters(abi.args(), self.local_types), + ] + .concat() + .join(", ") + )?; + self.out.indent(); + if self.local_types { + writeln!( + self.out, + r#" +TransactionPayload::EntryFunction(EntryFunction::new( + {}, + {}, + vec![{}], + vec![{}], +))"#, + self.quote_module_id(abi.module_name()), + self.quote_identifier(abi.name()), + Self::quote_type_arguments(abi.ty_args()), + Self::quote_arguments(abi.args(), /* local_types */ true), + )?; + } else { + writeln!( + self.out, + r#" +TransactionPayload::EntryFunction(EntryFunction {{ + module: {}, + function: {}, + ty_args: vec![{}], + args: vec![{}], +}})"#, + self.quote_module_id(abi.module_name()), + self.quote_identifier(abi.name()), + Self::quote_type_arguments(abi.ty_args()), + Self::quote_arguments(abi.args(), /* local_types */ false), + )?; + } + self.out.unindent(); + writeln!(self.out, "}}")?; + Ok(()) + } + + fn output_script_encoder_function(&mut self, abi: &EntryABI) -> Result<()> { + self.output_comment(0, &common::prepare_doc_string(abi.doc()))?; + match abi { + EntryABI::TransactionScript(abi) => self.emit_transaction_script_encoder_function(abi), + EntryABI::EntryFunction(abi) => self.emit_entry_function_encoder_function(abi), + } + } + + fn output_script_decoder_function(&mut self, abi: &EntryABI) -> Result<()> { + match abi { + EntryABI::TransactionScript(abi) => self.emit_transaction_script_decoder_function(abi), + EntryABI::EntryFunction(abi) => self.emit_entry_function_decoder_function(abi), + } + } + + fn emit_entry_function_decoder_function(&mut self, abi: &EntryFunctionABI) -> Result<()> { + // `payload` is always used, so don't need to fix warning "unused variable" by prefixing with "_" + // + writeln!( + self.out, + "\npub fn {}_{}(payload: &TransactionPayload) -> Option {{", + abi.module_name().name().to_string().to_snake_case(), + abi.name(), + )?; + self.out.indent(); + writeln!( + self.out, + "if let TransactionPayload::EntryFunction({}script) = payload {{", + // fix warning "unused variable" + if abi.ty_args().is_empty() && abi.args().is_empty() { + "_" + } else { + "" + } + )?; + self.out.indent(); + writeln!( + self.out, + "Some(EntryFunctionCall::{}{} {{", + abi.module_name().name().to_string().to_upper_camel_case(), + abi.name().to_upper_camel_case(), + )?; + self.out.indent(); + for (index, ty_arg) in abi.ty_args().iter().enumerate() { + writeln!( + self.out, + "{} : script.ty_args{}.get({})?.clone(),", + ty_arg.name(), + if self.local_types { "()" } else { "" }, + index, + )?; + } + for (index, arg) in abi.args().iter().enumerate() { + writeln!( + self.out, + "{} : bcs::from_bytes(script.args{}.get({})?).ok()?,", + arg.name(), + if self.local_types { "()" } else { "" }, + index, + )?; + } + self.out.unindent(); + writeln!(self.out, "}})")?; + self.out.unindent(); + writeln!(self.out, "}} else {{")?; + self.out.indent(); + writeln!(self.out, "None")?; + self.out.unindent(); + writeln!(self.out, "}}")?; + self.out.unindent(); + writeln!(self.out, "}}") + } + + fn emit_transaction_script_decoder_function( + &mut self, + abi: &TransactionScriptABI, + ) -> Result<()> { + writeln!( + self.out, + "\npub fn {}_script({}script: &Script) -> Option {{", + abi.name(), + // fix warning "unused variable" + if abi.ty_args().is_empty() && abi.args().is_empty() { + "_" + } else { + "" + } + )?; + self.out.indent(); + writeln!( + self.out, + "Some(ScriptCall::{} {{", + abi.name().to_upper_camel_case(), + )?; + self.out.indent(); + for (index, ty_arg) in abi.ty_args().iter().enumerate() { + writeln!( + self.out, + "{} : script.ty_args{}.get({})?.clone(),", + ty_arg.name(), + if self.local_types { "()" } else { "" }, + index, + )?; + } + for (index, arg) in abi.args().iter().enumerate() { + writeln!( + self.out, + "{} : {}_argument(script.args{}.get({})?.clone())?,", + arg.name(), + common::mangle_type(arg.type_tag()), + if self.local_types { "()" } else { "" }, + index, + )?; + } + self.out.unindent(); + writeln!(self.out, "}})")?; + self.out.unindent(); + writeln!(self.out, "}}")?; + Ok(()) + } + + fn output_transaction_script_decoder_map( + &mut self, + abis: &[TransactionScriptABI], + ) -> Result<()> { + writeln!( + self.out, + r#" +type TransactionScriptDecoderMap = std::collections::HashMap, Box Option + std::marker::Sync + std::marker::Send>>; + +static TRANSACTION_SCRIPT_DECODER_MAP: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| {{"# + )?; + self.out.indent(); + writeln!( + self.out, + "let mut map : TransactionScriptDecoderMap = std::collections::HashMap::new();" + )?; + for abi in abis { + writeln!( + self.out, + "map.insert({}_CODE.to_vec(), Box::new(decoder::{}_script));", + abi.name().to_shouty_snake_case(), + abi.name() + )?; + } + writeln!(self.out, "map")?; + self.out.unindent(); + writeln!(self.out, "}});") + } + + fn output_entry_function_decoder_map(&mut self, abis: &[EntryFunctionABI]) -> Result<()> { + writeln!( + self.out, + r#" +type EntryFunctionDecoderMap = std::collections::HashMap Option + std::marker::Sync + std::marker::Send>>; + +static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| {{"# + )?; + self.out.indent(); + writeln!( + self.out, + "let mut map : EntryFunctionDecoderMap = std::collections::HashMap::new();" + )?; + for abi in abis { + writeln!( + self.out, + "map.insert(\"{}_{}\".to_string(), Box::new(decoder::{}_{}));", + abi.module_name().name(), + abi.name(), + abi.module_name().name().to_string().to_snake_case(), + abi.name() + )?; + } + writeln!(self.out, "map")?; + self.out.unindent(); + writeln!(self.out, "}});") + } + + fn output_decoding_helpers(&mut self, abis: &[EntryABI]) -> Result<()> { + let required_types = common::get_required_helper_types(abis); + for required_type in required_types { + self.output_decoding_helper(required_type)?; + } + Ok(()) + } + + fn output_decoding_helper(&mut self, type_tag: &TypeTag) -> Result<()> { + use TypeTag::*; + let (constructor, expr) = match type_tag { + Bool => ("Bool", "Some(value)".to_string()), + U8 => ("U8", "Some(value)".to_string()), + U16 => ("U16", "Some(value)".to_string()), + U32 => ("U32", "Some(value)".to_string()), + U64 => ("U64", "Some(value)".to_string()), + U128 => ("U128", "Some(value)".to_string()), + U256 => ("U256", "Some(value)".to_string()), + Address => ("Address", "Some(value)".to_string()), + Vector(type_tag) => match type_tag.as_ref() { + U8 => ("U8Vector", "Some(value)".to_string()), + _ => common::type_not_allowed(type_tag), + }, + Struct(_) | Signer => common::type_not_allowed(type_tag), + }; + writeln!( + self.out, + r#" +fn decode_{}_argument(arg: TransactionArgument) -> Option<{}> {{ + match arg {{ + TransactionArgument::{}(value) => {}, + _ => None, + }} +}} +"#, + common::mangle_type(type_tag), + Self::quote_type(type_tag, self.local_types), + constructor, + expr, + ) + } + + fn output_code_constant(&mut self, abi: &TransactionScriptABI) -> Result<()> { + writeln!( + self.out, + "\nconst {}_CODE: &[u8] = &[{}];", + abi.name().to_shouty_snake_case(), + abi.code() + .iter() + .map(|x| format!("{}", x)) + .collect::>() + .join(", ") + )?; + Ok(()) + } + + fn quote_identifier(&self, ident: &str) -> String { + if self.local_types { + format!("ident_str!(\"{}\").to_owned()", ident) + } else { + format!("Identifier(\"{}\".to_string())", ident) + } + } + + fn quote_address(&self, address: &AccountAddress) -> String { + let u8_array = format!( + "[{}]", + address + .to_vec() + .iter() + .map(|x| format!("{}", x)) + .collect::>() + .join(", ") + ); + if self.local_types { + format!("AccountAddress::new({})", u8_array) + } else { + format!("AccountAddress({})", u8_array) + } + } + + fn quote_module_id(&self, module_id: &ModuleId) -> String { + if self.local_types { + format!( + "ModuleId::new( + {}, + {}, + )", + self.quote_address(module_id.address()), + self.quote_identifier(module_id.name().as_str()) + ) + } else { + format!( + "ModuleId {{ + address: {}, + name: {}, + }}", + self.quote_address(module_id.address()), + self.quote_identifier(module_id.name().as_str()) + ) + } + } + + fn quote_type_parameters(ty_args: &[TypeArgumentABI]) -> Vec { + ty_args + .iter() + .map(|ty_arg| format!("{}: TypeTag", ty_arg.name())) + .collect() + } + + fn quote_parameters(args: &[ArgumentABI], local_types: bool) -> Vec { + args.iter() + .map(|arg| { + format!( + "{}: {}", + arg.name(), + Self::quote_type(arg.type_tag(), local_types) + ) + }) + .collect() + } + + fn quote_type_arguments(ty_args: &[TypeArgumentABI]) -> String { + ty_args + .iter() + .map(|ty_arg| ty_arg.name().to_string()) + .collect::>() + .join(", ") + } + + fn quote_arguments(args: &[ArgumentABI], local_types: bool) -> String { + args.iter() + .map(|arg| Self::quote_transaction_argument(arg.type_tag(), arg.name(), local_types)) + .collect::>() + .join(", ") + } + + fn quote_arguments_for_script(args: &[ArgumentABI]) -> String { + args.iter() + .map(|arg| Self::quote_transaction_argument_for_script(arg.type_tag(), arg.name())) + .collect::>() + .join(", ") + } + + // TODO: see if we can avoid passing in local types in this manner + #[allow(clippy::only_used_in_recursion)] + fn quote_type(type_tag: &TypeTag, local_types: bool) -> String { + use TypeTag::*; + let str_tag: Lazy = + Lazy::new(|| StructTag::from_str("0x1::string::String").unwrap()); + match type_tag { + Bool => "bool".into(), + U8 => "u8".into(), + U16 => "u16".into(), + U32 => "u32".into(), + U64 => "u64".into(), + U128 => "u128".into(), + U256 => "U256".into(), + Address => "AccountAddress".into(), + Vector(type_tag) => { + format!("Vec<{}>", Self::quote_type(type_tag.as_ref(), local_types)) + }, + Struct(struct_tag) => match struct_tag { + tag if &**tag == Lazy::force(&str_tag) => "Vec".into(), + _ => common::type_not_allowed(type_tag), + }, + Signer => common::type_not_allowed(type_tag), + } + } + + fn quote_transaction_argument(_type_tag: &TypeTag, name: &str, local_types: bool) -> String { + let conversion = format!("bcs::to_bytes(&{}).unwrap()", name); + if local_types { + conversion + } else { + format!("serde_bytes::ByteBuf::from({})", conversion) + } + } + + fn quote_transaction_argument_for_script(type_tag: &TypeTag, name: &str) -> String { + use TypeTag::*; + match type_tag { + Bool => format!("TransactionArgument::Bool({})", name), + U8 => format!("TransactionArgument::U8({})", name), + U16 => format!("TransactionArgument::U16({})", name), + U32 => format!("TransactionArgument::U32({})", name), + U64 => format!("TransactionArgument::U64({})", name), + U128 => format!("TransactionArgument::U128({})", name), + U256 => format!("TransactionArgument::U256({})", name), + Address => format!("TransactionArgument::Address({})", name), + Vector(type_tag) => match type_tag.as_ref() { + U8 => format!("TransactionArgument::U8Vector({})", name), + _ => common::type_not_allowed(type_tag), + }, + + Struct(_) | Signer => common::type_not_allowed(type_tag), + } + } +} + +pub struct Installer { + install_dir: PathBuf, + aptos_types_version: String, +} + +impl Installer { + pub fn new(install_dir: PathBuf, aptos_types_version: String) -> Self { + Installer { + install_dir, + aptos_types_version, + } + } +} + +impl crate::SourceInstaller for Installer { + type Error = Box; + + fn install_transaction_builders( + &self, + public_name: &str, + abis: &[EntryABI], + ) -> std::result::Result<(), Self::Error> { + let (name, version) = { + let parts = public_name.splitn(2, ':').collect::>(); + if parts.len() >= 2 { + (parts[0].to_string(), parts[1].to_string()) + } else { + (parts[0].to_string(), "0.1.0".to_string()) + } + }; + let dir_path = self.install_dir.join(&name); + std::fs::create_dir_all(&dir_path)?; + let mut cargo = std::fs::File::create(dir_path.join("Cargo.toml"))?; + write!( + cargo, + r#"[package] +name = "{}" +version = "{}" +edition = "2021" + +[dependencies] +once_cell = "1.10.0" +serde = {{ version = "1.0", features = ["derive"] }} +serde_bytes = "0.11.6" +aptos-types = {{ path = "../aptos-types", version = "{}" }} +"#, + name, version, self.aptos_types_version, + )?; + std::fs::create_dir(dir_path.join("src"))?; + let source_path = dir_path.join("src/lib.rs"); + let mut source = std::fs::File::create(source_path)?; + output(&mut source, abis, /* local_types */ false)?; + Ok(()) + } +} + +/// Walks through the registry replacing variables known to be named as a +/// rust keyword, making the resulting codegen invalid. +/// ie: public function: Identifier => public function_name: Identifier +pub fn replace_keywords(registry: &mut BTreeMap) { + swap_keyworded_fields(registry.get_mut("TypeTag")); + swap_keyworded_fields(registry.get_mut("StructTag")); +} + +fn swap_keyworded_fields(fields: Option<&mut ContainerFormat>) { + match fields { + Some(ContainerFormat::Enum(fields)) => { + for (_, val) in fields.iter_mut() { + match val.name.as_str() { + "struct" => val.name = String::from("Struct"), + "bool" => val.name = String::from("Bool"), + "u8" => val.name = String::from("U8"), + "u64" => val.name = String::from("U64"), + "u128" => val.name = String::from("U128"), + "address" => val.name = String::from("Address"), + "signer" => val.name = String::from("Signer"), + "vector" => val.name = String::from("Vector"), + _ => (), + } + } + }, + Some(ContainerFormat::Struct(fields)) => { + for entry in fields.iter_mut() { + if entry.name.as_str() == "type_args" { + entry.name = String::from("type_params") + } + } + }, + _ => (), + } +} diff --git a/vm/starcoin-sdk-builder/tests/cli.rs b/vm/starcoin-sdk-builder/tests/cli.rs new file mode 100644 index 0000000000..8f72fc8c4a --- /dev/null +++ b/vm/starcoin-sdk-builder/tests/cli.rs @@ -0,0 +1,81 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use std::{io::Write, process::Command}; +use tempfile::tempdir; + +const EXPECTED_OUTPUT: &str = "224 1 161 28 235 11 1 0 0 0 7 1 0 2 2 2 4 3 6 16 4 22 2 5 24 29 7 53 96 8 149 1 16 0 0 0 1 1 0 0 2 0 1 0 0 3 2 3 1 1 0 4 1 3 0 1 5 1 6 12 1 8 0 5 6 8 0 5 3 10 2 10 2 0 5 6 12 5 3 10 2 10 2 1 9 0 11 68 105 101 109 65 99 99 111 117 110 116 18 87 105 116 104 100 114 97 119 67 97 112 97 98 105 108 105 116 121 27 101 120 116 114 97 99 116 95 119 105 116 104 100 114 97 119 95 99 97 112 97 98 105 108 105 116 121 8 112 97 121 95 102 114 111 109 27 114 101 115 116 111 114 101 95 119 105 116 104 100 114 97 119 95 99 97 112 97 98 105 108 105 116 121 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 4 1 12 11 0 17 0 12 5 14 5 10 1 10 2 11 3 11 4 56 0 11 5 17 2 2 1 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 88 68 88 3 88 68 88 0 4 3 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 1 135 214 18 0 0 0 0 0 4 0 4 0 \n3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 14 80 97 121 109 101 110 116 83 99 114 105 112 116 115 26 112 101 101 114 95 116 111 95 112 101 101 114 95 119 105 116 104 95 109 101 116 97 100 97 116 97 1 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 88 68 88 3 88 68 88 0 4 16 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 8 135 214 18 0 0 0 0 0 1 0 1 0 \n"; + +#[test] +#[ignore] +fn test_examples_in_readme() -> std::io::Result<()> { + let file = std::io::BufReader::new(std::fs::File::open("README.md")?); + let quotes = get_bash_quotes(file)?; + // Check that we have the expected number of examples starting with "```bash". + assert_eq!(quotes.len(), 14); + + let mut quotes = quotes.into_iter(); + + for _ in 0..4 { + let dir = tempdir().unwrap(); + let mut test_script = std::fs::File::create(dir.path().join("test.sh"))?; + write!(&mut test_script, "{}", quotes.next().unwrap())?; + write!(&mut test_script, "{}", quotes.next().unwrap())?; + let output = Command::new("bash") + .current_dir("../..") // root of Aptos + .env("DEST", dir.path()) + .arg("-e") + .arg("-x") + .arg(dir.path().join("test.sh")) + .output()?; + eprintln!("{}", std::str::from_utf8(&output.stderr).unwrap()); + assert!(output.status.success()); + assert_eq!( + std::str::from_utf8(&output.stdout).unwrap(), + EXPECTED_OUTPUT + ); + } + + // Last quote (Rust) is yet incomplete. + let dir = tempdir().unwrap(); + let mut test_script = std::fs::File::create(dir.path().join("test.sh"))?; + write!(&mut test_script, "{}", quotes.next().unwrap())?; + let output = Command::new("bash") + .current_dir("../..") // root of Aptos + .env("DEST", dir.path()) + .arg("-e") + .arg("-x") + .arg(dir.path().join("test.sh")) + .output()?; + eprintln!("{}", std::str::from_utf8(&output.stderr).unwrap()); + assert!(output.status.success()); + Ok(()) +} + +#[allow(clippy::while_let_on_iterator)] +fn get_bash_quotes(reader: R) -> std::io::Result> +where + R: std::io::BufRead, +{ + let mut result = Vec::new(); + let mut lines = reader.lines(); + + while let Some(line) = lines.next() { + let line = line?; + if line.starts_with("```bash") { + let mut quote = String::new(); + while let Some(line) = lines.next() { + let line = line?; + if line.starts_with("```") { + break; + } + quote += &line; + quote += "\n"; + } + result.push(quote); + } + } + + Ok(result) +} diff --git a/vm/starcoin-sdk-builder/tests/generation.rs b/vm/starcoin-sdk-builder/tests/generation.rs new file mode 100644 index 0000000000..93b17fda34 --- /dev/null +++ b/vm/starcoin-sdk-builder/tests/generation.rs @@ -0,0 +1,95 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use aptos_sdk_builder as buildgen; +use aptos_types::transaction::EntryABI; +use serde_generate as serdegen; +use serde_generate::SourceInstaller as _; +use serde_reflection::Registry; +use std::{io::Write, process::Command}; +use tempfile::tempdir; + +fn get_aptos_registry() -> Registry { + let path = "../../testsuite/generate-format/tests/staged/aptos.yaml"; + let content = std::fs::read_to_string(path).unwrap(); + serde_yaml::from_str::(content.as_str()).unwrap() +} + +const EXPECTED_SCRIPT_FUN_OUTPUT: &str = "3 0 0 0 0 0 0 0 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 8 84 101 115 116 67 111 105 110 8 116 114 97 110 115 102 101 114 0 2 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 8 135 214 18 0 0 0 0 0 \n"; + +fn test_rust(abis: &[EntryABI], demo_file: &str, expected_output: &str) { + let mut registry = get_aptos_registry(); + buildgen::rust::replace_keywords(&mut registry); + let dir = tempdir().unwrap(); + + let installer = serdegen::rust::Installer::new(dir.path().to_path_buf()); + let config = serdegen::CodeGeneratorConfig::new("aptos-types".to_string()); + installer.install_module(&config, ®istry).unwrap(); + + let stdlib_dir_path = dir.path().join("framework"); + std::fs::create_dir_all(stdlib_dir_path.clone()).unwrap(); + + let mut cargo = std::fs::File::create(stdlib_dir_path.join("Cargo.toml")).unwrap(); + write!( + cargo, + r#"[package] +name = "framework" +version = "0.1.0" +edition = "2021" + +[dependencies] +aptos-types = {{ path = "../aptos-types", version = "0.1.0" }} +serde_bytes = "0.11.6" +serde = {{ version = "1.0.114", features = ["derive"] }} +bcs = {{ git = "https://github.com/aptos-labs/bcs", rev = "2cde3e8446c460cb17b0c1d6bac7e27e964ac169" }} +once_cell = "1.10.0" + +[[bin]] +name = "stdlib_demo" +path = "src/stdlib_demo.rs" +test = false +"# + ) + .unwrap(); + std::fs::create_dir(stdlib_dir_path.join("src")).unwrap(); + let source_path = stdlib_dir_path.join("src/lib.rs"); + let mut source = std::fs::File::create(source_path).unwrap(); + buildgen::rust::output(&mut source, abis, /* local types */ false).unwrap(); + + std::fs::copy(demo_file, stdlib_dir_path.join("src/stdlib_demo.rs")).unwrap(); + + // Use a stable `target` dir to avoid downloading and recompiling crates everytime. + let target_dir = std::env::current_dir().unwrap().join("../../target"); + let status = Command::new("cargo") + .current_dir(dir.path().join("framework")) + .arg("build") + .arg("--target-dir") + .arg(target_dir.clone()) + .status() + .unwrap(); + assert!(status.success()); + + let output = Command::new(target_dir.join("debug/stdlib_demo")) + .output() + .unwrap(); + assert!(output.status.success()); + assert_eq!( + std::str::from_utf8(&output.stdout).unwrap(), + expected_output + ); +} + +#[test] +// Ignored because transactions require minting/transferring Coin, which the +// transaction builder does not support (it doesn't supported typed functions yet). +#[ignore] +fn test_that_rust_entry_fun_code_compiles() { + // TODO: need a way to get abis to reactivate this test + let abis = vec![]; + test_rust( + &abis, // &aptos_cached_packages::head_release_bundle().abis(), + "examples/rust/script_fun_demo.rs", + EXPECTED_SCRIPT_FUN_OUTPUT, + ); +} diff --git a/vm/starcoin-sdk-builder/tests/keyworded_registry.goldenfile.yaml b/vm/starcoin-sdk-builder/tests/keyworded_registry.goldenfile.yaml new file mode 100644 index 0000000000..04b81119e5 --- /dev/null +++ b/vm/starcoin-sdk-builder/tests/keyworded_registry.goldenfile.yaml @@ -0,0 +1,21 @@ +--- +Identifier: + NEWTYPESTRUCT: STR +ModuleId: + STRUCT: + - name: + TYPENAME: Identifier +EntryFunction: + STRUCT: + - module_name: + TYPENAME: ModuleId + - function_name: + TYPENAME: Identifier +StructTag: + STRUCT: + - address: + TYPENAME: STR + - module_name: + TYPENAME: Identifier + - name: + TYPENAME: Identifier diff --git a/vm/starcoin-sdk-builder/tests/keyworded_registry.yaml b/vm/starcoin-sdk-builder/tests/keyworded_registry.yaml new file mode 100644 index 0000000000..d731a48819 --- /dev/null +++ b/vm/starcoin-sdk-builder/tests/keyworded_registry.yaml @@ -0,0 +1,21 @@ +--- +Identifier: + NEWTYPESTRUCT: STR +ModuleId: + STRUCT: + - name: + TYPENAME: Identifier +EntryFunction: + STRUCT: + - module: + TYPENAME: ModuleId + - function: + TYPENAME: Identifier +StructTag: + STRUCT: + - address: + TYPENAME: STR + - module: + TYPENAME: Identifier + - name: + TYPENAME: Identifier diff --git a/vm/types/src/lib.rs b/vm/types/src/lib.rs index a4c5bfd352..8c6c834ade 100644 --- a/vm/types/src/lib.rs +++ b/vm/types/src/lib.rs @@ -240,6 +240,7 @@ pub mod sips; pub mod state_store; pub mod time; pub mod token; +pub mod utility_coin; #[cfg(test)] mod unit_tests; diff --git a/vm/types/src/on_chain_config/starcoin_features.rs b/vm/types/src/on_chain_config/starcoin_features.rs index 333e8eabb3..ca94a0b053 100644 --- a/vm/types/src/on_chain_config/starcoin_features.rs +++ b/vm/types/src/on_chain_config/starcoin_features.rs @@ -54,6 +54,7 @@ pub enum FeatureFlag { BN254_STRUCTURES = 43, WEBAUTHN_SIGNATURE = 44, RECONFIGURE_WITH_DKG = 45, + REJECT_UNSTABLE_BYTECODE = 46, } /// Representation of features on chain as a bitset. diff --git a/vm/types/src/utility_coin.rs b/vm/types/src/utility_coin.rs new file mode 100644 index 0000000000..02a67046de --- /dev/null +++ b/vm/types/src/utility_coin.rs @@ -0,0 +1,18 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::account_address::AccountAddress; +use move_core_types::{ + ident_str, + language_storage::{StructTag, TypeTag}, +}; +use once_cell::sync::Lazy; + +pub static STARCOIN_COIN_TYPE: Lazy = Lazy::new(|| { + TypeTag::Struct(Box::new(StructTag { + address: AccountAddress::ONE, + module: ident_str!("starcoin_coin").to_owned(), + name: ident_str!("StarcoinCoin").to_owned(), + type_args: vec![], + })) +}); diff --git a/vm/vm-runtime-types/src/resolver.rs b/vm/vm-runtime-types/src/resolver.rs index 72b4592239..802c756e39 100644 --- a/vm/vm-runtime-types/src/resolver.rs +++ b/vm/vm-runtime-types/src/resolver.rs @@ -3,11 +3,16 @@ use bytes::Bytes; use move_core_types::value::MoveTypeLayout; -use starcoin_vm_types::state_store::state_key::StateKey; -use starcoin_vm_types::state_store::state_storage_usage::StateStorageUsage; -use starcoin_vm_types::state_store::state_value::{StateValue, StateValueMetadata}; -use starcoin_vm_types::state_store::StateViewId; -use starcoin_vm_types::state_view::StateView; +use starcoin_vm_types::{ + state_store::{ + errors::StateviewError, + state_key::StateKey, + state_storage_usage::StateStorageUsage, + state_value::{StateValue, StateValueMetadata}, + StateViewId, + }, + state_view::StateView, +}; /// Allows to query resources from the state. pub trait TResourceView { diff --git a/vm/vm-runtime-types/src/storage/change_set_configs.rs b/vm/vm-runtime-types/src/storage/change_set_configs.rs index 5ae000f86a..2633454edb 100644 --- a/vm/vm-runtime-types/src/storage/change_set_configs.rs +++ b/vm/vm-runtime-types/src/storage/change_set_configs.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{change_set::VMChangeSet, check_change_set::CheckChangeSet}; -use move_core_types::vm_status::{err_msg, StatusCode, VMStatus}; +use move_core_types::vm_status::VMStatus; use starcoin_gas_meter::StarcoinGasParameters; #[derive(Clone, Debug)]