สร้าง dapp บน Tezos (ฉบับปี 2023)

Feb 25 2023
ส่วนที่ 2 จาก 4-> กระเป๋าเงินและโทเค็นของผู้ใช้ ตอนนี้เรามาพูดถึงกระเป๋าเงินกัน กระเป๋าเงินเป็นองค์ประกอบสำคัญของ dapp ของคุณ หากไม่มี ผู้ใช้จะไม่สามารถโต้ตอบกับ Tezos blockchain ได้ ซึ่งผิดวัตถุประสงค์ของคุณ

ส่วนที่ 2 จาก 4-> กระเป๋าเงินและโทเค็นของผู้ใช้

ตอนนี้เรามาพูดถึงกระเป๋าสตางค์

กระเป๋าเงินเป็นองค์ประกอบสำคัญของ dapp ของคุณ หากไม่มี ผู้ใช้จะไม่สามารถโต้ตอบกับ Tezos blockchain ได้ ซึ่งผิดวัตถุประสงค์ของคุณ มีข้อควรพิจารณาหลายประการเมื่อคุณตั้งค่ากระเป๋าเงิน ซึ่งเราจะอธิบายด้านล่างนี้

ขั้นแรก เราต้องการแยกกระเป๋าเงินและการโต้ตอบและค่าต่างๆ ออกจากกันในองค์ประกอบเดียวกัน ซึ่งเรียกว่าWallet.svelteในตัวอย่างของเรา เมื่อใช้ Beacon SDK สิ่งสำคัญคือต้องให้อินสแตนซ์เดียวของ Beacon ทำงานเพื่อป้องกันข้อบกพร่อง

เมื่อติดตั้งส่วนประกอบ Wallet มีหลายสิ่งหลายอย่างที่เราต้องการทำ:

onMount(async () => {
    const wallet = new BeaconWallet({
      name: "Tezos dev portal dapp tutorial",
      preferredNetwork: network
    });
    store.updateWallet(wallet);
    const activeAccount = await wallet.client.getActiveAccount();
    if (activeAccount) {
      const userAddress = (await wallet.getPKH()) as TezosAccountAddress;
      store.updateUserAddress(userAddress);
      $store.Tezos.setWalletProvider(wallet);
      await getWalletInfo(wallet);
      // fetches user's XTZ, tzBTC and SIRS balances
      const res = await fetchBalances($store.Tezos, userAddress);
      if (res) {
        store.updateUserBalance("XTZ", res.xtzBalance);
        store.updateUserBalance("tzBTC", res.tzbtcBalance);
        store.updateUserBalance("SIRS", res.sirsBalance);
      } else {
        store.updateUserBalance("XTZ", null);
        store.updateUserBalance("tzBTC", null);
        store.updateUserBalance("SIRS", null);
      }
    }
  });

ตอนนี้ คุณต้องการตรวจสอบว่าผู้ใช้เคยเชื่อมต่อกระเป๋าเงินมาก่อนหรือไม่ Beacon จะติดตามการเชื่อมต่อสดในที่จัดเก็บในเครื่อง นี่คือวิธีที่ผู้ใช้ของคุณสามารถนำทางไปยัง dapp ของคุณและเชื่อมต่อกระเป๋าเงินของพวกเขาโดยอัตโนมัติ!

