- Регистрация
- 12.06.2018
- Сообщения
- 1 344
- Благодарностей
- 910
- Баллы
- 113
Для доступа к блокчейну рядовой пользователь использует плагин для браузера 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);
В результате получаем хэш нашей транзакции - 0xb5a35a7105e3d83874a8671f330d7d38208c84bd0efe126fe8c2160b4db15ebd, детали которой можно посмотреть в обозревателе блоков BscScan.
После этого можно узнать баланс нашего кошелька:
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;
}
}
Rinkeby Transaction Hash (Txhash) Details | Etherscan
Rinkeby (ETH) detailed transaction info for txhash 0x7db471e5792bbf38dc784a5b983ee6a7bbe3f1db85dd4daede9ee88ed88057a5. The transaction status, block confirmation, gas fee, Ether (ETH), and token transfer are shown.
rinkeby.etherscan.io
Данные (всего 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();
Т.к. никаких входящих данных нет, то эти самые данные будут состоять только из хэша сигнатуры метода:
data = 0xd46300fd
и на выходе получим ожидаемый результат 0x0000000000000000000000000000000000000000000000000000000000000001
2.1 Read Contract.
Теперь можно применить полученные знания на практике для реальных контрактов.
Возьмём контракт 0x23567C7299702018B133ad63cE28685788ff3f67 и будем взаимодействовать с функцией "offers". Этот же запрос можно сделать в обозревателе блоков BscScan, но для автоматизации он не подходит в силу ограничения по количеству запросов.
Данная функция принимает единственное значение id, и возвращает информацию по NFT:
Сделаем всё то же самое из кода. Для сопоставления типов данных нам нужен ABI данного контракта, берём его из обозревателя блоков для данного контракта в подразделе "Code":
Метод чтения контракта будет выглядеть слудующим образом:
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;
}
Код:
0x0000000000000000000000000000000000000000000000000000000000013548000000000000000000000000000000000000000000000002aef353bcddd60000000000000000000000000000965f527d9159dce6288a2219db51fc6eef120dd1000000000000000000000000d4220b0b196824c2f548a34c47d81737b0f6b5d6000000000000000000000000d87e639772276daa89a2c85f5bdd29021e72b1f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000
Код:
[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]
Код:
tokenId: 79176
price: 49500000000000000000
dealToken: 0x965F527D9159dCe6288a2219DB51fc6Eef120dD1
nft: 0xD4220B0B196824C2F548a34C47D81737b0F6B5D6
user: 0xd87e639772276dAa89A2c85F5bdD29021e72b1F2
acceptUser: 0x0000000000000000000000000000000000000000
status: 2
side: 0
2.2 Write Contract.
Напишем взаимодействие с функцией обмена токенов Pancakeswap. Для начала нам нужно собрать все необходимые для этого данные. Вручную инициируем обмен WBNB на BUSD. Во всплывающем окне метамаска скопируем адрес контракта, название функции и шестнадцатеричные данные:
Адрес контракта: 0x10ED43C718714eb63d5aA57B78B54704E256024E
Функция: SwapExactTokensForTokens
Параметры:
"amountIn": "uint256" - количество токена, который отдаем
"amountOutMin": "uint256" - на бирже задается в процентах, передается в виде минимального количества токенов, которые мы согласны получить
"path": "address[]" - адреса двух наших токенов (плюс тут ещё указаны промежуточные)
"to": "address" - наш кошелёк
"deadline": "uint256" - время выполнения
Шестрадцатеричные данные:
Код:
0x38ed173900000000000000000000000000000000000000000000000000a2d46a79ab0800000000000000000000000000000000000000000000000000bd07c2735b4f74db00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000075d68823ec5ad0b7e135960d7f8a23a400000000000000000000000000000000000000000000000000000000627ed3ee0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000023396cf899ca06c4472205fc903bdb4de249d6fc000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d56
Рассмотрим передаваемые данные, разбив их на куски по 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,8 МБ Просмотры: 529
Для запуска проектов требуется программа ZennoPoster или ZennoDroid.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...
Для того чтобы запустить шаблон, откройте нужную программу. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.