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

Всем привет! Добро пожаловать в мое четвертое прохождение этой серии. В этом посте мы продолжим рассказывать о том, как построить простую систему подписки пользователей на Solana Web3.

Предполагается, что вы закончили первые 3 поста этой серии, прежде чем начать этот. Если нет, то посмотрите предыдущие 2 поста:

Учебное пособие по Full Stack Solana Web3 (1) — подключение к фантомному кошельку

Full Stack Solana Web3 Tutorial (2) — Сделайте свой первый платеж

Full Stack Solana Web3 Tutorial (3) — Простая система подписки пользователей

Если вы закончили, давайте начнем!

Изменение выборки JSON

В предыдущем отрывке мы использовали JSON для получения нашего открытого ключа в серверную часть, чтобы проверить, подписан ли пользователь. Теперь, поскольку нам также нужно обновить метод подписки пользователя, мы немного изменим наше правило JSON Fetch.

В предыдущем случае наш JSON выглядит следующим образом:

{pubkey: <your_pub_key>}

Теперь мы бы изменили что-то вроде этого:

{pubkey: <your_pub_key>, method: "r"}

Если метод «r», это означает, что мы читаем данные. Это также может быть «w», что указывает на то, что передаваемый публичный ключ будет обновлен в базе данных. Теперь давайте изменим нашу функцию checksub в index.html на ниже:

async function checksubs(){
        const url = '/';
        const header = { 'Content-Type': 'application/json' };
const data = { pubkey: pubKey.toString(), method:"r"};   
        const res = await fetch(url,{
          method: 'POST',    
          cache: 'no-cache', 
          headers: header,
          body: JSON.stringify(data)    
      });
const result = await res.json();
        return result;
      }

Как и в случае с checksubs, он всегда просто считывает данные. Итак, мы бы поместили метод: «r» здесь. Кроме того, чтобы улучшить читаемость, я изменил вызов результата, используя await вместо .then в предыдущем посте.

Теперь, в app.js, мы должны изменить app.post() примерно так:

app.post('/', (req, res) => {
    console.log('Got body:', req.body.pubkey);
    if (req.body.method=="r"){
      pub_key = req.body.pubkey;
      con.query('SELECT * FROM users WHERE pubkey = ?', [pub_key], function (err, results, fields) {
        if (Object.keys(results).length>0){
          res.status(200).json({'result' : 'True'});
        }else{
          res.status(200).json({'result' : 'False'});
        }
});
    }
});

Проверка статуса подписки в интерфейсе

Итак, теперь наш бэкэнд вернет, подписан ли публичный адрес пользователя. Теперь давайте изменим connectWallet() в index.html так, как показано ниже:

async function connectWallet(){
        const isPhantomInstalled = window.solana && window.solana.isPhantom
try {
          const resp = await window.solana.connect();
          pubKey = resp.publicKey;
          var greeting_p = document.createElement("p");
          var message = document.createTextNode("hi! Your wallet"+pubKey.toString()+" is connected");
          greeting_p.appendChild(message);
          document.getElementById("greet").appendChild(greeting_p);  
          var result = await checksubs();
          if (result.result=="False"){
              not_subscribed();
          }if (result.result=="True"){
            subscribed();
          }
                  } catch (err) {
          console.log(err);
        }
      }

Теперь что мы делаем, так это проверяем, возвращает ли бэкэнд True или False. Если False, вызовите функцию not_subscribed(). В противном случае вызывается функция subscribed(). Теперь давайте посмотрим, как выглядят эти две функции:

function subscribed(){
        var subscribed_p = document.createElement("p");
        var subscribed_message = document.createTextNode("you are subscribed!");
            subscribed_p.appendChild(subscribed_message);
            document.getElementById("greet").appendChild(subscribed_p); 
      }
function not_subscribed(){
            var not_subscribed_p = document.createElement("p");
            var not_subscribed_message = document.createTextNode("you are not subscribed!");
            not_subscribed_p.appendChild(not_subscribed_message);
            document.getElementById("greet").appendChild(not_subscribed_p); 
            var btn = document.createElement("button");
            btn.innerHTML = "Subscribe Now!";
            btn.addEventListener("click", transferSOL);
            document.getElementById("greet").appendChild(btn); 
      }

Итак, в subscribed() мы просто печатаем вы подписаны в интерфейсе. В not_subscribed() мы напечатаем вы не подписаны, а также кнопку, которая вызывает функцию transferSOL(), о которой мы упоминали в предыдущем посте.

