-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathsimulation.rs
More file actions
190 lines (158 loc) · 6.86 KB
/
simulation.rs
File metadata and controls
190 lines (158 loc) · 6.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//! Example: Transaction Simulation
//!
//! This example demonstrates how to:
//! 1. Simulate transactions before sending
//! 2. Estimate gas costs accurately
//! 3. Detect failures before spending gas
//! 4. Analyze simulation results
//!
//! Run with: `cargo run --example simulation --features "ed25519,faucet"`
use aptos_sdk::{
Aptos, AptosConfig,
account::Ed25519Account,
transaction::{EntryFunction, TransactionBuilder},
types::TypeTag,
};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
println!("=== Transaction Simulation Example ===\n");
// Setup
let aptos = Aptos::new(AptosConfig::testnet())?;
println!("Connected to testnet");
// Create and fund accounts
let sender = Ed25519Account::generate();
let recipient = Ed25519Account::generate();
println!("Sender: {}", sender.address());
println!("Recipient: {}", recipient.address());
// Fund the sender
println!("\nFunding sender account...");
aptos.fund_account(sender.address(), 100_000_000).await?;
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
let balance = aptos.get_balance(sender.address()).await?;
println!("Sender balance: {} APT", balance as f64 / 100_000_000.0);
// 1. Simulate a valid transfer
println!("\n--- 1. Simulating a Valid Transfer ---");
{
let transfer_amount = 10_000_000u64; // 0.1 APT
let payload = EntryFunction::apt_transfer(recipient.address(), transfer_amount)?;
println!(
"Simulating transfer of {} APT...",
transfer_amount as f64 / 100_000_000.0
);
let result = aptos.simulate(&sender, payload.into()).await?;
println!("\nSimulation Result:");
println!(" Success: {}", result.success());
println!(" Gas Used: {} units", result.gas_used());
println!(" Gas Price: {} octas/unit", result.gas_unit_price());
println!(
" Total Cost: {} APT",
(result.gas_used() * result.gas_unit_price()) as f64 / 100_000_000.0
);
if result.success() {
println!("\n✓ Transaction will succeed!");
println!(" Events emitted: {}", result.events().len());
println!(" State changes: {}", result.changes().len());
}
}
// 2. Simulate with insufficient balance
println!("\n--- 2. Simulating Transfer with Insufficient Balance ---");
{
// Try to send more than we have
let huge_amount = 1_000_000_000_000u64; // 10,000 APT
let payload = EntryFunction::apt_transfer(recipient.address(), huge_amount)?;
println!(
"Simulating transfer of {} APT (more than balance)...",
huge_amount as f64 / 100_000_000.0
);
let result = aptos.simulate(&sender, payload.into()).await?;
println!("\nSimulation Result:");
println!(" Success: {}", result.success());
println!(" VM Status: {}", result.vm_status());
if !result.success() {
println!("\n✗ Transaction would fail!");
println!(" This saved you gas fees by detecting the failure before submission.");
}
}
// 3. Simulate with custom gas settings
println!("\n--- 3. Simulation with Custom Gas Settings ---");
{
let payload = EntryFunction::apt_transfer(recipient.address(), 1_000_000)?;
let seq_num = aptos.get_sequence_number(sender.address()).await?;
// Build transaction with custom gas
let raw_txn = TransactionBuilder::new()
.sender(sender.address())
.sequence_number(seq_num)
.payload(payload.into())
.chain_id(aptos.chain_id())
.max_gas_amount(500) // Intentionally low
.gas_unit_price(100)
.expiration_from_now(600)
.build()?;
// Sign it
let signed = aptos_sdk::transaction::builder::sign_transaction(&raw_txn, &sender)?;
println!("Simulating with very low max_gas_amount (500 units)...");
let result = aptos.simulate_signed(&signed).await?;
println!("\nSimulation Result:");
println!(" Success: {}", result.success());
println!(" Max Gas Set: {} units", result.max_gas_amount());
println!(" Gas Used: {} units", result.gas_used());
if !result.success() && result.vm_status().contains("OUT_OF_GAS") {
println!("\n✗ Transaction would run out of gas!");
println!(
" Suggestion: Increase max_gas_amount to at least {}",
result.gas_used() + 100
);
}
}
// 4. Use gas estimation
println!("\n--- 4. Using Gas Estimation ---");
{
let payload = EntryFunction::apt_transfer(recipient.address(), 5_000_000)?;
println!("Getting gas estimate for transfer...");
let estimated_gas = aptos.estimate_gas(&sender, payload.clone().into()).await?;
println!("\nGas Estimation:");
println!(" Estimated gas (with 20% buffer): {} units", estimated_gas);
// Now submit the transaction
println!("\nSubmitting transaction...");
let txn_result = aptos
.sign_submit_and_wait(&sender, payload.into(), None)
.await?;
let actual_gas = txn_result
.data
.get("gas_used")
.and_then(serde_json::Value::as_str)
.and_then(|s| s.parse::<u64>().ok())
.unwrap_or(0);
println!(" Actual gas used: {} units", actual_gas);
println!(" Estimated was: {} units", estimated_gas);
}
// 5. Simulate to check contract state
println!("\n--- 5. Simulation for Pre-flight Checks ---");
{
// Simulate a coin registration to check if already registered
let payload = EntryFunction::new(
"0x1::managed_coin".parse()?,
"register",
vec![TypeTag::aptos_coin()],
vec![],
);
println!("Checking if APT coin store needs registration...");
let result = aptos.simulate(&sender, payload.into()).await?;
if result.success() {
println!(" Coin store registration would succeed (not yet registered)");
} else if result.vm_status().contains("RESOURCE_ALREADY_EXISTS") {
println!(" Coin store already registered (no action needed)");
} else {
println!(" Registration would fail: {}", result.vm_status());
}
}
println!("\n--- Summary ---");
println!("Transaction simulation is useful for:");
println!(" • Validating transactions before submission");
println!(" • Getting accurate gas estimates");
println!(" • Detecting errors without spending gas");
println!(" • Checking state conditions before execution");
println!(" • Debugging failed transaction logic");
println!("\n=== Transaction Simulation Example Complete ===");
Ok(())
}