อินBeaconWalletสแตนซ์จัดเตรียมclientพร็อพเพอร์ตี้ด้วยเมธอดต่างๆ ซึ่งสิ่งที่คุณต้องการในที่นี้คือgetActiveAccount()ซึ่งจะดึงการเชื่อมต่อสดใดๆ ที่จัดเก็บไว้ในที่จัดเก็บในเครื่อง หากมีการเชื่อมต่อสด คุณสามารถดึงข้อมูลที่อยู่ของผู้ใช้และบันทึกไว้ในร้านค้า อัปเดตร้านค้าด้วยที่อยู่ของผู้ใช้ก่อนที่จะตั้งค่ากระเป๋าเงินเป็นผู้ลงนามด้วย รับข้อมูลที่คุณต้องการเกี่ยวกับกระเป๋าเงิน (โดยหลักคือ$store.Tezos.setWalletProvider(wallet)ชื่อ ของกระเป๋าเงิน) ด้วยgetWalletInfo()ฟังก์ชัน จากนั้นดึงยอดคงเหลือสำหรับที่อยู่ที่เชื่อมต่อกับfetchBalances()ฟังก์ชันที่อธิบายไว้ก่อนหน้านี้ เมื่อดึงยอดคงเหลือแล้ว ยอดคงเหลือจะถูกบันทึกไว้ในร้านค้าเพื่อแสดงในอินเทอร์เฟซ

หมายเหตุ: TezosAccountAddressเป็นประเภทกำหนดเองที่ฉันต้องการใช้เพื่อตรวจสอบความถูกต้องของที่อยู่ Tezos สำหรับบัญชีโดยนัย: type TezosAccountAddress = tz${"1" | "2" | "3"}${string}TypeScript จะส่งคำเตือนหากคุณพยายามใช้สตริงที่ไม่ตรงกับรูปแบบนี้

การเชื่อมต่อกระเป๋าเงิน

Taquito และ Beacon ทำงานพร้อมกันทำให้เชื่อมต่อกระเป๋าเงินได้ง่ายมาก โค้ดสองสามบรรทัดที่ใช้ API ของไลบรารีที่จำเป็นทั้งสองนี้บน Tezos กำลังจะสร้างปาฏิหาริย์

นี่คือวิธีการ:

const connectWallet = async () => {
  if (!$store.wallet) {
    const wallet = new BeaconWallet({
      name: "Tezos dev portal dapp tutorial",
      preferredNetwork: network
    });
    store.updateWallet(wallet);
  }
  await $store.wallet.requestPermissions({
    network: { type: network, rpcUrl }
  });
  const userAddress = (await $store.wallet.getPKH()) as TezosAccountAddress;
  store.updateUserAddress(userAddress);
  $store.Tezos.setWalletProvider($store.wallet);
  // finds account info
  await getWalletInfo($store.wallet);
  // fetches user's XTZ, tzBTC and SIRS balances
  const res = await fetchBalances($store.Tezos, userAddress);
  if (res) {
    store.updateUserBalance("XTZ", res.xtzBalance);
    store.updateUserBalance("tzBTC", res.tzbtcBalance);
    store.updateUserBalance("SIRS", res.sirsBalance);
  } else {
    store.updateUserBalance("XTZ", null);
    store.updateUserBalance("tzBTC", null);
    store.updateUserBalance("SIRS", null);
  }
};

ต่อไป คุณขอให้ผู้ใช้เลือกกระเป๋าเงินด้วย วิธีการที่มีอยู่ในอินสแตน ซ์requestPermissions()ของ BeaconWalletพารามิเตอร์คือวัตถุที่คุณระบุเครือข่ายที่คุณต้องการเชื่อมต่อ เช่นเดียวกับ URL ของโหนด Tezos RPC ที่คุณจะโต้ตอบด้วย

หลังจากที่ผู้ใช้เลือกกระเป๋าเงินที่จะใช้กับ dapp ของเรา คุณจะได้รับที่อยู่ของพวกเขาด้วยวิธีการgetPKH()บนBeaconWalletอินสแตนซ์ คุณอัปเดตผู้ลงนามในอินTezosToolkitสแตนซ์โดยส่งอินสแตนซ์กระเป๋าเงินไปที่setWalletProvider()คุณจะได้รับข้อมูลที่คุณต้องการจากกระเป๋าเงินและดึงข้อมูล ยอดคงเหลือของผู้ใช้

ตอนนี้กระเป๋าเงินเชื่อมต่อแล้ว และผู้ใช้จะแสดงยอดคงเหลือที่แตกต่างกัน รวมถึงสถานะการเชื่อมต่อในแถบด้านข้าง!

