Часть 2 - Подключение смарт-контракта к GraphQL

Вы можете найти часть 1 этого руководства здесь.

В этой части мы создадим сервер Express для нашего GraphQL API и подключим его к нашему смарт-контракту с помощью Web3 😎.

Настройка тестовых учетных записей

Перед настройкой нашего сервера установите ganache-cli и расширение для браузера Metamask.

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

Нам нужно расширение Metamask, потому что оно позволяет запускать приложения Ethereum dApps в обычном веб-браузере, а также действует как безопасное хранилище идентификационных данных.

Запустите команду ganache-cli, чтобы сгенерировать несколько тестовых учетных записей и скопируйте данную нам фразу «Мнемоника» в терминал.

Теперь щелкните значок Metamask в своем браузере и подключите расширение Metamask к сети Localhost 8545.

Затем выберите «восстановить из исходной фразы», ​​вставьте фразу, которую вы скопировали с терминала, и создайте новый пароль.

Если все пойдет хорошо, мы увидим, что у нас есть 100 эфиров, которые мы можем потратить!

Затем мы подключим Remix IDE, которую мы будем использовать для написания и тестирования нашего смарт-контракта, с Metamask, выбрав параметр Injected Web3 на вкладке RUN.

Чтобы развернуть разработанный контракт, добавьте строку приза и нажмите «Развернуть».

Настройка GraphQL API

Теперь мы создадим базовый сервер GraphQL с помощью Apollo. Давайте начнем. Создайте новый каталог для своего проекта и запустите в нем npm init -y.

Теперь мы настроим базовую файловую структуру нашего сервера GraphQL. Создайте папки и файлы, как показано на изображении ниже:

donationContract.js - это место, где будет жить JavaScript-версия нашего скомпилированного смарт-контракта. Внутри этого файла нам понадобятся две части информации из Remix: адрес развернутого контракта в тестовой цепочке блоков и нечто, называемое ABI.

Что такое ABI? Узнайте больше здесь.

Окончательный файл будет выглядеть примерно так:

const contractAddress = "0xd0a6E6C54DbC68Db5db3A091B171A77407Ff7ccf"
const contractABI = [{
    // Your ABI here...
}]

Теперь, когда у нас есть адрес нашего недавно развернутого смарт-контракта Ethereum, нам нужен способ взаимодействия с ним нашего приложения JavaScript. К счастью, для этого у нас есть библиотека web.js! Установите web3.js, запустив:

npm install --save-dev web3

Откройте getContract.js файл в src/contract и добавьте этот код:

const Web3 = require("web3");
// Importing contract details
const {address, ABI} = require("../../constants/donationContract");
const getWeb3 = () => {
  return (web3 = new Web3(
    new Web3.providers.HttpProvider("http://localhost:8545") 
  ));
};
const getContract = new Promise(function(resolve, reject) {
  const web3 = getWeb3();
// Create a JavaScript versions of your Smart Contract's interface          // using the contract address and ABI we got from the Remix
  const donationContract = new web3.eth.Contract(ABI, address); 
  if (donationContract) resolve(donationContract);
  else reject();
});
const getCoinbase = async () => {
  const web3 = getWeb3();
  return await web3.eth.getCoinbase();
};
module.exports = { getContract, getCoinbase };

Вы можете узнать больше о coinbase и Web3 здесь и здесь.

Создание схемы GraphQL

Добавьте следующие определения типов GraphQL в файл yourschema.js:

const typeDefs = 
   `type Contract {
        address: String!,
        balance: Int
   }
   type DonationReceipt {
        transactionHash: String!,
        blockHash: String!,
        blockNumber: Int!,
        gasUsed: Int!,
        status: Boolean!
   }
   
   type Query {
        contract: Contract
   }
   type Mutation {
        donate(amount: Int!): DonationReceipt
   }
`;
module.exports = typeDefs;

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

Наконец, напишем наш сервер. Откройте свой терминал и установите эти пакеты в свой проект:

npm install --save-dev apollo-server-express body-parser express graphql graphql-tools

Добавьте следующий код в начало index.js:

