2 место Работаем с блокчейном напрямую

Jufel

Client
Регистрация
12.06.2018
Сообщения
1 568
Реакции
1 094
Баллы
113
bc.png


Для доступа к блокчейну рядовой пользователь использует плагин для браузера Metamask, который делает следующие вещи:
• Обеспечивает подключение к нужной сети через свой удаленный узел.
• Позволяет создавать новые или импортировать существующие аккаунты для работы с блокчейном. Это дает возможность подписывать транзакции приватным ключом, который хранится локально у пользователя.

Использовать Metamask достаточно удобно, однако при попытке автоматизации с помощью ZennoPoster возникают дополнительные сложности - приходится взаимодействовать с браузерным плагином, что накладывает некоторые ограничения.
Исключим из нашей цепочки Metamask и будем работать напрямую с блокчейном с помощью Nethereum – удобной библиотеки для взаимодействия с блокчейном и смарт-контрактами. Таким образом повышается масштабируемость действий и скорость их выполнения.

В данной статье рассмотрим сеть Binance Smart Chain (BSC), которая поддерживает смарт-контракты и совместима с виртуальной машиной Ethereum (EVM), а соответственно поддерживает инструменты Ethereum и DApps.

1. Транзакции.
Транзакция — операция сохранения данных в блокчейне, в ходе которой происходит передача криптоактивов или другой информации между кошельками. Отправка транзакции происходит после её создания в кошельке и подписания цифровой подписью на основе закрытого ключа. Транзакция похожа на HTTP запрос. Сервер принимает этот запрос и вносит изменения в базу данных, которой по сути является блокчейн. Транзакция принимается сетью и цепочка блоков расширяется включёнными изменениями.

Для работы с конкретной сетью (в данном случае BSC) необходимы данные этой сети - адрес RPC сервера и Chain ID, а так же приватный ключ нашего кошелька.

BSC Mainnet:
Chain Id: 56
Json Rpc: https://bsc-dataseed.binance.org/


Для Testnet данные следующие:
Chain Id: 97
Json Rpc: https://data-seed-prebsc-1-s1.binance.org:8545/


Напишем код для транзакции в Testnet:
C#:
Развернуть Свернуть Копировать
int binanceTestnetChainId = 97;
string binanceTestnetJsonRpc = "https://data-seed-prebsc-1-s1.binance.org:8545/";
string walletKey = "01388939eaae42aad053c8db7ffe320e7c9c182de72b8f89f9822125dff5496a";
string addressTo = "0x000000000000000000000000000000000000dEaD";    // адрес получателя
string data = "0x";
decimal amount = 0.001;
string hash = string.Empty;

var account = new Account(walletKey, binanceTestnetChainId);
var web3 = new Web3(account, binanceTestnetJsonRpc);
web3.TransactionManager.UseLegacyAsDefault = true;

var transaction = new TransactionInput();
transaction.From = account.Address;
transaction.To = addressTo;
transaction.Data = data;
transaction.Value = Web3.Convert.ToWei(amount).ToHexBigInteger();
transaction.Gas = await web3.TransactionManager.EstimateGasAsync(transaction);

var hash = await web3.TransactionManager.SendTransactionAsync(transaction);
Данные по умолчанию для этой транзакции имеют значение "0x". Работа с данными будет рассмотрена чуть позже. Газ рассчитывается автоматически, но при необходимости его можно указывать вручную.
В результате получаем хэш нашей транзакции - 0xb5a35a7105e3d83874a8671f330d7d38208c84bd0efe126fe8c2160b4db15ebd, детали которой можно посмотреть в обозревателе блоков BscScan.
bscscan.png


После этого можно узнать баланс нашего кошелька:
C#:
Развернуть Свернуть Копировать
public async Task GetBnbTestnetAccountBalance()
{
    var account = new Account(walletKey, binanceTestnetChainId);
    var web3 = new Web3(account, binanceTestnetJsonRpc);

    var balance = await web3.Eth.GetBalance.SendRequestAsync("0x483879d01E943a404B97240D9Aa8B5b94E1a7C0B");
}