สำคัญ: อย่างไรก็ตาม คุณต้องการออกแบบ dapp ของคุณ สิ่งสำคัญคือต้องเก็บอินสแตนซ์เดียวของ the BeaconWalletและขอแนะนำอย่างยิ่งให้ทำเช่นเดียวกันกับอินสแตนซ์ของTezosToolkit. การสร้างหลายอินสแตนซ์ทำให้สถานะของแอปของคุณยุ่งเหยิงและกับ Taquito โดยทั่วไป

ตัดการเชื่อมต่อกระเป๋าเงิน

การตัดการเชื่อมต่อกระเป๋าเงินมีความสำคัญเท่ากับการเชื่อมต่อ ไม่มีอะไรน่าผิดหวังไปกว่าการค้นหาวิธีตัดการเชื่อมต่อกระเป๋าเงินของคุณเป็นเวลาหลายชั่วโมงทั้งที่ไม่ได้ระบุไว้อย่างชัดเจน โปรดจำไว้ว่า ผู้ใช้จำนวนมากมีกระเป๋าเงินหลายใบ (เช่น Temple หรือ Kukai) และแม้แต่ที่อยู่หลายที่อยู่ภายในกระเป๋าเงินเดียวกันที่พวกเขาต้องการใช้เพื่อโต้ตอบกับ dapp ของคุณ ทำให้การตัดการเชื่อมต่อกระเป๋าเงินเป็นเรื่องง่ายสำหรับพวกเขา

const disconnectWallet = async () => {
  $store.wallet.client.clearActiveAccount();
  store.updateWallet(undefined);
  store.updateUserAddress(undefined);
  connectedNetwork = "";
  walletIcon = "";
};

  • $store.wallet.client.clearActiveAccount()-> ฆ่าการเชื่อมต่อกับ Beacon ปัจจุบัน
  • store.updateWallet(undefined)-> ลบกระเป๋าเงินออกจากสถานะเพื่อทริกเกอร์การโหลดอินเทอร์เฟซใหม่
  • store.updateUserAddress(undefined)-> ลบที่อยู่ของผู้ใช้ปัจจุบันออกจากสถานะเพื่ออัปเดต UI
  • connectedNetwork = ""; walletIcon = ""-> จำเป็นต้องรีเซ็ตสถานะของ dapp และนำเสนออินเทอร์เฟซที่ไม่มีการเชื่อมต่อกระเป๋าเงิน

ข้อควรพิจารณาในการออกแบบ