const express = require("express");
const bodyParser = require("body-parser");
const { 
    graphqlExpress, 
    graphiqlExpress 
} = require("apollo-server-express");
const { makeExecutableSchema } = require("graphql-tools");
const typeDefs = require("./schema/schema");
const { 
    getContract, 
    getCoinbase 
} = require("./contract/getContract");

Наш следующий шаг - создать сервер Express и написать преобразователь GraphQL, чтобы получить баланс нашего контракта.

Продолжить редактирование index.js:

let contractInstance = {};
function getBalance() {
  return contractInstance.methods.checkContractBalance().call();
}
const resolvers = {
  Query: {
    async contract() {
      let balance = 0;
      await getBalance()
        .then(bal => (balance = bal / 1000000000000000000)) 
        // Convert to ether from wei
        .catch(err => console.log(err));
      return {
        address: contractInstance._address,
        balance
      };
    }
 }
};
// Create the schema
const schema = makeExecutableSchema({
  typeDefs,
  resolvers
});
// Initialize the app
const app = express();
const PORT = 4000;
// The GraphQL endpoint
app.use("/graphql", bodyParser.json(), graphqlExpress({ schema }));
// GraphiQL, a visual editor for graphql queries
app.use("/graphiql", graphiqlExpress({ endpointURL: "/graphql" }));
// Start the server and get contract instance
app.listen(PORT, () => {
  console.log(`Go to http://localhost:${PORT}/graphiql to explore the GraphQL API!`);
  // get our contract as soon as the server starts
  getContract
    .then(res => (contractInstance = res))
    .catch(err => console.log(err));
});

Если вы работали с GraphQL и Node.js, это должно быть вам знакомо.

Мы только что написали простой преобразователь с _11 _ / _ 12_, который возвращает адрес нашего развернутого смарт-контракта и его баланс!

Посетите http: // localhost: 4000 / graphiql, чтобы протестировать свой сервер GraphQL.

Если вы видите следующее, поздравляем! 🙌

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

Для этого добавьте в index.js следующую функцию:

// after our query resolver put this code
Mutation: {
 async function makeDonation(amount) {
    let response;
    let coinbase;
    let error;
    await getCoinbase()
      .then(res => (coinbase = res))
      .then(() =>
        contractInstance.methods
          .make_donation("sending some either")
          .send({
            gas: 300000,
            value: amount * 1000000000000000000, // wei conversion
            from: coinbase
          })
          .then(res => (response = res))
      )
      .catch(err => (error = err));
    return response;
  }
} // Mutation end

Помните, что мы импортировали getCoinbase из нашего getContract.js файла. Мы используем его сейчас, чтобы получить Coinbase, а затем сделать пожертвование.

Теперь мы добавим этот код в наш преобразователь под нашей contract функцией:

  async donate(obj, args, context) {
      let transactionHash = "";
      let blockHash = "";
      let blockNumber = 0;
      let gasUsed = 0;
      let status = false;
      const response = makeDonation(args.amount); 
      await response
        .then(res => {
          transactionHash = res.transactionHash;
          blockHash = res.blockHash;
          blockNumber = res.blockNumber;
          gasUsed = res.gasUsed;
          status = res.status;
        })
        .catch(err => console.log(err));
      return {
        transactionHash,
        blockHash,
        blockNumber,
        gasUsed,
        status
   };
}

Большой!

Вот файл finished index.js на случай, если что-то не так.

Давайте проверим, работает ли новый резолвер. Перезагрузите сервер и запустите эту мутацию, чтобы сделать пожертвование. Вы должны увидеть квитанцию ​​о пожертвовании следующим образом:

Чтобы убедиться, что все работает, проверьте баланс своего аккаунта в Metamask и баланс контракта через Remix. Все значения следует поменять!

Вы можете проверить это репозиторий GitHub, чтобы увидеть этот готовый проект.

Большое спасибо за кодирование вместе со мной в этом приложении GraphQL и смарт-контрактах. Надеюсь, вы кое-чему научились. Удачного кодирования!

Если вам понравился этот пост и вы хотите продолжить изучение разработки приложений и веб-приложений с помощью RED Academy, обязательно подпишитесь на нас на Medium или посетите наш веб-сайт.