2. Работа со смарт-контрактами.

Смарт-контракты - это алгоритм определенных действий, интегрированный в код блокчейна. При соблюдении установленных договоренностей, которые в нем прописаны, выполняется автоматический запуск последовательности. Являются посредником между данными и внешним миром. Посредством HTTP RPC вызываются методы смарт-контракта и изменяется его состояние. Транзакции относятся к смарт-контрактам так же, как HTTP запросы к вёб серверу. Код смарт контракта исполняется на стековой витруальной машине Ethereum Virtual Machine (EVM). Смарт-контракт запускается путем компиляции в байт-код EVM. Код Solidity должен быть скомпилирован в байт-код перед развертыванием в сети Ethereum. Этот байт-код соответствует серии инструкций кода операции, которые интерпретирует EVM. EVM использует архитектуру на основе стека. Размер элемента данных в стеке составляет 32 байта (или 256 бит).
Соответственно мы будем манипулировать блоками размером в 32 байта.

Рассмотрим простой контракт:
Код:
Развернуть Свернуть Копировать
contract C {
  uint256 a;
  function setA(uint256 _a) {
    a = _a;
  }
  function getA() returns(uint256) {
    return a;
  }
}

Создадим транзакцию вызывающую метод setA(1) этого контракта:

Данные (всего 36 байт), переданные в транзакции следующие:
0xee919d500000000000000000000000000000000000000000000000000000000000000001

Смарт-контракт интерпретирует этот набор байт, как вызов метода и выполнит код для setA(1).
Эти данные можно разбить на 2 части:
первые 4 байта это селектор метода - 0xee919d5
оставшиеся данные это аргумент метода длинной в 32 байта - 00000000000000000000000000000000000000000000000000000000000000001
Селектор метода это kecccak256 хэш сигнатуры метода setA(uint256)

Смарт-контракт вызывает методы, обрабатывая входные данные структурируемым способом, для чего используется ABI (Application Binary Interface) - данные кодируются в соответствии с их типом, описанным в этой спецификации. ABI в нашем случае нужен, чтобы преобразовывать входные и выходные данные к нужному типу.
Если вызываемый метод меняет состояние блокчейна, он будет выполняться как транзакция и соответственно будет израсходован газ. Однако, если метод только получает информацию и ничего не изменяет то такой запрос (eth_call) будет выполнен бесплатно. Eth_call похож на HTTP GET запрос, который не изменяет состояние, а просто получает данные. В примере выше это метод getA().
Таким образом существует 2 способа взаимодействия с контрактами - Read и Write.
В обозревателе блоков BscScan можно увидеть все функции контракта, с принимаемыми и возвращаемыми значениями, разделённые по типу, правда только для проверенных контрактов.
Сделаем вызов этого метода. Для начала необходимо рассчитать селектор метода getA(). Как я писал выше, это будет kecccak256 хэш "getA()".
Для удобства можно сделать это опять же с использованием Nethereum:
C#:
Развернуть Свернуть Копировать
var deserialize = new ABIJsonDeserialiser();
var abiFunctions = deserialize.DeserialiseContract(abi).Functions;
var hash = abiFunctions.Where(n => n.Name == functionName)
    .Select(f => f.Sha3Signature).First();
В результате получим d46300fd
Т.к. никаких входящих данных нет, то эти самые данные будут состоять только из хэша сигнатуры метода:
data = 0xd46300fd
и на выходе получим ожидаемый результат 0x0000000000000000000000000000000000000000000000000000000000000001

2.1 Read Contract.
Теперь можно применить полученные знания на практике для реальных контрактов.
Возьмём контракт 0x23567C7299702018B133ad63cE28685788ff3f67 и будем взаимодействовать с функцией "offers". Этот же запрос можно сделать в обозревателе блоков BscScan, но для автоматизации он не подходит в силу ограничения по количеству запросов.
Данная функция принимает единственное значение id, и возвращает информацию по NFT:
91751


