Пост

Подпись ETH транзакций в PHP

Подпись ETH транзакций в PHP

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

Подготовка

Мы будем работать в тестнете Sepolia, поэтому это нужно явно указать в коде:

1
2
$node = new SWeb3('https://eth.public-rpc.com');
$node->chainId = 0xaa36a7; // Sepolia network

Узнать id сети можно здесь.

Далее прописываем свой адрес и приватный ключ (будет использоваться для подписи транзакции):

1
2
3
4
$node->setPersonalData(
    '0x7e2f443930Ad42609b29efeFef7E132d9022DFBc', 
    'your-private-key-value',
);

Параметры транзакции

Итак, начнем по порядку. Что нам нужно знать, чтобы создать транзакцию? Адрес отправителя и получателя у нас есть. Value - количество ETH, которое хотим отправить тоже знаем. Что такое nonce и gas?

Nonce

Nonce - это индекс транзакции на адресе, с которого мы отправляем транзакции (как и любой индекс начинается с нуля). Этот механизм нужен для предотвращения атаки double spend - когда мы одновременно отправляем 2 транзакции и пытаемся использовать сумму, которая у нас есть дважды. С каждой транзакцией нужно отправить nonce и дальше блокчейн нода уже провалидирует его.

1
$nonce = $node->personal->getNonce();

Чтобы получить nonce можно запросить у ноды кол-во транзакций с нашего адреса eth_getTransactionCount. По сути это количество и будет равно nonce.

1
2
3
4
$nonce = $node->call(
  'eth_getTransactionCount',
  [$node->personal->address, 'pending']
)->result,

Value

Value - это сколько мы хотим передать Eth. Важно помнить, что всё передается в 16-ой системе. Плюс число указывается в минимальном номинале. Для Эфира это 1 Wei = 0,000000000000000001 Eth.

Wei — это минимальный номинал в блокчейне Ethereum. 1 Wei = 0,000000000000000001 Eth.

Мы будем отправлять 0.0001 Eth, что будет равно 100000000000000 Wei:

1
$value = Utils::toWei('0.0001', 'ether'); // 100000000000000 Wei

Gas

Что такое Gas? В блокчейне Ethereum каждая операция имеют свою вычислительную цену. Например, сохранить данные в блокчейн - дороже всего, изменить - дешевле, прочитать - вообще бесплатно. И вот эта стоимость операции измеряется в своих единицах, называемых gas. Gas также имеет свою стоимость в Eth, и здесь, когда мы указываем gas, мы говорим сколько максимум газа мы готовы потратить, или за сколько максимум газа мы готовы заплатить.

Gas — это единица измерения количества вычислительных ресурсов, необходимых для выполнения определенных операций в блокчейне.

Считаем сколько gas-а потребуется для выполнения нашей транзакции:

1
2
3
4
5
6
$sendParams = [
    'from' => $node->personal->address,
    'to' => $addressTo,
    'value' => Utils::toWei('0.0001', 'ether'),
];
$gas =  Utils::hexToBn($node->call('eth_estimateGas', [$sendParams])->result);

Для это вызываем у ноды метод eth_estimateGas и передаем параметры нашей будущей транзакции: адрес отправителя, адрес получателя и сколько мы планируем отправить.

На самом деле цена перевода эфира фиксирована и равна 21000 газа, поэтому для простых переводов Eth на EOA адрес вызывать eth_estimateGas не обязательно.

Все числа в ответе от ноды мы будем получать в 16-ой системе. Поэтому используем хелпер Utils::hexToBn() для конвертации hex числа в BigInteger.

Отправка в блокчейн

Сейчас у нас есть всё необходимое для создания и отправки транзакции в блокчейн:

1
2
3
4
5
6
7
8
9
$transaction = [
    'from' => $node->personal->address,
    'to' => $addressTo,
    'value' => $node->utils->toWei('0.0001', 'ether'),
    'nonce' => $nonce,
    'gasLimit' => $gas, 
];

$hash = $node->send($sendParams)->result;

Под капотом при вызове $node->send(...) будет транзакция будет подписана нашим приватным ключом (будет получен hex транзакции). А затем транзакция будет забродкащена на ноду (будет вызван json-rpc метод eth_sendRawTransaction). В результате мы получим хэш транзакции, с которым можно пойти в эксплорер и найти её на блокчейне.

Где взять ETH в тестнете? Есть несколько faucet-ов, где можно получить бесплатно несколько ETH. Например, от Google или от Automata.