การเขียนโค้ดเพื่อโต้ตอบกับกระเป๋าเงินในแอปพลิเคชันแบบกระจายศูนย์เป็นกระบวนทัศน์ใหม่ และแม้ว่าคุณจะสามารถนำแนวคิดและแนวปฏิบัติที่ดีมากมายจากประสบการณ์ของคุณในฐานะนักพัฒนากลับมาใช้ใหม่ได้ แต่ก็มีสิ่งใหม่ๆ สองสามข้อที่ควรคำนึงถึง:

  1. อย่าแจ้งให้ผู้ใช้เชื่อมต่อกระเป๋าเงินของพวกเขาหลังจากติดตั้ง dapp แล้ว: การได้รับป๊อปอัปกระเป๋าเงินบนหน้าจอหลังจากโหลดแอปนั้นน่ารำคาญ คุณต้องจำไว้ว่าผู้ใช้จำนวนมากของคุณไม่มีความรู้ด้านเทคนิคและไม่เข้าใจว่า การเชื่อมต่อกระเป๋าเงินนั้นไม่เป็นอันตราย ดังนั้นพวกเขาอาจระวังเกี่ยวกับ dapp ของคุณหากคุณขอให้พวกเขาเชื่อมต่อกระเป๋าเงินตั้งแต่เริ่มใช้งาน ให้แสดงข้อมูลบางอย่างเกี่ยวกับ dapp ของคุณและปุ่มเพื่อเชื่อมต่อกระเป๋าเงินด้วยตนเอง หากนี่เป็นครั้งแรก
  2. ปุ่มสำหรับเชื่อมต่อกระเป๋าเงินต้องโดดเด่นในอินเทอร์เฟซของคุณ ไม่ว่าคุณจะทำให้มันใหญ่ขึ้น มีสีอื่น หรือแบบอักษรอื่น ผู้ใช้จะต้องไม่ใช้เวลามากกว่าสองสามวินาทีในการค้นหา
  3. ปุ่มต้องอยู่ในตำแหน่งที่คาดเดาได้: Dapps ส่วนใหญ่บน Tezos วางปุ่มเพื่อเชื่อมต่อกระเป๋าเงินที่ด้านบนซ้ายหรือขวาบนของ UI คุณไม่ได้"สร้างสรรค์"ด้วยการวางปุ่มในตำแหน่งอื่น คุณจะทำให้ผู้ใช้สับสน
  4. ข้อความในปุ่มควรอ่านว่า Connect หรือคำอื่นที่คล้ายกัน หลีกเลี่ยงการ Sync หรือคำอื่นๆ แต่คำว่า "connect" เนื่องจากอาจหมายถึงสิ่งที่แตกต่างออกไปในบริบทของแอปพลิเคชันแบบกระจายอำนาจ
  5. สถานะของกระเป๋าเงินจะต้องแสดงใน Dapp ไม่ว่าจะเชื่อมต่อหรือตัดการเชื่อมต่อ ผู้ใช้ควรจะสามารถบอกได้ นอกจากนี้ คุณสามารถเพิ่มข้อมูลบางอย่างเกี่ยวกับกระเป๋าเงินที่พวกเขาใช้ (เหมือนที่เราทำในบทช่วยสอนนี้) เครือข่ายที่พวกเขาเชื่อมต่อ หรือยอดคงเหลือ
  6. คุณต้องเปิด/ปิดการโต้ตอบของ dapp ของคุณที่ขึ้นอยู่กับกระเป๋าเงิน ผู้ใช้ไม่ควรโต้ตอบกับคุณลักษณะของแอปพลิเคชันของคุณที่ต้องเชื่อมต่อกระเป๋าเงินของพวกเขา หากไม่เป็นเช่นนั้น

หนึ่งในคุณสมบัติที่สำคัญที่สุดของ dapp ซึ่งเป็นหนึ่งในคุณสมบัติที่ง่ายที่สุดที่จะมองข้ามคือการดึงข้อมูลยอดคงเหลือของผู้ใช้ ผู้ใช้สามารถบอกได้ว่ามีสิ่งผิดปกติหากยอดคงเหลือของพวกเขาแสดงไม่ถูกต้องหรือไม่อัปเดตตามนั้นหลังจากการโต้ตอบกับสัญญา นั่นเป็นเหตุผลว่าทำไมการดูแลการแสดงและอัปเดตยอดคงเหลือจึงเป็นเรื่องสำคัญ

เนื่องจากคุณกำลังดึงข้อมูลยอดคงเหลือในส่วนประกอบต่างๆ ของแอปพลิเคชันของเรา คุณจะสร้างฟังก์ชันในไฟล์utils.tsและนำเข้าเมื่อจำเป็น

ในการเรียกยอดคงเหลือ คุณจะใช้ Taquito สำหรับยอดคงเหลือ XTZ ของผู้ใช้ และ API ยอดนิยมบน Tezos สำหรับยอดคงเหลือ tzBTC และ SIRS, TzKT API หากคุณต้องการสร้างแอปพลิเคชันที่ซับซ้อนมากขึ้นบน Tezos ความรู้ที่ดีเกี่ยวกับ TzKT API เป็นสิ่งสำคัญ เนื่องจากมีคุณสมบัติมากมายที่จะทำให้แอปของคุณมีเนื้อหาที่สมบูรณ์ยิ่งขึ้นและรวดเร็วยิ่งขึ้น

มาดูประเภทของฟังก์ชันกัน:

