-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcontract_bindings.rs
More file actions
232 lines (211 loc) · 7.54 KB
/
contract_bindings.rs
File metadata and controls
232 lines (211 loc) · 7.54 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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//! Example: Type-safe contract bindings using proc macros
//!
//! This example demonstrates how to use the `aptos_contract!` macro to generate
//! type-safe bindings for Move contracts at compile time.
//!
//! # Run with:
//! ```bash
//! cargo run --example contract_bindings --features "ed25519,macros"
//! ```
use aptos_sdk::{aptos_contract, types::AccountAddress};
// ANCHOR: define_contract
// Generate type-safe bindings from inline ABI
aptos_contract! {
name: CoinModule,
abi: r#"{
"address": "0x1",
"name": "coin",
"exposed_functions": [
{
"name": "transfer",
"visibility": "public",
"is_entry": true,
"is_view": false,
"generic_type_params": [{"constraints": []}],
"params": ["&signer", "address", "u64"],
"return": []
},
{
"name": "balance",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [{"constraints": []}],
"params": ["address"],
"return": ["u64"]
}
],
"structs": []
}"#,
// Optional: Include Move source for better parameter names
source: r#"
module 0x1::coin {
/// Transfer coins from sender to recipient.
public entry fun transfer<CoinType>(
sender: &signer,
to: address,
amount: u64,
) { }
/// Get the balance of an account.
#[view]
public fun balance<CoinType>(owner: address): u64 { 0 }
}
"#
}
// ANCHOR_END: define_contract
// ANCHOR: define_custom_contract
// A more complex example with custom token
aptos_contract! {
name: MyToken,
abi: r#"{
"address": "0xcafe",
"name": "my_token",
"exposed_functions": [
{
"name": "mint",
"visibility": "public",
"is_entry": true,
"is_view": false,
"generic_type_params": [],
"params": ["&signer", "address", "u64"],
"return": []
},
{
"name": "burn",
"visibility": "public",
"is_entry": true,
"is_view": false,
"generic_type_params": [],
"params": ["&signer", "u64"],
"return": []
},
{
"name": "total_supply",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": [],
"return": ["u64"]
},
{
"name": "balance_of",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": ["address"],
"return": ["u64"]
}
],
"structs": [
{
"name": "TokenInfo",
"is_native": false,
"abilities": ["key"],
"generic_type_params": [],
"fields": [
{"name": "name", "type": "0x1::string::String"},
{"name": "symbol", "type": "0x1::string::String"},
{"name": "decimals", "type": "u8"},
{"name": "total_supply", "type": "u64"}
]
}
]
}"#,
source: r#"
module 0xcafe::my_token {
/// Mint new tokens to a recipient.
public entry fun mint(
admin: &signer,
recipient: address,
amount: u64,
) { }
/// Burn tokens from sender's account.
public entry fun burn(
account: &signer,
amount: u64,
) { }
/// Get the total supply of tokens.
#[view]
public fun total_supply(): u64 { 0 }
/// Get the balance of an address.
#[view]
public fun balance_of(owner: address): u64 { 0 }
}
"#
}
// ANCHOR_END: define_custom_contract
#[tokio::main]
async fn main() -> anyhow::Result<()> {
println!("=== Type-Safe Contract Bindings Example ===\n");
// ANCHOR: use_contract
// The macro generates a struct with instance methods and address override support
// Create instances using the default address or a custom address
let coin_module = CoinModule::new(); // Uses default address from ABI
let my_token = MyToken::new();
// You can also override the address for different deployments
let _custom_deployment = MyToken::with_address("0xabcd1234");
println!("CoinModule constants:");
println!(" Default Address: {}", CoinModule::DEFAULT_ADDRESS);
println!(" Effective Address: {}", coin_module.address());
println!(" Module: {}", CoinModule::MODULE);
println!("\nMyToken constants:");
println!(" Default Address: {}", MyToken::DEFAULT_ADDRESS);
println!(" Effective Address: {}", my_token.address());
println!(" Module: {}", MyToken::MODULE);
// ANCHOR_END: use_contract
// ANCHOR: build_transaction
// Build a transfer transaction payload
let recipient = AccountAddress::from_hex("0x1234")?;
let amount = 1_000_000u64;
// With Move source, we get meaningful parameter names: `to`, `amount`
// Methods are called on the instance, which uses the configured address
let transfer_payload = coin_module.transfer(
recipient, // to: address
amount, // amount: u64
vec![], // type_args (e.g., AptosCoin type)
)?;
println!("\nGenerated transfer payload: {:?}", transfer_payload);
// ANCHOR_END: build_transaction
// ANCHOR: custom_token_operations
// Build custom token operations
let mint_payload = my_token.mint(
recipient, // recipient
500_000, // amount
)?;
println!("Generated mint payload: {:?}", mint_payload);
let burn_payload = my_token.burn(
100_000, // amount
)?;
println!("Generated burn payload: {:?}", burn_payload);
// ANCHOR_END: custom_token_operations
// ANCHOR: view_functions
// View functions require an Aptos client (async)
println!("\n--- View Function Demo (requires network) ---");
println!("To call view functions, you need an Aptos client:");
println!();
println!(" let aptos = Aptos::new(AptosConfig::testnet())?;");
println!(" let coin = CoinModule::new();");
println!(" let balance = coin.view_balance(&aptos, owner, type_args).await?;");
println!(" let supply = my_token.view_total_supply(&aptos).await?;");
// ANCHOR_END: view_functions
// ANCHOR: generated_structs
// The macro also generates struct definitions
println!("\n--- Generated Struct: TokenInfo ---");
let token_info = TokenInfo {
name: "My Token".to_string(),
symbol: "MTK".to_string(),
decimals: 8,
total_supply: 1_000_000_000,
};
println!("TokenInfo: {:?}", token_info);
// ANCHOR_END: generated_structs
println!("\n=== Benefits of Type-Safe Bindings ===");
println!("1. Compile-time type checking for arguments");
println!("2. IDE autocomplete and documentation");
println!("3. Meaningful parameter names from Move source");
println!("4. No runtime ABI parsing overhead");
println!("5. Generated structs for Move types");
Ok(())
}