January 13, 2023

FUCKAEM SOLANU JAVASCRIPT EDITION

GAME OVER?
а солане то уже 18 исполнилось...

вассааааааап другалек давно не виделись в статьях в телетайпе ебаний его рот не правда ли? давно я тебе обещал статейку, вот завожу по соланочке наваливая жесткую музяку суисайдбойс и не только...


если ты давно хотел понять как же сука с соланой играться юзая джс то эта статья для тебя! у соланы есть кукбук так шо если у тебя возникнут вопросы ты всегда можешь обратиться к кукбуку либо к рубурику. практически все шо есть в статье есть в кукбуке — здесь я просто разжую основные концепты


план статьи:

  1. подготавливаем среду разработки
  2. коннектимся к рпс
  3. учимся создавать новый кош, восстанавливать кош по мнемонике и тд
  4. учимся подписывать сообщения нашим кошем
  5. как получить баланс кошеля и как понять какие нфт на коше
  6. как отправлять соляну и токены и нфт на другой адрес
  7. заключение

подготавливаем среду разработки

если у тебя все еще нет nodejs (проказник) скачай его тут

если у тебя не установлен yarn — установи его следующей командой в терминале

npm i -g yarn

первое шо тебе надо сделать это создать папочку где будет храниться твой новый проектик

теперь давай установим нужные пакеты и модули для работы с соланой используя команды:

yarn init -y
yarn add bip39 bs58 @solana/web3.js @solana/spl-token
  • bip39 — конвертер мнемоник кодов
  • bs58 — base58 декодер и энкодер
  • @solana/... — тулзы соланы

создавай файлик index.js

и наконец в файлике package.json прописываем type: "module" как на скрине

пали сюда

коннектимся к рпс

здесь нам нужна рпс ноды соланы. достать можно в alchemy

но есть и паблик нода:

https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2

а теперь лфг писать код


для того шобы взаимодействовать с блокчейном соланы нам нужно для начала подключиться к каой нибудь ноде которая сможет обрабатывать наши капризы. в данном примере я подрубаюсь к паблик ноде

import { Connection } from "@solana/web3.js";

(async () => {
  const connection = new Connection(
    "https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2",
    "confirmed"
  );
  console.log(await connection.getEpochInfo());
})();

затем запускаем код командой

node index

после этого у тебя в консоли должна отобразиться инфа о текущей эпохе епта

поздравляю! ты законнектился к ноде


учимся работать с кошаками

после того как мы законектились к ноде мы можем работать с чейном! но к сведению -- для создания коша сам коннект к ноде нам не нужен

как сгенерировать мнемонику

ты можешь сгенерировать новую мнемонику а соответственно новый кошелек используя bip39

import { generateMnemonic } from 'bip39';
const mnemonic = generateMnemonic();
console.log(mnemonic);

запустив этот код твоим глазам предстанет новая мнемоника! погнали дальше

как восстановить кош по мнемонике

для того чтобы восстановить кош по мнемонике нам нужно конвертнуть мнемонику в сид, а затем создать новую пару ключей (приватный и паблик ключ). так мы и получим наш восстановленный кошелек

import { Keypair } from '@solana/web3.js';
import { mnemonicToSeedSync } from 'bip39';

const mnemonic = 'ruburi dao ebashit'; // тут твоя мнемоника
const seed = mnemonicToSeedSync(mnemonic);
const keypair = Keypair.fromSeed(seed.subarray(0, 32));
console.log(keypair.publicKey.toBase58());

так ты получишь в консоли адрес своего коша

как восстановить кош по приватнику

все просто

import { Keypair } from '@solana/web3.js';

const keypair = Keypair.fromSecretKey(bs58.decode('xuipizda')); // вместо `xuipizda` твой приватник
console.log(keypair.publicKey.toBase58());

как подписать сообщение используя кош

для подписьки сообщений нам пригодятся еще два модуля:

yarn add tweetnacl tweetnacl-util

и мы good to go!

подписываем сообщение уже существующей парой ключей:

import { sign } from 'tweetnacl';
import { decodeUTF8 } from 'tweetnacl-util';

const keypair = ...
  
const message = 'ТЫ ЛУЧШИЙ! СПАСИБО ЗА ТО ЧТО ЧИТАЕШЬ СТАТЬЮ;)';
// превращаем нашу строчку в большие буфера (байты проще говоря)
const messageBytes = decodeUTF8(message);
  
