Понимание методов и ошибок MetaMask RPC

Понимание методов и ошибок MetaMask RPC

Содержание
  1. Что такое RPC?
  2. Вызов функции
  3. Заключение

MetaMask - это популярный криптовалютный кошелек, который отправляет, получает и подписывает транзакции на блокчейне. Это предпочтительный криптовалютный кошелек, используемый web3-разработчиками, благодаря его гибкости, передовым и инновационным функциям.

Как разработчик, работающий с MetaMask и его RPC, вы, должно быть, уже заметили, что перехват ошибок MetaMask невозможен с помощью блока try-and-catch. Ситуация может расстроить, особенно когда вы можете четко увидеть ошибку в консоли браузера.

Прежде чем перейти к отлову этих ошибок, мы должны понять, что такое RPC и как MetaMask использует его для своих методов.

Что такое RPC?

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

В случае с web3 RPC позволяет приложению получать доступ к данным блокчейна, создавать транзакции и взаимодействовать с функциями смарт-контракта через серверный узел. Такие кошельки, как MetaMask, имеют встроенный RPC, известный как JSON-RPC. Он является промежуточным звеном между внешними приложениями и функциями смарт-контракта. Этот тип RPC представляет собой нестационарный и легкий протокол, используемый для агностической передачи данных через WebSockets или HTTP.

Когда пользователи загружают расширение MetaMask, кошелек внедряет объект Ethereum в окно браузера (window.ethereum). Объект содержит все RPC-методы MetaMask, а именно isConnected, on и request.

ethereum.isConnected: Этот метод проверяет состояние соединения между сервером узла MetaMask и блокчейном. Он возвращает булево значение. Если он возвращает true, то сервер узла может делать RPC-запросы к Ethereum или другой цепочке, совместимой с Ethereum Virtual Machine (EVM).

ethereum.on: Metamask реализует API эмиттера событий Node.js в этом методе для отслеживания событий блокчейна, изменений цепочки и учетных записей пользователей. Метод использует аргументы, содержащие название события, которое нужно отследить, и функцию, содержащую то, что делает ваше React-приложение, когда происходит событие. Некоторые из событий MetaMask по умолчанию - “accountsChanged”:

window.ethereum.on('accountsChanged',(accounts)=>{ console.log("You switched your account to: ", accounts[0]) })

И “chainChanged”:

window.ethereum.on('chainChanged',(chains) => { console.log("You switched chains to: ", chains[0]) })

ethereum.request: Этот метод содержит RPC API MetaMask и открывает вызывающему его пользователю доступ к внешним методам сервера узла, подключенного к MetaMask. Он принимает один JSON-объект, содержащий внешний метод для вызова и его параметры (params).

window.ethereum.request({
	method: 'eth_sendTransaction',
	params: [
		{
			from: '0x21ab...', //sender address
			to: '0x1432ba...', //receiver address
			gas: '0x5208', //hex representation of 21000
			gasPrice: '0x9184e72a000', // hex of 1e13 wei
			value: '0xDE0B6B3A7640000', // hex for 1e18 wei or 1 Ether
		},
	],
});

Вызов функции

Вызов функции смарт-контракта может быть осуществлен с помощью одного из RPC-методов MetaMask. Однако лучшим способом вызова функций и установления соединения с кошельком MetaMask и другими кошельками является использование пакетов библиотек web3, таких как web3modal и ether.js. Чтобы установить эти пакеты, выполните следующую команду в терминале:

npm install --save web3modal ethers

Мы будем вызывать функцию из базового смарт-контракта erc20 под названием “approve”. Эта функция смарт-контракта позволяет нам дать стороннему адресу разрешение на использование токенов erc20 от нашего имени. Но сначала давайте разберемся с ABI. Application Binary Interface (ABI) - это стандартный способ взаимодействия со смарт-контрактами в сети Ethereum.

ABI для функции “approve” выглядит как function approve(address _spender, uint256 _value) public returns (bool success).

Теперь, когда у нас есть ABI, мы можем легко вызвать функцию с помощью установленных зависимостей web3modal и ethers.

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

import Web3Modal from "web3modal";
import { ethers } from "ethers";

export const Approve = () => {
  const abi = [
    "function approve(address _spender, uint256 value) public returns (bool success)",
  ];
  const usdtAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7";
  const thirdPartyAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7";
  const web3Modal =
    typeof window !== "undefined" && new Web3Modal({ cacheProvider: true });

  async function handleApproveSubmit() {
    const connection = web3Modal && (await web3Modal.connect());
    const provider = new ethers.providers.Web3Provider(connection);
    const contract = new ethers.Contract(usdtAddress, abi, provider.getSigner());
    contract.approve(thirdPartyAddress, 20);
  }

  return <button onClick={handleApproveSubmit}>Approve</button>;
};

The handleApproveSubmit() function will open up MetaMask with a transaction to be signed.

Функция handleApproveSubmit() откроет MetaMask с транзакцией, которую нужно подписать.

Блока try-and-catch достаточно, чтобы перехватить все ошибки, возникающие при вызове функции смарт-контракта.

try {
	const connection = web3Modal && (await web3Modal.connect());
	const provider = new ethers.providers.Web3Provider(connection);
	const contract = new ethers.Contract(usdtAddress, abi, provider.getSigner());
	contract.approve(thirdPartyAddress, 20);
} catch (error) {
	console.log(error.message);
}

Однако он не может обнаружить ошибки в RPC MetaMask.

Чтобы отловить ошибки MetaMask, нужно добавить обещание после вызова функции. Это обещание ожидает хэш транзакции, которая будет транслироваться в блокчейн. Если транзакция транслируется успешно, выводим в консоль сообщение об успехе и хэш транзакции, если нет - выводим ошибку.

contract
	.approve(thirdPartyAddress, 20)
	.then((tx) => {
		return provider.waitForTransaction(tx.hash);
	})
	.then(() => {
		console.log('success');
		console.log(tx.hash);
	})
	.catch((error) => {
		console.log(error.message);
	});

Такой подход позволяет отловить все возможные ошибки RPC MetaMask, включая 4001: “User Denied Transaction Signature”.

Заключение

С помощью подхода, описанного в этой статье, вы сможете более эффективно обрабатывать ошибки MetaMask в своем React-приложении. Этот подход также применим к другим кошелькам с аналогичными RPC, таким как TrustWallet, Exodus или MyEtherWallet(MEW).