1
+ ////! Higher-level Ethereum utilities for common operations in Hyperware.
2
+ ////!
3
+ ////! This module provides utility functions for common Ethereum operations in the Hyperware
4
+ ////! ecosystem, particularly focusing on integrating with Hypermap for name resolution.
5
+ ////!
6
+ ////! The main goals of this module are:
7
+ ////! 1. Provide simple, developer-friendly functions for common operations
8
+ ////! 2. Abstract away the complexity of blockchain interactions
9
+ ////! 3. Integrate with Hypermap for human-readable addressing
10
+ ////!
11
+ ////! ## Usage Examples
12
+ ////!
13
+ ////! ```rust
14
+ ////! use hyperware_process_lib::eth_utils;
15
+ ////!
16
+ ////! // Send ETH to a Hypermap name
17
+ ////! let tx_hash = eth_utils::send_eth("alice.hypr", 1.3)?;
18
+ ////!
19
+ ////! // Check if a wallet owns an NFT
20
+ ////! let has_token = eth_utils::has_nft(contract_address, token_id, wallet_address)?;
21
+ ////!
22
+ ////! // Get a token balance
23
+ ////! let balance = eth_utils::get_token_balance(token_address, wallet_address)?;
24
+ ////!
25
+ ////! // Send tokens to a Hypermap name
26
+ ////! let tx_hash = eth_utils::send_token_to_name(token_address, "bob.hypr", amount)?;
27
+ ////! ```
28
+ //
29
+ //use crate::eth::{
30
+ // Address,
31
+ // EthError,
32
+ // TxHash,
33
+ // U256
34
+ //};
35
+ //use crate::hypermap::{Hypermap, HYPERMAP_ADDRESS};
36
+ //use crate::wallet::{Wallet, WalletError};
37
+ //use std::str::FromStr;
38
+ //use thiserror::Error;
39
+ //use sha3::Digest;
40
+ //
41
+ ///// Default chain ID to use for operations if not specified.
42
+ ///// Currently set to Base (Coinbase L2).
43
+ //pub const DEFAULT_CHAIN_ID: u64 = crate::hypermap::HYPERMAP_CHAIN_ID;
44
+ //
45
+ ///// Default timeout (in milliseconds) for Ethereum RPC operations.
46
+ //pub const DEFAULT_TIMEOUT_MS: u64 = 60_000; // 60 seconds
47
+ //
48
+ ///// Errors that can occur in Ethereum utility operations
49
+ //#[derive(Debug, Error)]
50
+ //pub enum EthUtilsError {
51
+ // #[error("Ethereum RPC error: {0}")]
52
+ // Eth(#[from] EthError),
53
+ //
54
+ // #[error("Wallet error: {0}")]
55
+ // Wallet(#[from] WalletError),
56
+ //
57
+ // #[error("Name resolution error: {0}")]
58
+ // NameResolution(String),
59
+ //
60
+ // #[error("Transaction error: {0}")]
61
+ // Transaction(String),
62
+ //}
63
+ //
64
+ ///// Send Ether to an address
65
+ /////
66
+ ///// This function creates, signs, and sends a transaction to send ETH to an address.
67
+ /////
68
+ ///// # Parameters
69
+ ///// - `provider`: The Ethereum provider to use
70
+ ///// - `wallet`: The wallet to send from
71
+ ///// - `to`: The recipient address
72
+ ///// - `amount_wei`: The amount to send in wei
73
+ ///// - `gas_limit`: Optional gas limit (defaults to 21000)
74
+ ///// - `gas_price`: Optional gas price (defaults to auto-estimation)
75
+ /////
76
+ ///// # Returns
77
+ ///// A `Result<TxHash, EthUtilsError>` representing the transaction hash if successful
78
+ /////
79
+ ///// # Example
80
+ ///// ```rust
81
+ ///// use hyperware_process_lib::{eth_utils, wallet, eth};
82
+ ///// use alloy_primitives::{Address, U256};
83
+ ///// use std::str::FromStr;
84
+ /////
85
+ ///// // Create wallet and provider
86
+ ///// let wallet = wallet::Wallet::from_private_key(
87
+ ///// "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
88
+ ///// 8453 // Base chain ID
89
+ ///// )?;
90
+ ///// let provider = eth::Provider::new(8453, 60000);
91
+ ///// let to = Address::from_str("0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf")?;
92
+ ///// let amount = U256::from(1000000000000000000u64); // 1 ETH
93
+ /////
94
+ ///// // Send ETH
95
+ ///// let tx_hash = eth_utils::send_eth(&provider, &wallet, to, amount, None, None)?;
96
+ ///// println!("Transaction hash: {}", tx_hash);
97
+ ///// ```
98
+ //pub fn send_eth(
99
+ // provider: &crate::eth::Provider,
100
+ // wallet: &Wallet,
101
+ // to: Address,
102
+ // amount_wei: U256,
103
+ // gas_limit: Option<u64>,
104
+ // gas_price: Option<u128>
105
+ //) -> Result<TxHash, EthUtilsError> {
106
+ // // Create RLP-encoded transaction
107
+ // let nonce = provider.get_transaction_count(wallet.address(), None)?;
108
+ // let nonce_u64 = u64::try_from(nonce).unwrap_or(0);
109
+ //
110
+ // // Get gas price if not provided
111
+ // let gas_price_value = if let Some(price) = gas_price {
112
+ // price
113
+ // } else {
114
+ // let current_gas_price = provider.get_gas_price()?;
115
+ // u128::try_from(current_gas_price).unwrap_or(20000000000)
116
+ // };
117
+ //
118
+ // // Get gas limit
119
+ // let gas_limit_value = gas_limit.unwrap_or(21000);
120
+ //
121
+ // // Create and sign a transaction manually
122
+ // // First, construct the RLP-encoded transaction
123
+ // let mut rlp_data = Vec::new();
124
+ // rlp_data.extend_from_slice(to.as_slice());
125
+ // rlp_data.extend_from_slice(&amount_wei.to_be_bytes::<32>());
126
+ // rlp_data.extend_from_slice(&nonce_u64.to_be_bytes());
127
+ // rlp_data.extend_from_slice(&gas_limit_value.to_be_bytes());
128
+ // rlp_data.extend_from_slice(&gas_price_value.to_be_bytes());
129
+ //
130
+ // // Hash the transaction data with keccak256
131
+ // let mut hasher = sha3::Keccak256::new();
132
+ // hasher.update(&rlp_data);
133
+ // let tx_hash = hasher.finalize();
134
+ //
135
+ // // Sign the transaction hash
136
+ // let signed_tx = wallet.sign_transaction_hash(&tx_hash)?;
137
+ //
138
+ // // Send raw transaction
139
+ // let tx_hash = provider.send_raw_transaction(signed_tx)?;
140
+ //
141
+ // Ok(tx_hash)
142
+ //}
143
+ //
144
+ ///// Sends Ether to the owner of the specified Hypermap name.
145
+ /////
146
+ ///// This function first resolves the name to its owner address using Hypermap,
147
+ ///// then sends the specified amount of Ether to that address.
148
+ /////
149
+ ///// # Parameters
150
+ ///// - `provider`: The Ethereum provider to use
151
+ ///// - `wallet`: The wallet to send from
152
+ ///// - `name`: The Hypermap name (e.g., "alice.hypr")
153
+ ///// - `amount_eth`: The amount of Ether to send (as a f64)
154
+ /////
155
+ ///// # Returns
156
+ ///// A `Result<TxHash, EthUtilsError>` representing the transaction hash if successful
157
+ /////
158
+ ///// # Example
159
+ ///// ```rust
160
+ ///// use hyperware_process_lib::{eth_utils, wallet, eth};
161
+ /////
162
+ ///// // Create wallet and provider
163
+ ///// let wallet = wallet::Wallet::from_private_key(
164
+ ///// "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
165
+ ///// 8453 // Base chain ID
166
+ ///// )?;
167
+ ///// let provider = eth::Provider::new(8453, 60000);
168
+ /////
169
+ ///// // Send 1.3 ETH to alice.hypr
170
+ ///// let tx_hash = eth_utils::send_eth_to_name(&provider, &wallet, "alice.hypr", 1.3)?;
171
+ ///// println!("Transaction hash: {}", tx_hash);
172
+ ///// ```
173
+ //pub fn send_eth_to_name(
174
+ // provider: &crate::eth::Provider,
175
+ // wallet: &Wallet,
176
+ // name: &str,
177
+ // amount_eth: f64
178
+ //) -> Result<TxHash, EthUtilsError> {
179
+ // // Get Hypermap instance using our provider
180
+ // let hypermap = Hypermap::new(provider.clone(),
181
+ // Address::from_str(HYPERMAP_ADDRESS).unwrap());
182
+ //
183
+ // // Format the name if needed (add .hypr if missing)
184
+ // let formatted_name = format_hypermap_name(name);
185
+ //
186
+ // // Resolve name to owner address
187
+ // let (_, owner, _) = hypermap.get(&formatted_name)
188
+ // .map_err(|e| EthUtilsError::NameResolution(format!("Failed to resolve name '{}': {}", formatted_name, e)))?;
189
+ //
190
+ // // Convert amount to wei (1 ETH = 10^18 wei)
191
+ // let amount_wei = (amount_eth * 1e18) as u128;
192
+ // let amount_in_wei = U256::from(amount_wei);
193
+ //
194
+ // // Send ETH to the resolved address
195
+ // send_eth(provider, wallet, owner, amount_in_wei, None, None)
196
+ //}
197
+ //
198
+ ///// Format a name for Hypermap resolution
199
+ /////
200
+ ///// If the name already contains a dot (.), it's returned as is.
201
+ ///// Otherwise, ".hypr" is appended to the name.
202
+ /////
203
+ ///// # Parameters
204
+ ///// - `name`: The name to format
205
+ /////
206
+ ///// # Returns
207
+ ///// A formatted name suitable for Hypermap resolution
208
+ //fn format_hypermap_name(name: &str) -> String {
209
+ // // If name already has a domain extension, return as is
210
+ // if name.contains('.') {
211
+ // return name.to_string();
212
+ // }
213
+ //
214
+ // // Otherwise, add the default .hypr extension
215
+ // format!("{}.hypr", name)
216
+ //}
217
+ //
218
+ ///// Resolve a Hypermap name to its owner's Ethereum address
219
+ /////
220
+ ///// # Parameters
221
+ ///// - `name`: The Hypermap name to resolve
222
+ ///// - `chain_id`: Optional chain ID to use (defaults to Base chain)
223
+ ///// - `timeout_ms`: Optional timeout in milliseconds (defaults to 60 seconds)
224
+ /////
225
+ ///// # Returns
226
+ ///// A `Result<Address, EthError>` representing the owner's Ethereum address
227
+ /////
228
+ ///// # Example
229
+ ///// ```rust
230
+ ///// use hyperware_process_lib::eth_utils;
231
+ /////
232
+ ///// let owner = eth_utils::resolve_name("alice.hypr", None, None)?;
233
+ ///// println!("Owner address: {}", owner);
234
+ ///// ```
235
+ //pub fn resolve_name(
236
+ // name: &str,
237
+ // chain_id: Option<u64>,
238
+ // timeout_ms: Option<u64>
239
+ //) -> Result<Address, EthError> {
240
+ // // Use provided chain ID or default
241
+ // let chain_id = chain_id.unwrap_or(DEFAULT_CHAIN_ID);
242
+ // let timeout = timeout_ms.unwrap_or(DEFAULT_TIMEOUT_MS);
243
+ //
244
+ // // Create provider
245
+ // let provider = crate::eth::Provider::new(chain_id, timeout);
246
+ //
247
+ // // Get Hypermap instance using our provider
248
+ // let hypermap = Hypermap::new(provider,
249
+ // Address::from_str(HYPERMAP_ADDRESS).unwrap());
250
+ //
251
+ // // Format the name if needed (add .hypr if missing)
252
+ // let formatted_name = format_hypermap_name(name);
253
+ //
254
+ // // Resolve name to owner address
255
+ // let (_, owner, _) = hypermap.get(&formatted_name)?;
256
+ //
257
+ // Ok(owner)
258
+ //}
259
+ //
260
+ //#[cfg(test)]
261
+ //mod tests {
262
+ // use super::*;
263
+ // use alloy_primitives::{Address, U256};
264
+ // use std::str::FromStr;
265
+ //
266
+ // #[test]
267
+ // fn test_format_hypermap_name() {
268
+ // // Test with name that already has dot
269
+ // let name_with_dot = "test.hypr";
270
+ // assert_eq!(format_hypermap_name(name_with_dot), name_with_dot);
271
+ //
272
+ // // Test with name that doesn't have dot
273
+ // let name_without_dot = "test";
274
+ // assert_eq!(format_hypermap_name(name_without_dot), "test.hypr");
275
+ // }
276
+ //
277
+ // // Note: These tests would need real providers and wallets to run
278
+ // // We'll implement placeholders that describe what should be tested
279
+ //
280
+ // #[test]
281
+ // #[ignore] // Ignore this test since it requires network connectivity
282
+ // fn test_resolve_name() {
283
+ // // This would test name resolution with real provider and chain
284
+ // // let name = "test.hypr";
285
+ // // let result = resolve_name(name, Some(DEFAULT_CHAIN_ID), Some(DEFAULT_TIMEOUT_MS));
286
+ // // assert!(result.is_ok());
287
+ // }
288
+ //
289
+ // #[test]
290
+ // #[ignore] // Ignore this test since it requires network connectivity
291
+ // fn test_send_eth_to_name() {
292
+ // // This would test ETH sending with real provider and wallet
293
+ // // let wallet = Wallet::new_random(DEFAULT_CHAIN_ID).unwrap();
294
+ // // let provider = crate::eth::Provider::new(DEFAULT_CHAIN_ID, DEFAULT_TIMEOUT_MS);
295
+ // // let result = send_eth_to_name(&provider, &wallet, "test.hypr", 0.001);
296
+ // // assert!(result.is_ok());
297
+ // }
298
+ //}
0 commit comments