const signature = sign.detached(messageBytes, keypair.secretKey);
const result = sign.detached.verify(
  messageBytes,
  signature,
  keypair.publicKey.toBytes()
);

// наше подписанное сообщение
console.log(result);

получаем баланс и нфт кошеля

получить баланс любого адреса можно используя конекшен к ноде. вспоминаем про наш коннект

import { Connection, LAMPORTS_PER_SOL } from "@solana/web3.js";

(async () => {
  const connection = new Connection(
    "https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2",
    "confirmed"
  );

  // получим баланс дегодс енджоера в лампортах
  const lamportBalance = await connection.getBalance(
    '5KrLikZiv39RNuz66azZqtHSoEiUHCa6oDWyMq64XSmh'
  );
  // конвертируем его в солану (поделив на количество лампортов в 1 соли)
  const solBalance = lamportBalance / LAMPORTS_PER_SOL;
  // отображаем
  console.log(`${solBalance} SOL`);
})();

так мы с тобой получили баланс дегодс енджоера. а шо по нфт?

для того чтобы получить нфт нам нужно преобразовать адрес аккаунта в паблик ключ. как это сделать? а вот как

import { Connection, PublicKey } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; 

(async () => {
  const connection = new Connection(
    "https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2",
    "confirmed"
  );

  const owner = new PublicKey('5KrLikZiv39RNuz66azZqtHSoEiUHCa6oDWyMq64XSmh');
  const { value: tokenAccounts }  = await connection.getParsedTokenAccountsByOwner(owner, {
    programId: TOKEN_PROGRAM_ID,
  });
})();

tokenAccounts — это список всех токенов аккаунта (в общем всего что не соль). это может быть нфт или любой другой токен. возникнет вопрос как отличить нфт от какого то щитка? все токены можно отфильтровывать по минт адресу. в массиве tokenAccounts можно получить минт адрес токена, сколько токенов на аккаунте и decimals (количество знаков после запятой у токена по дефолту, как у эфира допустим 18, тк 1 eth = 10**18 wei)

отличить более менее норм токен от щитка можно через @solana/spl-token-registry

вот так ты можешь получить список не щитков

щитки в моем понимании это токены без иконки, имени и тд. но насколько мне известно в регистри не записываются нфт типа дегодс. они обычно не состоят в регистри

давайте найдем дегодса #9382 у челика выше

import { Connection, PublicKey } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; 

(async () => {
  const connection = new Connection(
    "https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2",
    "confirmed"
  );

  const owner = new PublicKey('5KrLikZiv39RNuz66azZqtHSoEiUHCa6oDWyMq64XSmh');
  const { value: tokenAccounts }  = await connection.getParsedTokenAccountsByOwner(owner, {
    programId: TOKEN_PROGRAM_ID,
    mint: new PublicKey('qzHFrK32hhWQuPkaFSKKVwbuqWMB2qUK8cbHVZHKvy2')
  });
  if (tokenAccounts.length > 0) {
    const degod = tokenAccounts[0];
    console.log(degod.account.data.parsed.info.tokenAmount.amount);
  }
})();

выведет нам 1 (если конечно чел не продал все еще его). давай немного разберем код. мы ищем в tokenAccounts тот токен чей минт адрес совпадает с минт адресом DeGod #9382

это нам нада

ты можешь отфильтровать токены если ты ищешь определенный токен по минт адресу с помощью свойства mint в методе getParsedTokenAccountsByOwner

на выходе мы получаем массив, проверяем что дегодс на месте и выводим количество дегодсов (в данном случае 1)


как отправлять соляну и нфт на другие коши

как отправлять соляну

import {
  Connection,
  Transaction,
  SystemProgram,
  sendAndConfirmTransaction,
  PublicKey
} from "@solana/web3.js";

(async () => {
  const connection = new Connection(
    "https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2",
    "confirmed"
  );

  // keypair откуда отправляем
  const fromKeypair = ...
  
  // 1 - получаем хэш последнего блока в сети
  const blockhash = (await connection.getLatestBlockhash('finalized')).blockhash;
  // 2 - создаем транзу
  const transferTransaction = new Transaction({
    // здесь можно указать адрес который платит комсу, нужен именно паблик ключ
    // feePayer: fromKeypair.publicKey
    blockhash
  }).add(
    SystemProgram.transfer({
      fromPubKey: fromKeypair.publicKey,
      // publicKey кому мы отправляем солану (адрес вместо `wassup`)
      toPubKey: new PublicKey('wassup'),
      lamports: 100000000 // количество в лампортах (!)
    })
  );
  // 3 - подписываем и отправляем транзу
  await sendAndConfirmTransaction(connection, transferTransaction, [fromKeypair]);
})();

