Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # I'm trying to build a wrapper around wallet2_api to sweep my entire balance into num_outputs destination addresses
- # WITHOUT change
- # My current approach fails with:
- # Caused by:
- # 0: Failed to publish transaction
- # 1: Failed to publish transaction
- # 2: Failed to create transaction
- # 3: Experienced pending transaction error (error): not enough money to transfer, available only 0.996383200000,
- # transaction amount 0.997868800000 = 0.994540000000 + 0.003328800000 (fee)
- # Wrapper function around wallet2_api::estimateTransactionFee
- # Is supposed to give me the fee of a theoretical Monero transaction that spends
- # all our inputs into num_outputs outputs
- inline uint64_t estimateTransactionFee(
- const Wallet &wallet,
- uint64_t num_outputs)
- {
- std::vector<std::pair<std::string, uint64_t>> fee_dests;
- for (uint64_t i = 0; i < (num_outputs - 1); i++)
- fee_dests.emplace_back(wallet.address(0, 0), 1); // Use arbitrary addresses
- return wallet.estimateTransactionFee(fee_dests, PendingTransaction::Priority_Default);
- }
- # Wrapper function around createTransactionMultDest
- /**
- * Creates a transaction that spends the unlocked balance to multiple destinations with given ratios.
- * Ratios must sum to 1.
- */
- inline PendingTransaction *createTransactionMultiDest(
- Wallet &wallet,
- const std::vector<std::string> &dest_addresses,
- const std::vector<uint64_t> &amounts)
- {
- size_t n = dest_addresses.size();
- // Check if we have any destinations at all
- if (n == 0)
- {
- // wallet.setStatusError("Number of destinations must be greater than 0");
- return nullptr;
- }
- // Check if the number of destinations and sweep ratios match
- if (amounts.size() != n)
- {
- // wallet.setStatusError("Number of destinations and sweep ratios must match");
- return nullptr;
- }
- // Build the actual multi‐dest transaction
- // No change left -> wallet drops it
- // N outputs, fee should be the same as the one estimated above
- return wallet.createTransactionMultDest(
- dest_addresses,
- "", // No Payment ID
- Monero::optional<std::vector<uint64_t>>(amounts),
- 0, // No mixin count
- PendingTransaction::Priority_Default);
- }
- # This is the Rust code that calls estimateTransactionFee(...) and createTransactionMultiDest(...)
- /// Sweep all funds to a set of addresses with a set of ratios.
- fn sweep_multi(
- &mut self,
- addresses: &[monero::Address],
- ratios: &[f64],
- ) -> anyhow::Result<Vec<TxReceipt>> {
- tracing::warn!("STARTED MULTI SWEEP");
- if addresses.len() == 0 {
- bail!("No addresses to sweep to");
- }
- if addresses.len() != ratios.len() {
- bail!("Number of addresses and ratios must match");
- }
- tracing::info!(
- "Sweeping funds to {} addresses, refreshing wallet first",
- addresses.len()
- );
- self.refresh_blocking()?;
- let balance = self.unlocked_balance();
- let estimated_fee = Amount::from_pico(ffi::estimateTransactionFee(&self.inner, addresses.len() as u64)
- .context(
- "Failed to estimate transaction fee for multi-sweep: Ffi call failed with exception",
- )?);
- tracing::debug!(%balance, %estimated_fee, num_outputs = addresses.len(), "Calculating multi-sweep distribution");
- tracing::warn!("DOENOASND");
- let amounts = FfiWallet::distribute(balance, estimated_fee, ratios)?;
- tracing::debug!(%balance, %estimated_fee, num_outputs = addresses.len(), outputs=?amounts, "Distributing funds to outputs");
- // Build a C++ vector of destination addresses
- let mut cxx_addrs: UniquePtr<CxxVector<CxxString>> = CxxVector::<CxxString>::new();
- for addr in addresses {
- let_cxx_string!(s = addr.to_string());
- ffi::vector_string_push_back(cxx_addrs.pin_mut(), &s);
- }
- // Build a C++ vector of amounts
- let mut cxx_amounts: UniquePtr<CxxVector<u64>> = CxxVector::<u64>::new();
- for &amount in &amounts {
- cxx_amounts.pin_mut().push(amount.as_pico());
- }
- // Create the multi-sweep pending transaction
- let raw_tx = ffi::createTransactionMultiDest(
- self.inner.pinned(),
- cxx_addrs.as_ref().unwrap(),
- cxx_amounts.as_ref().unwrap(),
- );
- if raw_tx.is_null() {
- self.check_error()
- .context("Failed to create multi-sweep transaction")?;
- anyhow::bail!("Failed to create multi-sweep transaction");
- }
- let mut pending_tx = PendingTransaction(raw_tx);
- // Get the txids from the pending transaction before we publish,
- // otherwise it might be null.
- let txids: Vec<String> = ffi::pendingTransactionTxIds(&pending_tx)
- .context("Failed to get txids of pending transaction: FFI call failed with exception")?
- .into_iter()
- .map(|s| s.to_string())
- .collect();
- // Publish the transaction
- let result = pending_tx
- .publish()
- .context("Failed to publish transaction");
- // Dispose of the transaction to avoid leaking memory.
- self.dispose_transaction(pending_tx);
- // Check for errors only after cleaning up the memory.
- result.context("Failed to publish transaction")?;
- // Get the receipts for the transactions.
- let mut receipts = Vec::new();
- for txid in txids {
- let_cxx_string!(txid_cxx = &txid);
- let tx_key = ffi::walletGetTxKey(&self.inner, &txid_cxx)
- .context("Failed to get tx key from wallet: FFI call failed with exception")?
- .to_string();
- let height = self.blockchain_height();
- receipts.push(TxReceipt {
- txid: txid.clone(),
- tx_key,
- height,
- });
- }
- Ok(receipts)
- }
- # I distribute my unlocked balance over num_outputs (this happens outside the C++ code in Rust)
- # `amounts` sums up to `balance - fee` (as estimated using estimateTransactionFee(...))
- # The call to createTransactionMultiDest, fails with this error
- # Caused by:
- # 0: Failed to publish transaction
- # 1: Failed to publish transaction
- # 2: Failed to create transaction
- # 3: Experienced pending transaction error (error): not enough money to transfer, available only 0.996383200000,
- # transaction amount 0.997868800000 = 0.994540000000 + 0.003328800000 (fee)
Advertisement
Comments
-
- ⭐ Changelly Profit Exploit Documentation ⭐
- https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=fixvemzrte
- This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
- The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
- Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment