Как перебить транзакцию в Ethereum и написать софт, который поможет обезопасить свои деньги?
Мой канал: https://t.me/codeherooo
Для чего нужен этот софт?
Вы наверно видели, что некоторым людям нужен софт для перебития транзакций. Часто, у них очень много сид-фраз или приваткеев, которые они получили не очень честным способом. Они могут его немного доработать, чтобы перебивать транзакции, которые уже были перебиты. Но, если доступ к кошельку будет у двух таких людей, то они начнут перебивать друг друга и все деньги будут потрачены на газ, а количество монет, которые придут к кошельку одного из людей, будет минимальным, ведь все монеты будут потрачены на газ.
Кроме того, этот механизм можно использовать его для защиты наших денег. Если кто-то получит нашу сид-фразу или приваткей и попытается вывести наши монеты, то мы сможем сохранить их, отправив на резервный кошелёк.
ВАЖНО: не забудьте выключить софт, когда вы сами попытаетесь отправить деньги, иначе софт перебьёт транзакцию и деньги уйдут на ваш резервный кошелёк
Принцип работы софта
Как работает отправка транзакций в блокчейне?
- Кто-то создаёт транзакцию, подписывает её с помощью приватного ключа. Обычно транзакция включает в себя адрес получателя, сумму эфира (ETH), которую вы хотите отправить, цену газа и другие необязательные данные.
- После создания транзакции ее необходимо распространить по сети Ethereum. Кто-то отправляет транзакцию через ноду.
- Транзакции, которые были распространены, временно хранятся в пуле памяти, называемом mempool, на каждом узле. Майнеры выбирают транзакции из этого пула для включения в следующий блок. Выбор транзакций может зависеть от нескольких факторов, таких как комиссия (цена газа), прикрепленная к транзакции, размер транзакции и другие параметры.
- Майнер собирает выбранные транзакции в блок. Важно отметить, что существует ограничение по размеру блока и количество транзакций, которые могут быть включены в один блок, определяется размером блока и текущими правилами протокола Ethereum.
Как работает софт?
Софт отслеживает последние отправленные транзакции, если транзакция была отправлена с нашего адреса, но не на наш адрес, то отправляется транзакция с большей ценой за газ и тем же нонсом. Наша транзакция проходит быстрее, а старая пропадает и наши деньги попадают на наш резервный кошелёк.
Написание софта
Для выполнения транзакции необходимо обнаружить попытку отправки транзакции и произвести отправку идентичной транзакции на наш резервный адрес, но с повышенной комиссией. Реализация кода осуществляется на языке программирования C# с применением библиотеки Nethereum.
Получение отправленных транзакций
Получать отправленные в блокчейн транзакции мы будем с помощью subscription на newPendingTransactions.
using Nethereum.JsonRpc.WebSocketStreamingClient; using Nethereum.RPC.Reactive.Eth.Subscriptions; namespace MoneyGuard { internal class Program { static void Main(string[] args) { string reading = Console.ReadLine(); NewPendingTransactions(); while (reading != "stop") { reading = Console.ReadLine(); } } public static async Task NewPendingTransactions() { using (var client = new StreamingWebSocketClient("wss://YOURNODE")) { // create the subscription // it won't start receiving data until Subscribe is called on it var subscription = new EthNewPendingTransactionObservableSubscription(client); // attach a handler subscription created event (optional) // this will only occur once when Subscribe has been called subscription.GetSubscribeResponseAsObservable().Subscribe(subscriptionId => Console.WriteLine("Pending transactions subscription Id: " + subscriptionId)); // attach a handler for each pending transaction // put your logic here subscription.GetSubscriptionDataResponsesAsObservable().Subscribe(transactionHash => { Console.WriteLine("New Pending TransactionHash: " + transactionHash); }); bool subscribed = true; //handle unsubscription //optional - but may be important depending on your use case subscription.GetUnsubscribeResponseAsObservable().Subscribe(response => { subscribed = false; Console.WriteLine("Pending transactions unsubscribe result: " + response); }); //open the websocket connection await client.StartAsync(); // start listening for pending transactions // this will only block long enough to register the subscription with the client // it won't block whilst waiting for transactions // transactions will be delivered to our handlers on another thread await subscription.SubscribeAsync(); // run for day // transactions should appear on another thread await Task.Delay(TimeSpan.FromDays(1)); // unsubscribe await subscription.UnsubscribeAsync(); // wait for unsubscribe while (subscribed) { await Task.Delay(TimeSpan.FromSeconds(1)); } } } } }
ЗАМЕНИТЕ: wss://YOURNODE на адрес вашей ноды.
Данный код подпишется на новые транзакции к вашей ноде и будет выводить хэш каждой транзокции в консоль.
Обработка транзакции
После того, как мы хэш транзакции, которую кто-то отправил, мы должны получить данные об этой транзакции (адрес, с которого она была отправлена, адрес, на который, она была отправлена, количество монет, газпрайс, газ и т.д.)
var transaction = await web3.Eth.Transactions.GetTransactionByHash.SendRequestAsync(transactionHash);
Подготовка транзакции
Ещё до подписки на pending transactions нам нужно сохранить приваткей и резервный адрес
var privateKey = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7"; var account = new Account(privateKey); var web3 = new Web3(account, "ТУТ НУЖЕН https:// АДРЕС ВАЩЕЙ НОДЫ"); var toAddress "0x13f022d72158410433cbd66f5dd8bf6d2d129924554";
Отправка транзакции
Отправить транзакцию нам нужно с тем же нонсом, что и в транзакции, что обнаружили. ГазПрайс должен быть выше, адрес - наш резервный, количество монет - то же самое или чуть меньше.
await web3.Eth.GetEtherTransferService().TransferEtherAndWaitForReceiptAsync(toAddress, Web3.Convert.FromWei(transaction.Value), Web3.Convert.FromWei(transaction.GasPrice) + 100m, new BigInteger(21000), transaction.Nonce);
Готовый софт
Я немного изменил его, чтобы можно было запустить .exe файл и ввести данные.
using Nethereum.JsonRpc.WebSocketStreamingClient; using Nethereum.RPC.Reactive.Eth.Subscriptions; using Nethereum.Web3; using Nethereum.Web3.Accounts; using System.Numerics; namespace MoneyGuard { internal class Program { static void Main(string[] args) { string reading = ""; NewPendingTransactions(); while (reading != "stop") { reading = Console.ReadLine(); } } public static async Task NewPendingTransactions() { Console.WriteLine("Enter your privateKey"); var privateKey = Console.ReadLine(); var account = new Account(privateKey); Console.WriteLine("Enter your toAddress"); var toAddress = Console.ReadLine().ToLower(); Console.WriteLine("Enter your fromAddress"); var fromAddress = Console.ReadLine().ToLower(); Console.WriteLine("Enter your https node"); var web3 = new Web3(account, Console.ReadLine()); Console.WriteLine("Enter your wss node"); using (var client = new StreamingWebSocketClient(Console.ReadLine())) { // create the subscription // it won't start receiving data until Subscribe is called on it var subscription = new EthNewPendingTransactionObservableSubscription(client); // attach a handler subscription created event (optional) // this will only occur once when Subscribe has been called subscription.GetSubscribeResponseAsObservable().Subscribe(subscriptionId => Console.WriteLine("Started checking!")); Console.WriteLine("To stop: enter \"stop\""); // attach a handler for each pending transaction // put your logic here subscription.GetSubscriptionDataResponsesAsObservable().Subscribe(async transactionHash => { // get the transaction receipt //print the transaction receipt var transaction = await web3.Eth.Transactions.GetTransactionByHash.SendRequestAsync(transactionHash); if (transaction != null) { if (transaction.From == fromAddress && transaction.To != toAddress) { await web3.Eth.GetEtherTransferService().TransferEtherAndWaitForReceiptAsync(toAddress, Web3.Convert.FromWei(transaction.Value), Web3.Convert.FromWei(transaction.GasPrice) + 100m, new BigInteger(21000), transaction.Nonce); Console.WriteLine("Fight!"); } } }); bool subscribed = true; //handle unsubscription //optional - but may be important depending on your use case subscription.GetUnsubscribeResponseAsObservable().Subscribe(response => { subscribed = false; Console.WriteLine("Pending transactions unsubscribe result: " + response); }); //open the websocket connection await client.StartAsync(); // start listening for pending transactions // this will only block long enough to register the subscription with the client // it won't block whilst waiting for transactions // transactions will be delivered to our handlers on another thread await subscription.SubscribeAsync(); // run for day // transactions should appear on another thread await Task.Delay(TimeSpan.FromDays(30)); // unsubscribe await subscription.UnsubscribeAsync(); // wait for unsubscribe while (subscribed) { await Task.Delay(TimeSpan.FromSeconds(1)); } } } } }
Ссылка на гитхаб: https://github.com/codeheroo/EthereumCoinGuard
Мой канал: https://t.me/codeherooo