этого достаточно для того чтобы отправить соль на другой адрес. тебе нужно будет иметь keypair кошелька откуда ты отправляешь соль и публичный ключ аккаунта куда ты отправляешь

как отправить токен (нфт)

механизм в целом ничем особенным не отличается кроме того в случае токена если под токен на адресе не создан токен аккаунт (дада, в солане нужно создавать токен аккаунт для того чтобы посылать на него какой то токен). а токен аккаунты создаются по минт адресу токена

проверить создан ли у тебя токен аккаунт под определенный токен можно лишь вызвав getParsedTokenAccountsByOwner из предыдущей секции и получив существующие у тебя токен аккаунты на коше

 import {
  Connection,
  transferChecked,
  PublicKey,
  Keypair
} from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { mnemonicToSeedSync } from 'bip39'; 

(async () => {
  const connection = new Connection(
    "https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2",
    "confirmed"
  );

  const mnemonic = 'ruburi dao ebashit'; // тут твоя мнемоника окда
  const seed = mnemonicToSeedSync(mnemonic);
  // keypair откуда отправляем нфт
  const owner = Keypair.fromSeed(seed.subarray(0, 32));
  const fromTokenAccount = new PublicKey('lolkek');
  const mintAddress = 'sosopaviashvilidao'
  const toTokenAccount = newPublicKey('scammer');
  const amount = 1, decimals = 1;
  
  const txHash = await transferChecked(
    connection, // наш коннкешен
    owner, // keypair кто платит комсу
    fromTokenAccount, // publicKey адреса токен аккаунта откуда отправляем
    mintAddress, // publicKey минт адреса отправляемого токена
    toTokenAccount, // publicKey адреса токен аккаунта куда отправляем
    owner, // keypair кошеля овнера токена
    amount, // количество токенов
    decimals // числа после запятых (можно получить в инфе из tokenAccounts)
  );
})();

создаем токен аккаунт если у коша его нет

import { ..., PublicKey, createAssociatedTokenAccount } from '@solana/web3.js';

(async () => {
  ...code
  
  const mint = new PublicKey('bulshitmintaddress');
  const ata = await createAssociatedTokenAccount(
    connection, // наш коннекшен
    feePayer, // keypair кто платит комсу
    mint, // publicKey (!) минт адреса
    owner.publicKey // publicKey (!) владельца нового токен аккаунта
  );
  console.log(ata.toBase58()); // выводим адрес нового токен аккаунта
})();

адрес нового токен аккаунта как раз таки и будет нужен тебе для отправки нужного токена, только не запутайся где publicKey а где keypair!

как преобразовать адрес в publicKey адреса

напомню тебе

new PublicKey('ADDRESS')

и не забудь импортировать нужные методы из модулей


заключение

вот в принципе все шо я хотел тебе сегодня рассказать и показать о солане на javascript!

скоро будет статья также по солане как создавать свой токен и минтить его, сжигать, как создавать candy machine, как туда вносить свои нфт и как минтить нфт через candy machine id. в общем будет оч оч гемно нахуй

я буду еще писать о концептах js более подробно и емко, так что подписывайся на рубури дао!

можешь не беспокоиться если чето не запомнилось, это нормально. не отступай и иди к цели. когда я учился я хотел бросить люто масштабно два раза... но не останавливался пон!!!!! я не остановился и ща работаю дворничком (шутка конечно мужики я во вкусно и точка)

ебашьте и все будет ахуенно

мотивация от рубури дао как всегда

благодарности

спасибо тебе за прочтение, спасибо тем кто ставит реакции, подпищекам, рыжему, сс ресерч, моей девочке, френдли тагу 52 нгг и всем остальным кто пон мотивирует ебашить люто жоска

и удачи тебе в пути кодинга еба!

отзыв

если в каком то примере ошибка, или что то не получается вы всегда можете обратиться за вопросом в телегу к рубурику @rubyuroboros


мой канал — https://t.me/ruburi

это ты чисто и я (рубурик давольный) после того как ты начал жоска воркать в веб3