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
This tutorial builds on concepts from the Aptos blockchain. If you’re new to blockchain development, don’t worry - we’ll explain key concepts along the way.
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:
npm install @aptos-labs/ts-sdk
Create a project directory
Create a new directory for your project:
mkdir my-first-transaction
cd my-first-transaction
Create a new file
Create a new file named transaction.ts
:
touch transaction.ts
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 client
const 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);
We’re connecting to the Aptos devnet, which is a test network where you can experiment without using real coins. The devnet is reset periodically, so don’t store anything important there.
Generate accounts
Now let’s create two accounts: Alice (sender) and Bob (receiver):
Add this code inside your main()
function:
// 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}`);
Each account has a unique address (like a bank account number) and a keypair (like your login credentials). The address is derived from the public key, while the private key is kept secret and used for signing transactions.
Fund the accounts
To perform transactions, accounts need funds. Let’s use the faucet to get some test coins:
Add this code after generating the accounts:
// Fund the accounts
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`);
Run the code
Let’s test our code so far:
npx ts-node transaction.ts
You should see output similar to:
Connected to Aptos devnet
=== Addresses ===
Alice's address: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aa
Bob's address: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b
=== Funding accounts ===
Accounts funded successfully
=== Initial Balances ===
Alice: 100000000 octas
Bob: 0 octas
The addresses you see will be different from the ones shown here, as they are randomly generated each time.
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
All data in Aptos transactions is serialized using Binary Canonical Serialization (BCS), a compact and deterministic format designed for blockchain use. The SDK handles this serialization for you.
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 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");
// Access transaction details from the raw transaction
const 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()}`);
The function 0x1::aptos_account::transfer
is a built-in function in the Aptos framework that transfers coins between accounts. The 0x1
prefix indicates it’s part of the core framework.
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 transaction
console.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"}`);
Gas is the computational fee paid to process transactions on the blockchain. The total cost is calculated as gas_used Ă— gas_unit_price
. Simulation helps you estimate this cost before committing to the transaction.
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 transaction
console.log("\n=== 3. Signing the transaction ===");
const senderAuthenticator = aptos.transaction.sign({
signer: alice,
transaction,
});
console.log("Transaction signed successfully");
Digital signatures work like a personal seal or signature in the physical world. They prove that the transaction was authorized by the account owner (who has the private key) and haven’t been tampered with.
Submit the transaction
Now we submit the signed transaction to the blockchain:
Add this code after signing the transaction:
// 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}`);
The transaction hash is a unique identifier for your transaction, similar to a tracking number for a package. You can use it to check the status of your transaction on the Aptos Explorer.
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 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}`);
Verify the results
Finally, let’s check the balances to confirm the transfer worked:
Add this code after waiting for the transaction:
// 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)`);
Run the complete code
Now run the complete program:
npx ts-node transaction.ts
You should see output similar to:
Connected to Aptos devnet
=== Addresses ===
Alice's address: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aa
Bob's address: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b
=== Funding accounts ===
Accounts funded successfully
=== Initial Balances ===
Alice: 100000000 octas
Bob: 0 octas
=== 1. Building the transaction ===
Transaction built successfully
Sender: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aa
Sequence Number: 0
Max Gas Amount: 20000
Gas Unit Price: 100
Expiration Timestamp: 2025-03-05T22:59:21.000Z
=== 2. Simulating the transaction ===
Estimated gas units: 146
Estimated gas cost: 14600 octas
Transaction 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: SUCCESS
VM Status: Executed successfully
Gas used: 146
=== Final Balances ===
Alice: 99984400 octas (spent 15600 octas on transfer and gas)
Bob: 1000 octas (received 1000 octas)
Notice that Alice’s balance decreased by more than 1000 octas. The extra amount is the gas fee paid to process the transaction.
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.
Do not press enter! There is a known bug where searching with Enter does not work.
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
The Explorer is a powerful tool for debugging transactions and understanding blockchain activity. Developers frequently use it to verify their transactions executed as expected and to investigate any issues.
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
These links are for the Typescript SDK but the principles are the same if you are using Python.
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!