Теперь в функцию transferSOL() мы можем добавить функцию, которая также извлекает JSON для добавления открытого ключа пользователя после успешной оплаты SOL:

async function transferSOL(){
        const transferTransaction = new web3.Transaction().add(web3.SystemProgram.transfer({
            fromPubkey: pubKey,
            toPubkey: new web3.PublicKey("FVv5Dtmreiz9TPnU71tkXVZAPZhasYXujHk2QTehSBPJ"),
            lamports: 10000000
          }))
  
        const network = "https://api.devnet.solana.com";
        const connection = new web3.Connection(network);
        transferTransaction.feePayer = pubKey;
        let blockhash = (await connection.getLatestBlockhash("finalized")).blockhash;
        transferTransaction.recentBlockhash = blockhash;
        const {signature} = await window.solana.signAndSendTransaction(transferTransaction);
        console.log("test");
        await connection.confirmTransaction(signature);
console.log(signature);
        const url = '/';
        const header = { 'Content-Type': 'application/json' };
const data = { pubkey: pubKey.toString(), method:"w", signature: signature};   
        const res = await fetch(url,{
          method: 'POST',    
          cache: 'no-cache', 
          headers: header,
          body: JSON.stringify(data)    
      });
const result = await res.json();
      }

Итак, в приведенном выше коде вы можете видеть, что помимо открытого ключа пользователя мы также получаем подпись в нашем бэкэнде для проверки. Итак, в бэкенде нам нужно проверить, есть ли подпись и т. Д. Итак, в app.js мы теперь исправим что-то вроде следующего:

app.post('/', async function (req, res){
    console.log('Got body:', req.body.pubkey);
    if (req.body.method=="r"){
      pub_key = req.body.pubkey;
      con.query('SELECT * FROM users WHERE pubkey = ?', [pub_key], function (err, results, fields) {
        if (Object.keys(results).length>0){
          res.status(200).json({'result' : 'True'});
        }else{
          res.status(200).json({'result' : 'False'});
        }
});
    }else if (req.body.method=="w"){
      establishConnection();
      console.log(req.body.signature);
      const transactionDetails = await connection.getParsedTransaction(req.body.signature);
      pub_key = transactionDetails.transaction.message.instructions[0].parsed.info.source;
      
      if (transactionDetails.transaction.message.instructions[0].parsed.info.destination=="FVv5Dtmreiz9TPnU71tkXVZAPZhasYXujHk2QTehSBPJ"&&transactionDetails.transaction.message.instructions[0].parsed.info.lamports=="10000000"){
      con.query('INSERT INTO `users`(pubkey) VALUES (?);', [pub_key], function (err, result) {  
        if (err) throw err;  
        console.log("record inserted");  
        res.status(200).json("sucess!");
      });  
      }
}else{
      console.log("something wrong!");
    }
});

Итак, здесь нам нужно установить соединение с сетью Solana. Итак, ставим все это под establishConnection(). Код в функции прост. Теперь давайте посмотрим, что под app.js:

  1. Во-первых, когда мы получаем выборку из внешнего интерфейса, нам нужно определить его метод «w» или «r». Если «r», запустите часть, чтобы проверить, подписан ли пользователь.
  2. Если это «w», мы устанавливаем соединение с Solana и находим детали транзакции, используя getParsedTransaction(). Мы передали подпись get from frontend, чтобы продолжить;
  3. Затем, используя transactionDetails.transaction.message.instructions[0].parsed.info.destination, вы сможете извлечь пункт назначения потока средств. Затем, используя transactionDetails.transaction.message.instructions[0].parsed.info.lamports, вы сможете извлечь сумму перевода средств по транзакции. Используя эти 2 информации, убедитесь, что достаточное количество лампорта переведено на учетную запись назначения;
  4. Теперь обновите открытый ключ пользователя в базе данных SQL. Помнить! Используйте transactionDetails.transaction.message.instructions[0].parsed.info.source для извлечения открытого ключа, чтобы добавить список подписанных пользователей.

Заключение

Итак, теперь, если вы следуете вышеизложенному, нажмите «подписать пользователя» через интерфейс и подтвердите транзакцию. Теперь обновите снова. Вы увидите что-то вроде b ниже:

Поздравляю! Вы успешно создали систему подписки вашего первого пользователя. Если вы хотите узнать больше о разработке web3 в Solana. Пожалуйста, следите за обновлениями и увидимся в следующий раз!