Сделаем всё то же самое из кода. Для сопоставления типов данных нам нужен ABI данного контракта, берём его из обозревателя блоков для данного контракта в подразделе "Code":

91752


Метод чтения контракта будет выглядеть слудующим образом:
C#:
Развернуть Свернуть Копировать
public async Task<string> ReadContract(string contractAddress, string abi, string functionName, int parameter)
{
    var web3 = new Web3(jsonRpc);
    web3.TransactionManager.UseLegacyAsDefault = true;

    var contract = web3.Eth.GetContract(abi, contractAddress);
    var function = contract.GetFunction(functionName);

    string param = parameter.ToString("X");

    var data = function.GetData(param);
    var call = new CallInput(data, contractAddress);
    var result = await function.CallAsync(call);

    return result;
}

Передаём параметры (адрес контракта, abi, имя функции, параметр). Функция возвращает набор байт, которые необходимо преобразовать в нужный тип данных:
Код:
Развернуть Свернуть Копировать
0x0000000000000000000000000000000000000000000000000000000000013548000000000000000000000000000000000000000000000002aef353bcddd60000000000000000000000000000965f527d9159dce6288a2219db51fc6eef120dd1000000000000000000000000d4220b0b196824c2f548a34c47d81737b0f6b5d6000000000000000000000000d87e639772276daa89a2c85f5bdd29021e72b1f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000

Как мы уже знаем, данные представлены в блоках по 32 байта, для наглядности разобьём их по этим блокам и пропишем соответствие типам в порядке следования:
Код:
Развернуть Свернуть Копировать
[0]: 0000000000000000000000000000000000000000000000000000000000013548    tokenId [uint256]
[1]: 000000000000000000000000000000000000000000000002aef353bcddd60000    price [uint256]
[2]: 000000000000000000000000965f527d9159dce6288a2219db51fc6eef120dd1    dealToken [address]
[3]: 000000000000000000000000d4220b0b196824c2f548a34c47d81737b0f6b5d6    nft [address]
[4]: 000000000000000000000000d87e639772276daa89a2c85f5bdd29021e72b1f2    user [address]
[5]: 0000000000000000000000000000000000000000000000000000000000000000    acceptUser [address]
[6]: 0000000000000000000000000000000000000000000000000000000000000002    status [uint8]
[7]: 0000000000000000000000000000000000000000000000000000000000000000    side [uint8]

После преобразования из Hex в Dec получаем нужные данные:
Код:
Развернуть Свернуть Копировать
tokenId: 79176
price: 49500000000000000000
dealToken: 0x965F527D9159dCe6288a2219DB51fc6Eef120dD1
nft: 0xD4220B0B196824C2F548a34C47D81737b0F6B5D6
user: 0xd87e639772276dAa89A2c85F5bdD29021e72b1F2
acceptUser: 0x0000000000000000000000000000000000000000
status: 2
side: 0

2.2 Write Contract.
Напишем взаимодействие с функцией обмена токенов Pancakeswap. Для начала нам нужно собрать все необходимые для этого данные. Вручную инициируем обмен WBNB на BUSD. Во всплывающем окне метамаска скопируем адрес контракта, название функции и шестнадцатеричные данные:
91753

91754

91755


Адрес контракта: 0x10ED43C718714eb63d5aA57B78B54704E256024E
Функция: SwapExactTokensForTokens
Параметры:
"amountIn": "uint256" - количество токена, который отдаем
"amountOutMin": "uint256" - на бирже задается в процентах, передается в виде минимального количества токенов, которые мы согласны получить
"path": "address[]" - адреса двух наших токенов (плюс тут ещё указаны промежуточные)
"to": "address" - наш кошелёк
"deadline": "uint256" - время выполнения
Шестрадцатеричные данные:
Код:
Развернуть Свернуть Копировать
0x38ed173900000000000000000000000000000000000000000000000000a2d46a79ab0800000000000000000000000000000000000000000000000000bd07c2735b4f74db00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000075d68823ec5ad0b7e135960d7f8a23a400000000000000000000000000000000000000000000000000000000627ed3ee0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000023396cf899ca06c4472205fc903bdb4de249d6fc000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d56

