Your First Transaction
Transactions are the fundamental way to change data on the Aptos blockchain. Think of them like sending a package: you need to specify what you’re sending, who it’s going to, and then track it until delivery is confirmed. In blockchain terms, transactions allow you to transfer coins, call smart contract functions, and update on-chain state.
This tutorial will guide you through creating and submitting your first transaction on the Aptos blockchain. You’ll learn how to:
- Set up your development environment
- Create test accounts and fund them
- Build a transaction to transfer coins
- Simulate the transaction to estimate costs
- Sign and submit the transaction
- Verify the transaction was executed successfully
1. Setting Up Your Environment
Section titled “1. Setting Up Your Environment”Before we can create transactions, we need to set up our development environment with the necessary tools and SDKs.
-
Install the TypeScript SDK
Install the TypeScript SDK using your preferred package manager:
Terminal window npm install @aptos-labs/ts-sdkTerminal window yarn add @aptos-labs/ts-sdkTerminal window pnpm add @aptos-labs/ts-sdk -
Create a project directory
Create a new directory for your project:
Terminal window mkdir my-first-transactioncd my-first-transaction -
Create a new file
Create a new file named
transaction.ts
:Terminal window touch transaction.tsTerminal window type nul > transaction.ts
Before we can create transactions, we need to set up our development environment with the necessary tools and SDKs.
-
Install the Python SDK
Install the Python SDK using pip:
Terminal window pip install aptos-sdk -
Create a project directory
Create a new directory for your project:
Terminal window mkdir my-first-transactioncd my-first-transaction -
Create a new file
Create a new file named
transaction.py
:Terminal window touch transaction.pyTerminal window type nul > transaction.py
2. Creating Test Accounts
Section titled “2. Creating Test Accounts”In blockchain, all transactions must come from an account. Let’s create two test accounts: one to send coins (Alice) and one to receive them (Bob).
-
Set up the client
First, we need to initialize the Aptos client that will connect to the blockchain. Open
transaction.ts
in your editor and add:import {Account,Aptos,AptosConfig,Network,} from "@aptos-labs/ts-sdk";async function main() {// Initialize the Aptos clientconst config = new AptosConfig({ network: Network.DEVNET });const aptos = new Aptos(config);console.log("Connected to Aptos devnet");// More code will go here}main().catch(console.error); -
Generate accounts
Add this code inside your
main()
function to create two accounts - Alice (sender) and Bob (receiver):// Generate two accountsconst alice = Account.generate();const bob = Account.generate();console.log("=== Addresses ===");console.log(`Alice's address: ${alice.accountAddress}`);console.log(`Bob's address: ${bob.accountAddress}`); -
Fund the accounts
Add this code after generating the accounts to get test coins from the faucet:
// Fund the accounts with test APT from the devnet faucetconsole.log("\n=== Funding accounts ===");await aptos.fundAccount({accountAddress: alice.accountAddress,amount: 100_000_000, // 1 APT = 100,000,000 octas});console.log("Accounts funded successfully");// Check initial balancesconst aliceBalance = await aptos.getAccountAPTAmount({accountAddress: alice.accountAddress,});const bobBalance = await aptos.getAccountAPTAmount({accountAddress: bob.accountAddress,});console.log("\n=== Initial Balances ===");console.log(`Alice: ${aliceBalance} octas`);console.log(`Bob: ${bobBalance} octas`); -
Run the code
Let’s test our code so far:
Terminal window npx ts-node transaction.tsYou should see output similar to:
Connected to Aptos devnet=== Addresses ===Alice's address: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aaBob's address: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b=== Funding accounts ===Accounts funded successfully=== Initial Balances ===Alice: 100000000 octasBob: 0 octas
In blockchain, all transactions must come from an account. Let’s create two test accounts: one to send coins (Alice) and one to receive them (Bob).
-
Set up the client
First, we need to initialize the Aptos client that will connect to the blockchain. Open
transaction.py
in your editor and add:import asynciofrom aptos_sdk.account import Accountfrom aptos_sdk.async_client import FaucetClient, RestClientfrom aptos_sdk.transactions import EntryFunction, TransactionPayload, TransactionArgument, RawTransactionfrom aptos_sdk.bcs import Serializerimport time# Network configurationNODE_URL = "https://fullnode.devnet.aptoslabs.com/v1"FAUCET_URL = "https://faucet.devnet.aptoslabs.com"async def main():# Initialize the clientsrest_client = RestClient(NODE_URL)faucet_client = FaucetClient(FAUCET_URL, rest_client)print("Connected to Aptos devnet")# More code will go hereif __name__ == "__main__":asyncio.run(main()) -
Generate accounts
Add this code inside your
main()
function to create two accounts - Alice (sender) and Bob (receiver):# Generate two accountsalice = Account.generate()bob = Account.generate()print("=== Addresses ===")print(f"Alice's address: {alice.address()}")print(f"Bob's address: {bob.address()}") -
Fund the accounts
Add this code after generating the accounts to get test coins from the faucet:
# Fund the accounts with test APT from the devnet faucetprint("\n=== Funding accounts ===")alice_amount = 100_000_000 # 1 APT = 100,000,000 octasbob_amount = 0 # Bob starts with 0 APTawait faucet_client.fund_account(alice.address(), alice_amount)print("Account funded successfully")# Check initial balancesalice_balance = await rest_client.account_balance(alice.address())bob_balance = await rest_client.account_balance(bob.address())print("\n=== Initial Balances ===")print(f"Alice: {alice_balance} octas")print(f"Bob: {bob_balance} octas") -
Run the code
Let’s test our code so far:
Terminal window python transaction.pyYou should see output similar to:
Connected to Aptos devnet=== Addresses ===Alice's address: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aaBob's address: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b=== Funding accounts ===Accounts funded successfully=== Initial Balances ===Alice: 100000000 octasBob: 0 octas
3. Building a Transaction
Section titled “3. Building a Transaction”Now that we have funded accounts, let’s create a transaction to transfer coins from Alice to Bob. This is like filling out a form specifying what you want to send and to whom.
-
Understand transaction structure
A transaction in Aptos has several key components:
- Sender: The account initiating the transaction (Alice)
- Function: The on-chain function to call (in this case, a coin transfer)
- Arguments: Data needed by the function (recipient address and amount)
- Gas parameters: Maximum gas amount and gas unit price
- Expiration time: When the transaction is no longer valid if not executed
- Sequence number: A counter that prevents replay attacks
-
Build the transaction
Let’s add code to build a transaction that transfers 1000 octas from Alice to Bob:
Add this code to your
main()
function:// 1. Build the transactionconsole.log("\n=== 1. Building the transaction ===");const transaction = await aptos.transaction.build.simple({sender: alice.accountAddress,data: {function: "0x1::aptos_account::transfer",functionArguments: [bob.accountAddress, 1000], // Transfer 1000 octas},});console.log("Transaction built successfully");// Access transaction details from the raw transactionconst rawTxn = transaction.rawTransaction;console.log(`Sender: ${rawTxn.sender}`);console.log(`Sequence Number: ${rawTxn.sequence_number}`);console.log(`Max Gas Amount: ${rawTxn.max_gas_amount}`);console.log(`Gas Unit Price: ${rawTxn.gas_unit_price}`);console.log(`Expiration Timestamp: ${new Date(Number(rawTxn.expiration_timestamp_secs) * 1000).toISOString()}`);
Now that we have funded accounts, let’s create a transaction to transfer coins from Alice to Bob. This is like filling out a form specifying what you want to send and to whom.
-
Understand transaction structure
A transaction in Aptos has several key components:
- Sender: The account initiating the transaction (Alice)
- Function: The on-chain function to call (in this case, a coin transfer)
- Arguments: Data needed by the function (recipient address and amount)
- Gas parameters: Maximum gas amount and gas unit price
- Expiration time: When the transaction is no longer valid if not executed
- Sequence number: A counter that prevents replay attacks
-
Build the transaction
Add the following code to your
main()
function to build a transaction that transfers 1000 octas from Alice to Bob:# 1. Build the transactionprint("\n=== 1. Building the transaction ===")# Create the entry function payload# This specifies which function to call and with what argumentsentry_function = EntryFunction.natural("0x1::aptos_account", # Module address and name"transfer", # Function name[], # Type arguments (empty for this function)[# Function arguments with their serialization typeTransactionArgument(bob.address(), Serializer.struct), # Recipient addressTransactionArgument(1000, Serializer.u64), # Amount to transfer (1000 octas)],)# Get the chain ID for the transactionchain_id = await rest_client.chain_id()# Get the sender's current sequence numberaccount_data = await rest_client.account(alice.address())sequence_number = int(account_data["sequence_number"])# Create the raw transaction with all required fieldsraw_transaction = RawTransaction(sender=alice.address(), # Sender's addresssequence_number=sequence_number, # Sequence number to prevent replay attackspayload=TransactionPayload(entry_function), # The function to callmax_gas_amount=2000, # Maximum gas units to usegas_unit_price=100, # Price per gas unit in octasexpiration_timestamps_secs=int(time.time()) + 600, # Expires in 10 minuteschain_id=chain_id, # Chain ID to ensure correct network)print("Transaction built successfully")print(f"Sender: {raw_transaction.sender}")print(f"Sequence Number: {raw_transaction.sequence_number}")print(f"Max Gas Amount: {raw_transaction.max_gas_amount}")print(f"Gas Unit Price: {raw_transaction.gas_unit_price}")print(f"Expiration Timestamp: {time.ctime(raw_transaction.expiration_timestamps_secs)}")
4. Simulating the Transaction
Section titled “4. Simulating the Transaction”Before submitting a transaction, it’s wise to simulate it first to estimate the gas cost. This is like checking shipping costs before sending a package.
-
Simulate the transaction
Add this code after building the transaction:
// 2. Simulate the transactionconsole.log("\n=== 2. Simulating the transaction ===");const [simulationResult] = await aptos.transaction.simulate.simple({signerPublicKey: alice.publicKey,transaction,});const gasUsed = parseInt(simulationResult.gas_used);const gasUnitPrice = parseInt(simulationResult.gas_unit_price);console.log(`Estimated gas units: ${gasUsed}`);console.log(`Estimated gas cost: ${gasUsed * gasUnitPrice} octas`);console.log(`Transaction would ${simulationResult.success ? "succeed" : "fail"}`);
Before submitting a transaction, it’s wise to simulate it first to estimate the gas cost. This is like checking shipping costs before sending a package.
-
Simulate the transaction
Add this code after building the transaction:
# 2. Simulate the transactionprint("\n=== 2. Simulating the transaction ===")# Create a BCS transaction for simulation# This doesn't actually submit the transaction to the blockchainsimulation_transaction = await rest_client.create_bcs_transaction(alice, TransactionPayload(entry_function))# Simulate the transaction to estimate gas costs and check for errorssimulation_result = await rest_client.simulate_transaction(simulation_transaction, alice)# Extract and display the simulation resultsgas_used = int(simulation_result[0]['gas_used'])gas_unit_price = int(simulation_result[0]['gas_unit_price'])success = simulation_result[0]['success']print(f"Estimated gas units: {gas_used}")print(f"Estimated gas cost: {gas_used * gas_unit_price} octas")print(f"Transaction would {'succeed' if success else 'fail'}")
5. Signing and Submitting the Transaction
Section titled “5. Signing and Submitting the Transaction”Now that we’ve built and simulated the transaction, we need to sign it with Alice’s private key and submit it to the blockchain.
-
Sign the transaction
Signing proves that Alice authorized this transaction:
Add this code after simulating the transaction:
// 3. Sign the transactionconsole.log("\n=== 3. Signing the transaction ===");const senderAuthenticator = aptos.transaction.sign({signer: alice,transaction,});console.log("Transaction signed successfully"); -
Submit the transaction
Add this code after signing the transaction to submit the signed transaction to the blockchain:
// 4. Submit the transactionconsole.log("\n=== 4. Submitting the transaction ===");const pendingTransaction = await aptos.transaction.submit.simple({transaction,senderAuthenticator,});console.log(`Transaction submitted with hash: ${pendingTransaction.hash}`);
Now that we’ve built and simulated the transaction, we need to sign it with Alice’s private key and submit it to the blockchain.
-
Sign the transaction
Signing proves that Alice authorized this transaction:
Add this code after simulating the transaction:
# 3. Sign the transactionprint("\n=== 3. Signing the transaction ===")# Sign the raw transaction with the sender's private key# This creates a cryptographic signature that proves the sender authorized this transactionsigned_transaction = await rest_client.create_bcs_signed_transaction(alice, # Account with the private keyTransactionPayload(entry_function), # The payload from our transactionsequence_number=sequence_number # Use the same sequence number as before)print("Transaction signed successfully")# We can't easily extract the signature from the signed transaction object,# but we can confirm it was created -
Submit the transaction
Add this code after signing the transaction to submit the signed transaction to the blockchain:
# 4. Submit the transactionprint("\n=== 4. Submitting the transaction ===")# Submit the signed transaction to the blockchain# This broadcasts the transaction to the network for processingtx_hash = await rest_client.submit_bcs_transaction(signed_transaction)print(f"Transaction submitted with hash: {tx_hash}")
6. Waiting for Confirmation
Section titled “6. Waiting for Confirmation”After submitting a transaction, we need to wait for it to be processed by the blockchain. This is like waiting for a package to be delivered.
-
Wait for transaction completion
Add this code after submitting the transaction:
// 5. Wait for the transaction to completeconsole.log("\n=== 5. Waiting for transaction completion ===");const txnResult = await aptos.waitForTransaction({transactionHash: pendingTransaction.hash,});console.log(`Transaction completed with status: ${txnResult.success ? "SUCCESS" : "FAILURE"}`);// If you want to see more details about the transaction:console.log(`VM Status: ${txnResult.vm_status}`);console.log(`Gas used: ${txnResult.gas_used}`); -
Verify the results
Add this code after waiting for the transaction to check the balances and confirm the transfer worked:
// Check final balancesconst aliceFinalBalance = await aptos.getAccountAPTAmount({accountAddress: alice.accountAddress,});const bobFinalBalance = await aptos.getAccountAPTAmount({accountAddress: bob.accountAddress,});console.log("\n=== Final Balances ===");console.log(`Alice: ${aliceFinalBalance} octas (spent ${aliceBalance - aliceFinalBalance} octas on transfer and gas)`);console.log(`Bob: ${bobFinalBalance} octas (received 1000 octas)`); -
Run the complete code
Terminal window npx ts-node transaction.tsYou should see output similar to:
Connected to Aptos devnet=== Addresses ===Alice's address: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aaBob's address: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b=== Funding accounts ===Accounts funded successfully=== Initial Balances ===Alice: 100000000 octasBob: 0 octas=== 1. Building the transaction ===Transaction built successfullySender: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aaSequence Number: 0Max Gas Amount: 20000Gas Unit Price: 100Expiration Timestamp: 2025-03-05T22:59:21.000Z=== 2. Simulating the transaction ===Estimated gas units: 146Estimated gas cost: 14600 octasTransaction would succeed=== 3. Signing the transaction ===Transaction signed successfully=== 4. Submitting the transaction ===Transaction submitted with hash: 0x3a8a3e34a1c64ad9d7636a3a827b7ec3bb12d73825b36fa06d425c5a3b42cccc=== 5. Waiting for transaction completion ===Transaction completed with status: SUCCESSVM Status: Executed successfullyGas used: 146=== Final Balances ===Alice: 99984400 octas (spent 15600 octas on transfer and gas)Bob: 1000 octas (received 1000 octas)
After submitting a transaction, we need to wait for it to be processed by the blockchain. This is like waiting for a package to be delivered.
-
Wait for transaction completion
Add this code after submitting the transaction:
# 5. Wait for the transaction to completeprint("\n=== 5. Waiting for transaction completion ===")# Wait for the transaction to be processed by the blockchain# This polls the blockchain until the transaction is confirmedawait rest_client.wait_for_transaction(tx_hash)# Get the transaction details to check its statustransaction_details = await rest_client.transaction_by_hash(tx_hash)success = transaction_details["success"]vm_status = transaction_details["vm_status"]gas_used = transaction_details["gas_used"]print(f"Transaction completed with status: {'SUCCESS' if success else 'FAILURE'}")print(f"VM Status: {vm_status}")print(f"Gas used: {gas_used}") -
Verify the results
Add this code after waiting for the transaction to check the balances and confirm the transfer worked:
# Check final balancesalice_final_balance = await rest_client.account_balance(alice.address())bob_final_balance = await rest_client.account_balance(bob.address())print("\n=== Final Balances ===")print(f"Alice: {alice_final_balance} octas (spent {alice_balance - alice_final_balance} octas on transfer and gas)")print(f"Bob: {bob_final_balance} octas (received 1000 octas)") -
Run the complete code
Terminal window python transaction.pyYou should see output similar to:
Connected to Aptos devnet=== Addresses ===Alice's address: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aaBob's address: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b=== Funding accounts ===Accounts funded successfully=== Initial Balances ===Alice: 100000000 octasBob: 0 octas=== 1. Building the transaction ===Transaction built successfullySender: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aaSequence Number: 0Max Gas Amount: 2000Gas Unit Price: 100Expiration Timestamp: Wed Mar 05 22:59:21 2025=== 2. Simulating the transaction ===Estimated gas units: 146Estimated gas cost: 14600 octasTransaction would succeed=== 3. Signing the transaction ===Transaction signed successfully=== 4. Submitting the transaction ====== 3. Signing the transaction ===Transaction signed successfully=== 4. Submitting the transaction ===Transaction submitted with hash: 0x3a8a3e34a1c64ad9d7636a3a827b7ec3bb12d73825b36fa06d425c5a3b42cccc=== 5. Waiting for transaction completion ===Transaction completed with status: SUCCESSVM Status: Executed successfullyGas used: 146=== Final Balances ===Alice: 99984400 octas (spent 15600 octas on transfer and gas)Bob: 1000 octas (received 1000 octas)
7. (Optional) Explore Your Transaction On-Chain
Section titled “7. (Optional) Explore Your Transaction On-Chain”Now that you’ve successfully executed a transaction, you can explore it on the Aptos Explorer. This will help you understand how transactions are recorded on the blockchain and what information is publicly available.
-
Copy your transaction hash
From your terminal output, copy the transaction hash that was printed after submission. It looks something like this:
Transaction submitted with hash: 0x3a8a3e34a1c64ad9d7636a3a827b7ec3bb12d73825b36fa06d425c5a3b42cccc -
Open the Aptos Explorer
Go to the Aptos Explorer.
-
Ensure you are on Devnet network
Look for “Devnet” in the top right corner, or switch networks by clicking the dropdown and selecting Devnet.
-
Search for your transaction
Paste your transaction hash into the search bar in the middle of the page.
-
View the transaction details
Wait for the results to appear, then click on the transaction hash to view its details.
You should see information about your transaction, including:
- Status (should be “Success”)
- Timestamp
- Gas used
- Sender and recipient addresses
- Amount transferred
-
Explore further
From the transaction details page, you can:
- Click on the sender or recipient addresses to view their account details
- See the exact changes made to the blockchain state
- View the transaction payload and arguments
8. Next Steps
Section titled “8. Next Steps”Congratulations! You’ve successfully created and executed your first transaction on the Aptos blockchain. Here are some suggestions for what to explore next:
Learn about more complex transactions:
- Multi-Agent Signatures - Transactions requiring multiple signers
- Sponsoring Transactions - Having another account pay gas fees
- Batching Transactions - Sending multiple transactions efficiently
Explore smart contracts or account basics:
- Your First Move Module - Create your own smart contract
- Account Basics
Join the Aptos Discord and share what you’re building!
Full Code Sample
Section titled “Full Code Sample”The complete code samples below combine all the snippets we’ve covered in this tutorial:
import { Account, Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
async function main() { // Initialize the Aptos client const config = new AptosConfig({ network: Network.DEVNET }); const aptos = new Aptos(config);
console.log("Connected to Aptos devnet");
// More code will go here // Generate two accounts const alice = Account.generate(); const bob = Account.generate();
console.log("=== Addresses ==="); console.log(`Alice's address: ${alice.accountAddress}`); console.log(`Bob's address: ${bob.accountAddress}`);
// Fund the accounts with test APT from the devnet faucet console.log("\n=== Funding accounts ==="); await aptos.fundAccount({ accountAddress: alice.accountAddress, amount: 100_000_000, // 1 APT = 100,000,000 octas }); await aptos.fundAccount({ accountAddress: bob.accountAddress, amount: 0, // Bob starts with 0 APT }); console.log("Accounts funded successfully");
// Check initial balances const aliceBalance = await aptos.getAccountAPTAmount({ accountAddress: alice.accountAddress, }); const bobBalance = await aptos.getAccountAPTAmount({ accountAddress: bob.accountAddress, });
console.log("\n=== Initial Balances ==="); console.log(`Alice: ${aliceBalance} octas`); console.log(`Bob: ${bobBalance} octas`);
// 1. Build the transaction console.log("\n=== 1. Building the transaction ==="); const transaction = await aptos.transaction.build.simple({ sender: alice.accountAddress, data: { function: "0x1::aptos_account::transfer", functionArguments: [bob.accountAddress, 1000], // Transfer 1000 octas }, }); console.log("Transaction built successfully"); // Use type assertion to bypass TypeScript's type checking const txnAny = transaction as any; console.log(`Sender: ${alice.accountAddress}`); // Use the known sender address console.log(`Sequence Number: ${txnAny.sequenceNumber || "N/A"}`); console.log(`Max Gas Amount: ${txnAny.maxGasAmount || "N/A"}`); console.log(`Gas Unit Price: ${txnAny.gasUnitPrice || "N/A"}`); console.log( `Expiration Timestamp: ${new Date( Number(txnAny.expirationTimestampSecs || 0) * 1000 ).toISOString()}` );
// 2. Simulate the transaction console.log("\n=== 2. Simulating the transaction ==="); const [simulationResult] = await aptos.transaction.simulate.simple({ signerPublicKey: alice.publicKey, transaction, });
console.log(`Estimated gas units: ${simulationResult.gas_used}`); console.log( `Estimated gas cost: ${ Number(simulationResult.gas_used) * Number(simulationResult.gas_unit_price) } octas` ); console.log( `Transaction would ${simulationResult.success ? "succeed" : "fail"}` );
// 3. Sign the transaction console.log("\n=== 3. Signing the transaction ==="); const senderAuthenticator = aptos.transaction.sign({ signer: alice, transaction, }); console.log("Transaction signed successfully"); // Use type assertion to bypass TypeScript's type checking const authAny = senderAuthenticator as any; const signatureStr = typeof authAny.signature === 'string' ? authAny.signature : JSON.stringify(authAny.signature || ''); console.log(`Signature: ${signatureStr.slice(0, 20)}...`);
// 4. Submit the transaction console.log("\n=== 4. Submitting the transaction ==="); const pendingTransaction = await aptos.transaction.submit.simple({ transaction, senderAuthenticator, }); console.log(`Transaction submitted with hash: ${pendingTransaction.hash}`);
// 5. Wait for the transaction to complete console.log("\n=== 5. Waiting for transaction completion ==="); const txnResult = await aptos.waitForTransaction({ transactionHash: pendingTransaction.hash, }); console.log( `Transaction completed with status: ${ txnResult.success ? "SUCCESS" : "FAILURE" }` );
// If you want to see more details about the transaction: console.log(`VM Status: ${txnResult.vm_status}`); console.log(`Gas used: ${txnResult.gas_used}`);
// Check final balances const aliceFinalBalance = await aptos.getAccountAPTAmount({ accountAddress: alice.accountAddress, }); const bobFinalBalance = await aptos.getAccountAPTAmount({ accountAddress: bob.accountAddress, });
console.log("\n=== Final Balances ==="); console.log( `Alice: ${aliceFinalBalance} octas (spent ${ aliceBalance - aliceFinalBalance } octas on transfer and gas)` ); console.log(`Bob: ${bobFinalBalance} octas (received 1000 octas)`);}
main().catch(console.error);
import asynciofrom aptos_sdk.account import Accountfrom aptos_sdk.async_client import FaucetClient, RestClientfrom aptos_sdk.transactions import EntryFunction, TransactionPayload, TransactionArgument, RawTransactionfrom aptos_sdk.bcs import Serializerimport time
# Network configurationNODE_URL = "https://fullnode.devnet.aptoslabs.com/v1"FAUCET_URL = "https://faucet.devnet.aptoslabs.com"
async def main(): # Initialize the clients rest_client = RestClient(NODE_URL) faucet_client = FaucetClient(FAUCET_URL, rest_client)
print("Connected to Aptos devnet")
# Generate two accounts alice = Account.generate() bob = Account.generate()
print("=== Addresses ===") print(f"Alice's address: {alice.address()}") print(f"Bob's address: {bob.address()}") # More code will go here # Fund the accounts with test APT from the devnet faucet print("\n=== Funding accounts ===") alice_amount = 100_000_000 # 1 APT = 100,000,000 octas bob_amount = 0 # Bob starts with 0 APT
await faucet_client.fund_account(alice.address(), alice_amount) await faucet_client.fund_account(bob.address(), bob_amount) print("Accounts funded successfully")
# Check initial balances alice_balance = await rest_client.account_balance(alice.address()) bob_balance = await rest_client.account_balance(bob.address())
print("\n=== Initial Balances ===") print(f"Alice: {alice_balance} octas") print(f"Bob: {bob_balance} octas")
# 1. Build the transaction print("\n=== 1. Building the transaction ===")
# Create the entry function payload # This specifies which function to call and with what arguments entry_function = EntryFunction.natural( "0x1::aptos_account", # Module address and name "transfer", # Function name [], # Type arguments (empty for this function) [ # Function arguments with their serialization type TransactionArgument(bob.address(), Serializer.struct), # Recipient address TransactionArgument(1000, Serializer.u64), # Amount to transfer (1000 octas) ], )
# Get the chain ID for the transaction chain_id = await rest_client.chain_id()
# Get the sender's current sequence number account_data = await rest_client.account(alice.address()) sequence_number = int(account_data["sequence_number"])
# Create the raw transaction with all required fields raw_transaction = RawTransaction( sender=alice.address(), # Sender's address sequence_number=sequence_number, # Sequence number to prevent replay attacks payload=TransactionPayload(entry_function), # The function to call max_gas_amount=2000, # Maximum gas units to use gas_unit_price=100, # Price per gas unit in octas expiration_timestamps_secs=int(time.time()) + 600, # Expires in 10 minutes chain_id=chain_id, # Chain ID to ensure correct network )
print("Transaction built successfully") print(f"Sender: {raw_transaction.sender}") print(f"Sequence Number: {raw_transaction.sequence_number}") print(f"Max Gas Amount: {raw_transaction.max_gas_amount}") print(f"Gas Unit Price: {raw_transaction.gas_unit_price}") print(f"Expiration Timestamp: {time.ctime(raw_transaction.expiration_timestamps_secs)}")
# 2. Simulate the transaction print("\n=== 2. Simulating the transaction ===")
# Create a BCS transaction for simulation # This doesn't actually submit the transaction to the blockchain simulation_transaction = await rest_client.create_bcs_transaction(alice, TransactionPayload(entry_function))
# Simulate the transaction to estimate gas costs and check for errors simulation_result = await rest_client.simulate_transaction(simulation_transaction, alice)
# Extract and display the simulation results gas_used = int(simulation_result[0]['gas_used']) gas_unit_price = int(simulation_result[0]['gas_unit_price']) success = simulation_result[0]['success']
print(f"Estimated gas units: {gas_used}") print(f"Estimated gas cost: {gas_used * gas_unit_price} octas") print(f"Transaction would {'succeed' if success else 'fail'}")
# 3. Sign the transaction print("\n=== 3. Signing the transaction ===")
# Sign the raw transaction with the sender's private key # This creates a cryptographic signature that proves the sender authorized this transaction signed_transaction = await rest_client.create_bcs_signed_transaction( alice, # Account with the private key TransactionPayload(entry_function), # The payload from our transaction sequence_number=sequence_number # Use the same sequence number as before )
print("Transaction signed successfully") # We can't easily extract the signature from the signed transaction object, # but we can confirm it was created
# 4. Submit the transaction print("\n=== 4. Submitting the transaction ===")
# Submit the signed transaction to the blockchain # This broadcasts the transaction to the network for processing tx_hash = await rest_client.submit_bcs_transaction(signed_transaction)
print(f"Transaction submitted with hash: {tx_hash}")
# 5. Wait for the transaction to complete print("\n=== 5. Waiting for transaction completion ===")
# Wait for the transaction to be processed by the blockchain # This polls the blockchain until the transaction is confirmed await rest_client.wait_for_transaction(tx_hash)
# Get the transaction details to check its status transaction_details = await rest_client.transaction_by_hash(tx_hash) success = transaction_details["success"] vm_status = transaction_details["vm_status"] gas_used = transaction_details["gas_used"]
print(f"Transaction completed with status: {'SUCCESS' if success else 'FAILURE'}") print(f"VM Status: {vm_status}") print(f"Gas used: {gas_used}")
# Check final balances alice_final_balance = await rest_client.account_balance(alice.address()) bob_final_balance = await rest_client.account_balance(bob.address())
print("\n=== Final Balances ===") print(f"Alice: {alice_final_balance} octas (spent {alice_balance - alice_final_balance} octas on transfer and gas)") print(f"Bob: {bob_final_balance} octas (received 1000 octas)")if __name__ == "__main__": asyncio.run(main())