January 11, 2024

Как перебить транзакцию в Ethereum и написать софт, который поможет обезопасить свои деньги?

  1. Для чего нужен этот софт?
  2. Принцип работы софта.
  3. Написание софта.
  4. Готовый софт.
Ethereum

Мой канал: https://t.me/codeherooo

Для чего нужен этот софт?

Вы наверно видели, что некоторым людям нужен софт для перебития транзакций. Часто, у них очень много сид-фраз или приваткеев, которые они получили не очень честным способом. Они могут его немного доработать, чтобы перебивать транзакции, которые уже были перебиты. Но, если доступ к кошельку будет у двух таких людей, то они начнут перебивать друг друга и все деньги будут потрачены на газ, а количество монет, которые придут к кошельку одного из людей, будет минимальным, ведь все монеты будут потрачены на газ.

Кроме того, этот механизм можно использовать его для защиты наших денег. Если кто-то получит нашу сид-фразу или приваткей и попытается вывести наши монеты, то мы сможем сохранить их, отправив на резервный кошелёк.

ВАЖНО: не забудьте выключить софт, когда вы сами попытаетесь отправить деньги, иначе софт перебьёт транзакцию и деньги уйдут на ваш резервный кошелёк

картинка с транзакциями

Принцип работы софта

Как работает отправка транзакций в блокчейне?

  1. Кто-то создаёт транзакцию, подписывает её с помощью приватного ключа. Обычно транзакция включает в себя адрес получателя, сумму эфира (ETH), которую вы хотите отправить, цену газа и другие необязательные данные.
  2. После создания транзакции ее необходимо распространить по сети Ethereum. Кто-то отправляет транзакцию через ноду.
  3. Транзакции, которые были распространены, временно хранятся в пуле памяти, называемом mempool, на каждом узле. Майнеры выбирают транзакции из этого пула для включения в следующий блок. Выбор транзакций может зависеть от нескольких факторов, таких как комиссия (цена газа), прикрепленная к транзакции, размер транзакции и другие параметры.
  4. Майнер собирает выбранные транзакции в блок. Важно отметить, что существует ограничение по размеру блока и количество транзакций, которые могут быть включены в один блок, определяется размером блока и текущими правилами протокола Ethereum.

Как работает софт?

Софт отслеживает последние отправленные транзакции, если транзакция была отправлена с нашего адреса, но не на наш адрес, то отправляется транзакция с большей ценой за газ и тем же нонсом. Наша транзакция проходит быстрее, а старая пропадает и наши деньги попадают на наш резервный кошелёк.

Написание софта

Для выполнения транзакции необходимо обнаружить попытку отправки транзакции и произвести отправку идентичной транзакции на наш резервный адрес, но с повышенной комиссией. Реализация кода осуществляется на языке программирования C# с применением библиотеки Nethereum.

  1. Получить транзакцию
  2. Обработать транзакцию
  3. Подготовить транзакцию
  4. Отправить транзакцию

Получение отправленных транзакций

Получать отправленные в блокчейн транзакции мы будем с помощью 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