Проверяем на bscscan - есть такое:
91756


Рассмотрим передаваемые данные, разбив их на куски по 32 байта, причём первые 4 байта это селектор функции, к которой необходимо обратиться.
Код:
Развернуть Свернуть Копировать
MethodID: 0x38ed1739
[0]: 00000000000000000000000000000000000000000000000000a2d46a79ab0800    amountIn
[1]: 000000000000000000000000000000000000000000000000bd07c2735b4f74db    amountOutMin
[2]: 00000000000000000000000000000000000000000000000000000000000000a0    path - адрес начала массива (5ая строка)
[3]: 0000000000000000000000000000000075d68823ec5ad0b7e135960d7f8a23a4    to
[4]: 00000000000000000000000000000000000000000000000000000000627ed3ee    deadline (unixtime)
[5]: 0000000000000000000000000000000000000000000000000000000000000004    начало массива пути к токенам (кол-во элементов)
[6]: 000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c    path1 - адрес токена WBNB
[7]: 0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d    path2 - адрес токена USDC
[8]: 00000000000000000000000023396cf899ca06c4472205fc903bdb4de249d6fc    path3 - адрес токена UST
[9]: 000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d56    path4 - адрес токена BUSD

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

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



Мною были опущены некоторые самые базовые понятия при работе с блокчейном, например то, что касается газа. Надеюсь, что полученная информация поможет в реализации и автоматизации ваших проектов.
В приложении находятся 3 шаблона, в которых реализованы вышеописанные действия по транзакциям, чтению и записи контрактов. В папке dll находятся библиотеки, которые необходимо переместить в ExternalAssemblies вашей версии ZennoPoster.
 
Номер конкурса статей
  1. Семнадцатый конкурс статей
Тема статьи
  1. Другое

Вложения

Просто шикарно.:ay:
Для удобного взаимодействия со смарт контрактами - самое то!
На сколько знаю, эту тему, еще не освещали на форуме - по крайней мере я не видел, когда это было остро необходимо!
 
  • Спасибо
Реакции: Jufel
Благодарочка, очень полезная статья, правда тяжеловата пока что, еще бы кто описал на примере, как это все работает с расшифровкой HEX, и даже лучше прям шаблончик где обменивается одна монетка на другую, нужно ли импортировать монету как в метамаске или все уже есть, и dll безопасны ли для работы?А то дело такое, денежное.
 
  • Спасибо
Реакции: Jufel
+ репу, про крипту и смартконтракты интересно:ay:
 
  • Спасибо
Реакции: Jufel
А где это можно использовать?
Есть простые примеры?
 
  • Спасибо
Реакции: Gor и AleXPrischepA
Не хрена не понял от слова совсем, читал читал, видимо по тому что не занимаюсь этим, но всем нам удачи и успехов)
 
Не хрена не понял от слова совсем, читал читал, видимо по тому что не занимаюсь этим, но всем нам удачи и успехов)
вот тоже сидел читал и не слова не понял в статье.Что это дает, для чего это нужно. Видимо статья написано для тех кто в теме.
 
  • Спасибо
Реакции: Gor
Насколько я понял, можно принимать платежи от пользователей, проверяя по блокчейну сумму, баланс и номер транзакции=перевода, также можно обменивать одну криптовалюту на другу, аналогично обменникам, нужно только более подробно, чтоб кто то расписал и показал на шаблона, тут достаточно все непросто написано. В любом случае начали появляться такие нужные статьи и это радует, как только народ поймет как внедрять в шаблоны данную технологи, бабло потечет рекой, причем почти анонимно. Также кто занимается аирдропами или сборами балансов массово с пачки кошельков тоже поможет.
 
в двух словах - работу с расширением метамаск, в зенке это полностью заменит? У кого то метамаск стабильно на зенке крутится? Спасибо!
 
Нужен перевод для чайников.)
 