export const fetchBalances = async (
  Tezos: TezosToolkit,
  userAddress: TezosAccountAddress
): Promise<{
  xtzBalance: number;
  tzbtcBalance: number;
  sirsBalance: number;
} | null> => {
  try {
    // the code will be here
  } catch (error) {
    console.error(error);
    return null;
  }
}

ขั้นแรก เรียกยอดคงเหลือ XTZ:

const xtzBalance = await Tezos.tz.getBalance(userAddress);
if (!xtzBalance) throw "Unable to fetch XTZ balance";

ต่อไป คุณตรวจสอบการมีอยู่ของยอดคงเหลือ และคุณปฏิเสธสัญญาหากไม่มีอยู่จริง หากเป็นเช่น นั้นยอดคงเหลือจะพร้อมใช้งานในรูปแบบBigNumber

หมายเหตุ: โดยส่วนใหญ่แล้ว Taquito จะส่งคืนค่าตัวเลขจากบล็อกเชนเป็น BigNumber เนื่องจากค่าบางค่าอาจเป็นตัวเลขที่สูงมาก และ JavaScript ขึ้นชื่อในเรื่องการจัดการตัวเลขจำนวนมากได้ไม่ดี

เมื่อดึงยอดคงเหลือ XTZ แล้ว คุณสามารถดำเนินการต่อและดึงยอดคงเหลือของ tzBTC และ SIRS:

import { tzbtcAddress, sirsAddress } from "./config";

// previous code for the function
const res = await fetch(
  `https://api.tzkt.io/v1/tokens/balances?account=${userAddress}&token.contract.in=${tzbtcAddress},${sirsAddress}`
);
if (res.status === 200) {
  const data = await res.json();
  if (Array.isArray(data) && data.length === 2) {
    const tzbtcBalance = +data[0].balance;
    const sirsBalance = +data[1].balance;
    if (!isNaN(tzbtcBalance) && !isNaN(sirsBalance)) {
      return {
        xtzBalance: xtzBalance.toNumber(),
        tzbtcBalance,
        sirsBalance
      };
    } else {
      return null;
    }
  }
} else {
  throw "Unable to fetch tzBTC and SIRS balances";
}

เมื่อสัญญาได้รับการแก้ไขด้วย200รหัส หมายความว่าได้รับข้อมูลแล้ว คุณแยกวิเคราะห์เป็น JSON ด้วย.json()วิธีการตอบกลับ และเราตรวจสอบว่าข้อมูลมีรูปร่างตามที่คาดไว้ นั่นคืออาร์เรย์ที่มี 2 องค์ประกอบในนั้น

องค์ประกอบแรกคือยอดคงเหลือ tzBTC และส่วนที่สองคือยอดคงเหลือ SIRS คุณเก็บไว้ในตัวแปรของตัวเองที่คุณแปลงเป็นตัวเลขก่อนที่จะตรวจสอบว่าพวกเขาถูกโยนอย่างถูกต้องisNaNด้วย หากทุกอย่างเป็นไปด้วยดี ความสมดุลทั้ง 3 จะถูกส่งกลับ และหากมีอะไรผิดพลาดระหว่างทาง ฟังก์ชันจะส่งnullกลับ

หลังจากเรียกยอดคงเหลือในส่วนประกอบใดๆ ของแอปพลิเคชันของเรา คุณจะเก็บข้อมูลนี้ในร้านค้าเพื่ออัปเดตสถานะ:

const res = await fetchBalances($store.Tezos, userAddress);
if (res) {
  store.updateUserBalance("XTZ", res.xtzBalance);
  store.updateUserBalance("tzBTC", res.tzbtcBalance);
  store.updateUserBalance("SIRS", res.sirsBalance);
} else {
  store.updateUserBalance("XTZ", null);
  store.updateUserBalance("tzBTC", null);
  store.updateUserBalance("SIRS", null);
}

ในส่วนที่สามการแลกเปลี่ยนโทเค็น =>