use aptos_sdk::{
api::response::{MoveFunction, MoveModuleABI, MoveStructDef, MoveStructField},
codegen::{GeneratorConfig, ModuleGenerator, MoveSourceParser},
};
fn main() -> anyhow::Result<()> {
let abi = MoveModuleABI {
address: "0xcafe".to_string(),
name: "my_token".to_string(),
exposed_functions: vec![
MoveFunction {
name: "mint".to_string(),
visibility: "public".to_string(),
is_entry: true,
is_view: false,
generic_type_params: vec![],
params: vec![
"&signer".to_string(),
"address".to_string(),
"u64".to_string(),
],
returns: vec![],
},
MoveFunction {
name: "transfer".to_string(),
visibility: "public".to_string(),
is_entry: true,
is_view: false,
generic_type_params: vec![],
params: vec![
"&signer".to_string(),
"address".to_string(),
"u64".to_string(),
],
returns: vec![],
},
MoveFunction {
name: "balance".to_string(),
visibility: "public".to_string(),
is_entry: false,
is_view: true,
generic_type_params: vec![],
params: vec!["address".to_string()],
returns: vec!["u64".to_string()],
},
MoveFunction {
name: "total_supply".to_string(),
visibility: "public".to_string(),
is_entry: false,
is_view: true,
generic_type_params: vec![],
params: vec![],
returns: vec!["u64".to_string()],
},
],
structs: vec![
MoveStructDef {
name: "TokenStore".to_string(),
is_native: false,
abilities: vec!["key".to_string()],
generic_type_params: vec![],
fields: vec![
MoveStructField {
name: "balance".to_string(),
typ: "u64".to_string(),
},
MoveStructField {
name: "owner".to_string(),
typ: "address".to_string(),
},
],
},
MoveStructDef {
name: "TokenInfo".to_string(),
is_native: false,
abilities: vec!["key".to_string()],
generic_type_params: vec![],
fields: vec![
MoveStructField {
name: "name".to_string(),
typ: "0x1::string::String".to_string(),
},
MoveStructField {
name: "symbol".to_string(),
typ: "0x1::string::String".to_string(),
},
MoveStructField {
name: "decimals".to_string(),
typ: "u8".to_string(),
},
MoveStructField {
name: "total_supply".to_string(),
typ: "u64".to_string(),
},
],
},
],
};
let move_source = r#"
/// A token management module.
///
/// This module provides functionality for minting, transferring,
/// and querying token balances.
module 0xcafe::my_token {
use std::string::String;
/// Stores token balance for an account.
struct TokenStore has key {
/// The current balance.
balance: u64,
/// The account that owns this store.
owner: address,
}
/// Metadata about the token.
struct TokenInfo has key {
/// The human-readable name.
name: String,
/// The ticker symbol.
symbol: String,
/// Number of decimal places.
decimals: u8,
/// Total tokens in circulation.
total_supply: u64,
}
/// Mints new tokens to a recipient.
///
/// Only the admin can call this function.
///
/// # Arguments
/// * `admin` - The admin account authorized to mint
/// * `recipient` - The address to receive the minted tokens
/// * `amount` - The number of tokens to mint
public entry fun mint(
admin: &signer,
recipient: address,
amount: u64,
) {
// implementation
}
/// Transfers tokens from the sender to a recipient.
///
/// # Arguments
/// * `sender` - The account sending tokens
/// * `to` - The address to receive tokens
/// * `amount` - The number of tokens to transfer
public entry fun transfer(
sender: &signer,
to: address,
amount: u64,
) {
// implementation
}
/// Gets the token balance for an account.
///
/// Returns 0 if the account has no TokenStore.
#[view]
public fun balance(owner: address): u64 {
0
}
/// Gets the total supply of tokens.
#[view]
public fun total_supply(): u64 {
0
}
}
"#;
let source_info = MoveSourceParser::parse(move_source);
println!("Parsed Move source:");
println!(
" - Functions: {:?}",
source_info.functions.keys().collect::<Vec<_>>()
);
println!(
" - Structs: {:?}",
source_info.structs.keys().collect::<Vec<_>>()
);
println!("\n=== Generated WITHOUT Move Source ===\n");
let config = GeneratorConfig::new()
.with_entry_functions(true)
.with_view_functions(true)
.with_structs(false);
let generator = ModuleGenerator::new(&abi, config.clone());
let code_without_source = generator.generate()?;
for line in code_without_source.lines() {
if line.contains("pub fn transfer")
|| line.contains("/// Entry function: `my_token::transfer`")
{
println!("{}", line);
}
}
println!("\n=== Generated WITH Move Source ===\n");
let generator_with_source = ModuleGenerator::new(&abi, config).with_source_info(source_info);
let code_with_source = generator_with_source.generate()?;
let mut in_transfer = false;
for line in code_with_source.lines() {
if line.contains("/// Transfers tokens") {
in_transfer = true;
}
if in_transfer {
println!("{}", line);
if line.starts_with("pub fn transfer") {
break;
}
}
}
println!("\n=== Full Generated Code (with source) ===\n");
let full_config = GeneratorConfig::new()
.with_entry_functions(true)
.with_view_functions(true)
.with_structs(true);
let full_source_info = MoveSourceParser::parse(move_source);
let full_generator = ModuleGenerator::new(&abi, full_config).with_source_info(full_source_info);
let full_code = full_generator.generate()?;
println!("{}", full_code);
println!("\n=== CLI Usage ===\n");
println!("# Generate from ABI file only:");
println!("aptos-codegen --input abi.json --output src/generated/");
println!();
println!("# Generate with Move source for better names:");
println!("aptos-codegen --input abi.json --source my_token.move --output src/generated/");
println!();
println!("# Fetch from chain and generate:");
println!("aptos-codegen --module 0x1::coin --network testnet --output src/generated/");
Ok(())
}