Автор молодец. Очень ждал материала по взаимодействию с блокчейном. Пиши еще!
 
  • Спасибо
Реакции: Jufel, Roman* и tanichev
в двух словах - работу с расширением метамаск, в зенке это полностью заменит? У кого то метамаск стабильно на зенке крутится? Спасибо!
Метамаск это всего лишь удобная оболочка, под капотом у которой крутится примерно такой же код. Это конечно грубо сказано, но смысл такой.

еще бы кто описал на примере, как это все работает с расшифровкой HEX, и даже лучше прям шаблончик где обменивается одна монетка на другую, нужно ли импортировать монету как в метамаске или все уже есть, и dll безопасны ли для работы?.
Расшифровать HEX можно хоть вручную, но для этого есть удобные методы в nethereum библиотеках. Насколько я знаю, nethereum это единственное решение для C# для работы с блокчейном. Шаблончик по обмену WBNB на BUSD приложен
 
Сейчас такое время, все про крипту говорят/пишут и т.п. А тут сразу практическое применение. Спасибо за инфу.
 
  • Спасибо
Реакции: Jufel
Отличный материал! Благодарю!
 
  • Спасибо
Реакции: Jufel
Очень интересный материал, знаю что у некоторых была проблема в автоматизации как раз из-за подключения метамаска, тут она решается. Спасибо.
 
  • Спасибо
Реакции: Jufel
Интересно но ничего не понятно :( как и где можно использовать?
 
Интересно но ничего не понятно :( как и где можно использовать?
Можно использовать для автоматизации транзакций и работой со смарт-контрактами. Кто в теме, думаю найдут применение для подобных задач.
 
нужно было дать определение на "пальцах" блокчейна) это не все понимают, а статья посвящена блокчейну. Ты начинаешь сразу с транзакций... можно было в начале статьи предоставить тезаурус, словарик, где основные термины проговорены.
 
нужно было дать определение на "пальцах" блокчейна) это не все понимают, а статья посвящена блокчейну. Ты начинаешь сразу с транзакций... можно было в начале статьи предоставить тезаурус, словарик, где основные термины проговорены.
А для чего пользователю, который не знает, что такое блокчейн - данная статья? Не зная блокчейн, все что сказано в сказано выше - пустой шум. Вытекает одно из другого.
Или Вы хотите сказать, когда автор рассказывает, как работает трансмиссия в автомобиле, он обязан рассказать обо всем автомобиле?
Современный мир, информации для само-обучения и познания, более чем достаточно.
 
  • Спасибо
Реакции: DDDmoney и lamar015
дело не только в этом... по условию конкурса статья должна содержать "... предисловие. Кратко изложено, о чем пойдет речь в статье, кому будет полезно, какие инструменты понадобятся для реализации. " . Статья не должна отпугивать обилием сложных терминов потенциальных клиентов зеннки, максимальная доступность темы без потери смысла. Даже, если ты @Tfzimakin академик, то и тебе будет проще читать такую статью. Это же логика и не нужно создавать искусственных барьеров для понимания. Как можно говорить блокчейне и при этом ни слова не сказав о том, что это такое???
 
Автору спасибо, материал отличный.
 
  • Спасибо
Реакции: Jufel
дело не только в этом... по условию конкурса статья должна содержать "... предисловие. Кратко изложено, о чем пойдет речь в статье, кому будет полезно, какие инструменты понадобятся для реализации. " . Статья не должна отпугивать обилием сложных терминов потенциальных клиентов зеннки, максимальная доступность темы без потери смысла. Даже, если ты @Tfzimakin академик, то и тебе будет проще читать такую статью. Это же логика и не нужно создавать искусственных барьеров для понимания. Как можно говорить блокчейне и при этом ни слова не сказав о том, что это такое???

Гугл-яндекс в помощь по изучению.

Всё отлично изложено! Разжевывание базовых понятий по крипте займет больше обьем чем статья.
 
  • Спасибо
Реакции: edger, VanaDefele и Jufel

Кто просматривает тему: (Всего: 0, Пользователи: 0, Гости: 0)