<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          opennft-clientOpenNFT 瀏覽器插件

          聯(lián)合創(chuàng)作 · 2023-09-18 15:04

          opennft-client 需要谷歌瀏覽器或 Chromium 內(nèi)核

          前期準(zhǔn)備

          注冊(cè)百度賬號(hào)以及獲取私鑰

          注冊(cè)

          充值百度開(kāi)放網(wǎng)絡(luò)

          Tip:用戶(hù)地址下需要有百度開(kāi)放網(wǎng)絡(luò)余額才能使用轉(zhuǎn)移資產(chǎn),查詢(xún)余額等功能。建議在百度開(kāi)放網(wǎng)絡(luò)充值0.1元。充值鏈接:https://xuper.baidu.com/n/console#/finance/wallet/recharge

          充值

          插件使用

          使用幫助二維碼

          插件安裝

          插件已放置根目錄下()

          國(guó)內(nèi)加速下載 https://gitee.com/shengjian-tech/opennft-client/raw/master/MakerONE.zip

          1,瀏覽器選擇管理擴(kuò)展程序

          擴(kuò)展程序

          2,首先打開(kāi)開(kāi)發(fā)者模式,然后解壓下載的壓縮包并選擇加載,此時(shí)您可以看到瀏覽器已經(jīng)安裝好該插件了

          加載程序

          3,您可以選擇插件常駐

          擴(kuò)展常駐

          插件登錄

          下載私鑰到本地之后,打開(kāi)瀏覽器插件進(jìn)入登錄頁(yè),選擇本地私鑰,輸入安全碼登錄:

          登錄頁(yè)

          用戶(hù)首頁(yè)

          登錄之后跳轉(zhuǎn)到首頁(yè),顯示目前處于百度開(kāi)放網(wǎng)絡(luò),用戶(hù)百度開(kāi)放網(wǎng)絡(luò)地址,余額。以及功能等。

          首頁(yè)

          查詢(xún)資產(chǎn)余額:

          查詢(xún)余額

          轉(zhuǎn)移資產(chǎn):

          轉(zhuǎn)移資產(chǎn)

          查詢(xún)交易:

          查詢(xún)交易

          整體設(shè)計(jì):

          登錄頁(yè)

          • 本地私鑰路徑:需要用戶(hù)選擇本地私鑰存放路徑,讀取私鑰內(nèi)容。
          • 安全碼(可選)(6 位數(shù)):根據(jù)超級(jí)鏈生成賬戶(hù)的方式可選。開(kāi)放網(wǎng)絡(luò)必填。

          js 代碼:

          轉(zhuǎn)換開(kāi)放網(wǎng)絡(luò)地址為 EVM 地址的工具類(lèi) addressUtils.js

          import base58 from 'bs58'
          import { sha256 } from 'js-sha256'
          export function XchainAddrToEvm(addr) {
            var result = ''
            try {
              // 判斷是否是合約賬號(hào);判斷合約賬戶(hù)地址僅支持 XC11111111111@xuper, xuper后綴,go-sdk有相同問(wèn)題。
              if (determineContractAccount(addr)) {
                result = contractAccountToEVMAddress(addr)
              } else if (determineContractName(addr)) {
                result = contractNameToEVMAddress(addr)
              } else {
                result = xchainAKToEVMAddress(addr)
              }
              return result
            } catch (err) {
              console.log(err)
            }
          }
          // 判斷合約賬戶(hù)地址僅支持 XC11111111111@xuper, xuper后綴,go-sdk有相同問(wèn)題。
          function determineContractAccount(xchainAddr) {
            if (isAccount(xchainAddr) != 1) {
              return false
            }
            return xchainAddr.indexOf('@xuper') != -1
          }
          
          const accountPrefix = 'XC'
          function isAccount(name) {
            if (name == '') {
              return -1
            }
            if (name.indexOf(accountPrefix) != 0) {
              return 0
            }
            var prefix = name.split('@')[0]
            prefix = prefix.substr(accountPrefix.length)
            if (!validRawAccount(prefix)) {
              return 0
            }
            return 1
          }
          
          const accountSize = 16
          function validRawAccount(accountName) {
            if (accountName == '') {
              return false
            }
            if (accountName.length != accountSize) {
              return false
            }
            for (var i = 0; i < accountSize; i++) {
              if (accountName[i] >= '0' && accountName[i] <= '9') {
                continue
              } else {
                return false
              }
            }
            return true
          }
          const contractAccountPrefixs = '1112'
          const Word160Length = 20
          function contractAccountToEVMAddress(contractAccount) {
            var contractAccountValid = contractAccount.slice(2, 18)
            var str = contractAccountPrefixs.concat(contractAccountValid)
            if (str.length != Word160Length) {
              throw new Error('slice passed as address shou have 20 byte length')
            }
            return Buffer.from(str).toString('hex').toUpperCase()
          }
          
          const contractNameMaxSize = 16
          const contractNameMinSize = 4
          const contractNameRegex = /^[a-zA-Z_]{1}[0-9a-zA-Z_.]+[0-9a-zA-Z_]$/
          
          function determineContractName(xchainAddr) {
            var contractSize = xchainAddr.length
            if (
              contractSize > contractNameMaxSize ||
              contractSize < contractNameMinSize
            ) {
              return false
            }
            if (!contractNameRegex.test(xchainAddr)) {
              return false
            }
            return true
          }
          
          const evmAddressFiller = '-'
          const contractNamePrefixs = '1111'
          function contractNameToEVMAddress(contractName) {
            var contractNameLength = contractName.length
            var prefixStr = ''
            for (var i = 0; i < Word160Length - contractNameLength - 4; i++) {
              prefixStr += evmAddressFiller
            }
            contractName = prefixStr + contractName
            contractName = contractNamePrefixs + contractName
          
            if (contractName.length != Word160Length) {
              throw new Error('slice passed as address shou have 20 byte length')
            }
            return Buffer.from(contractName).toString('hex').toUpperCase()
          }
          
          function xchainAKToEVMAddress(xchainAddr) {
            var rawAddr = base58.decode(xchainAddr)
            if (rawAddr.length < 21) {
              throw new Error('bad address')
            }
            rawAddr = rawAddr.slice(1, 21)
            return Buffer.from(rawAddr, '').toString('hex').toUpperCase()
          }
          
          export function EvmToXchainAddr(addr) {
            // return addr, addrType, nil
            var result = ''
            try {
              var bs = Buffer.from(addr, 'hex').toString('ascii')
              if (bs.length != Word160Length) {
                throw new Error('slice passed as address shou have 20 byte length')
              }
              var evmAddrStrWithPrefix = bs
              // 合約賬號(hào)
              if (evmAddrStrWithPrefix.slice(0, 4) == contractAccountPrefixs) {
                result = evmAddressToContractAccount(bs)
              } else if (evmAddrStrWithPrefix.slice(0, 4) == contractNamePrefixs) {
                result = evmAddressToContractName(bs)
              } else {
                var buffer = Buffer.from(addr, 'hex')
                result = evmAddressToXchain(buffer)
              }
              return result
            } catch (err) {
              console.log(err)
            }
          }
          function evmAddressToContractAccount(addr) {
            return accountPrefix + addr.slice(4) + '@xuper'
          }
          function evmAddressToContractName(addr) {
            var index = addr.lastIndexOf(evmAddressFiller)
            return addr.slice(index + 1)
          }
          
          function evmAddressToXchain(addr) {
            var addTyepe = []
            var addrArray = new Uint8Array(addr)
            addTyepe.push(1)
            for (var i = 0; i < addrArray.length; i++) {
              addTyepe.push(addrArray[i])
            }
            var checkCode = DoubleSha256(addTyepe)
            var simpleCheckCode = checkCode.slice(0, 4)
            for (var i = 0; i < simpleCheckCode.length; i++) {
              addTyepe.push(simpleCheckCode[i])
            }
            return base58.encode(addTyepe)
          }
          
          // DoubleSha256 執(zhí)行2次SHA256,這是為了防止SHA256算法被攻破。
          function DoubleSha256(data) {
            return UsingSha256(UsingSha256(data))
          }
          
          // UsingSha256 get the hash result of data using SHA256
          function UsingSha256(data) {
            return sha256.array(data)
          }
           
          // 需要引入 XuperSDK 和上面的地址轉(zhuǎn)換工具類(lèi)
          import XuperSDK, { Endorsement } from '@xuperchain/xuper-sdk'
          import { XchainAddrToEvm } from './addressUtils'
          
          // TODO 需要通過(guò)用戶(hù)選擇的私鑰路徑,讀取出來(lái)私鑰的內(nèi)容
          const private = ''
          // 安全碼
          const password = ''
          // 登錄后 生成 賬戶(hù)對(duì)象
          const acc = xsdk.import(password, private)
           

          首頁(yè)

          • 默認(rèn)首頁(yè)用戶(hù)處于開(kāi)放網(wǎng)絡(luò)。 開(kāi)放網(wǎng)絡(luò)為下拉框,默認(rèn)一個(gè)位開(kāi)放網(wǎng)絡(luò)。用戶(hù)可以添加網(wǎng)絡(luò)。添加網(wǎng)絡(luò)可以彈框,需要參數(shù):網(wǎng)絡(luò)名(用戶(hù)自己輸入就行),節(jié)點(diǎn) IP(例如:39.156.69.83:37100),鏈名:(例如 xuperchain), Vue 里面開(kāi)放網(wǎng)絡(luò)的 node 需要設(shè)置為https://xuper.baidu.com/nodeapi

            // 默認(rèn)就有的開(kāi)放網(wǎng)絡(luò),默認(rèn)開(kāi)放網(wǎng)絡(luò)的鏈名
            const node = '39.156.69.83:37100' // vue里面設(shè)置為 https://xuper.baidu.com/nodeapi
            const chain = 'xuper'
            
            // 連接開(kāi)放網(wǎng)絡(luò)時(shí)需要加載背書(shū)服務(wù),
            const params = {
              server: '39.156.69.83:37100', // ip, port // vue里面設(shè)置為 https://xuper.baidu.com/nodeapi
              fee: '400', // fee
              endorseServiceCheckAddr: 'jknGxa6eyum1JrATWvSJKW3thJ9GKHA9n', // sign address
              endorseServiceFeeAddr: 'aB2hpHnTBDxko3UoP2BpBZRujwhdcAFoT', // fee address
            }
            // 默認(rèn)的開(kāi)放網(wǎng)絡(luò) SDK client, 后續(xù)查詢(xún)余額,調(diào)用合約使用。
            const xsdk = new XuperSDK({
              node,
              chain,
              plugins: [
                Endorsement({
                  transfer: params,
                  makeTransaction: params,
                }),
              ],
            })
            
            // 用戶(hù)新增網(wǎng)絡(luò)可以生成新的sdk client并記錄,切換網(wǎng)絡(luò)即切換SDK,新增網(wǎng)絡(luò)暫時(shí)不考慮背書(shū)插件,僅傳入IP和鏈名即可
            const xsdk = new XuperSDK({
              node,
              chain,
            })
             
          • 顯示用戶(hù) Address

            // 用戶(hù)登錄時(shí)生成的acc, acc.address即為用的address地址
            const addr = acc.address
             
          • 顯示用戶(hù)余額

            // 查詢(xún)登錄用戶(hù)余額
            // 用戶(hù)超級(jí)鏈賬戶(hù)余額 address 直接傳入上面 acc.address即可。
            const balance = async (adress) => {
              try {
                const result = await xsdk.getBalance(adress)
                debug(result.bcs[0].balance)
              } catch (err) {
                throw err
              }
            }
             
          • 默認(rèn)提供三個(gè) Action 功能,轉(zhuǎn)移 NFT。查詢(xún) NFT 數(shù)量,查詢(xún)交易。并提供新增 Action 操作

          • 點(diǎn)擊功能,跳轉(zhuǎn)到功能頁(yè)。最上面為下拉框,用戶(hù)可以選擇功能,默認(rèn)為上述三個(gè),并且有一個(gè)新增操作。

          • 默認(rèn)三個(gè)功能 轉(zhuǎn)移,查詢(xún),查詢(xún)交易

            // 默認(rèn)合約名
            const contractName = 'opennft'
            // 默認(rèn)方法名
            const methodName = 'safeTransferFrom'
            // 默認(rèn)參數(shù)
            // nft 轉(zhuǎn)移發(fā)起者,默認(rèn)取值 acc.address,acc.address需要轉(zhuǎn)換,下述為轉(zhuǎn)換好的。
            // acc.address 格式為 ULuqhymLPGidfihUb683i2TH4qtaqZ2Dz 需要用工具類(lèi)轉(zhuǎn)換為evm的地址2BEF68690AE24553824BA37C003C2B9067665F81
            const from = XchainAddrToEvm(acc.address)
            
            // 下述三個(gè)參數(shù),需要用戶(hù)在頁(yè)面輸入,提供三個(gè)輸入框即可。
            // nft 轉(zhuǎn)移接受者 前端輸入 例如 cRsoDDnDX1NjhzJtNKLS3GHudBsgyRouQ 也需要轉(zhuǎn)換
            const to = XchainAddrToEvm('cRsoDDnDX1NjhzJtNKLS3GHudBsgyRouQ')
            // 轉(zhuǎn)移的 nft token id
            const nftTokenID = '6'
            // 轉(zhuǎn)移數(shù)量
            const amount = '1'
            
            // 轉(zhuǎn)移NFT  轉(zhuǎn)移操作前先查詢(xún)一下賬戶(hù)余額。是0的話(huà)讓他去充值。建議最少充值一元。
            // 咱們默認(rèn)提供的NFT 轉(zhuǎn)移,只需要轉(zhuǎn)移著的地址,tokenid,數(shù)量。給用戶(hù)返回交易ID
            const TransferNFTEvm = async (toAddr, TokenID, Amount) => {
              try {
                const contractName = contractName
                const methodName = methodName
                const demo = await xsdk.invokeSolidityContarct(
                  contractName,
                  methodName,
                  'evm',
                  {
                    from: from,
                    to: to,
                    id: nftTokenID,
                    amount: amount,
                    data: '',
                  },
                  '0',
                  acc
                )
                // 352cd3f829dded7ad1da7ab3a0c3a8776cd3ec545c617ad499abb2d29459c6ee  // 交易ID 返回給用戶(hù)
                debug(xsdk.transactionIdToHex(demo.transaction.txid))
                const result = await xsdk.postTransaction(demo.transaction, acc)
                // TODO 調(diào)用轉(zhuǎn)移操作成功后
                // TODO 調(diào)用坤那邊的服務(wù)端接口解析交易 只傳輸txid,調(diào)用接口即可,后續(xù)不管。最后給用戶(hù)返回上面的交易ID就行。
                debug(result)
                // err 是空 證明轉(zhuǎn)移成功,不是 就是執(zhí)行失敗。
              } catch (err) {
                console.log(err)
              }
            }
             
          • 查詢(xún)自己的 NFT 余額

            // 查詢(xún)  NFT 余額 前端用戶(hù)選擇查詢(xún)資產(chǎn)余額,需要輸入NFT token ID 就行,然后返回余額數(shù)量就OK。
            const queryNFTBalance = async (tokenID) => {
              try {
                const contractName = 'opennft'
                const methodName = 'balanceOf'
                const args = {
                  account: XchainAddrToEvm(acc.address),
                  id: tokenID,
                }
                const demo = await xsdk.invokeSolidityContarct(
                  contractName,
                  methodName,
                  'evm',
                  args,
                  '0',
                  acc
                )
                // 判斷  demo.preExecutionTransaction.response.responses的長(zhǎng)度是否大于0, 大于0 取demo.preExecutionTransaction.response.responses[length - 1]
                const len = demo.preExecutionTransaction.response.responses.length
                if (len > 0) {
                  const str =
                    demo.preExecutionTransaction.response.responses[len - 1].body
                  const result = Buffer.from(str, 'base64').toString('ascii')
                  // [{\"0\":\"10\"}]  result 即為 [{\"0\":\"10\"}]  10即為想要的結(jié)果,即對(duì)應(yīng)nft 的余額
                  debug(result)
                }
              } catch (err) {
                console.log(err)
              }
            }
             
          • 查詢(xún)交易信息

            // 查詢(xún)交易 前端用戶(hù)選擇查詢(xún)交易,讓用戶(hù)輸入交易ID,即可,返回交易信息。目前交易信息很少
            // 查詢(xún)交易
            const GetTxDetail = async (txID) => {
              try {
                const demo = await xsdk.queryTransaction(
                  Buffer.from(txID, 'hex').toString('base64')
                )
                if (demo.tx == undefined) {
                  // 證明此交易鏈上沒(méi)有 直接報(bào)錯(cuò)
                  throw new Error('this tx undefined')
                }
                // 交易ID
                var txID = Buffer.from(demo.tx.txid, 'base64').toString('hex')
                var txReqJson = JSON.parse(
                  Buffer.from(
                    demo.tx.contract_requests[1].args.input,
                    'base64'
                  ).toString()
                )
                var from = ''
                var to = ''
                var tokenID = ''
                var amount = ''
                if (demo.tx.contract_requests[1].method_name == 'safeTransferFrom') {
                  from = EvmToXchainAddr(txReqJson.from)
                  to = EvmToXchainAddr(txReqJson.to)
                  tokenID = txReqJson.id
                  amount = txReqJson.amount
                } else {
                  from = demo.tx.initiator
                  tokenID = txReqJson._id
                  amount = txReqJson._initialSupply
                }
            
                // 根據(jù) tokenID 查詢(xún)token id的圖片路徑 供瀏覽器跳轉(zhuǎn)
                const contractName = 'opennft'
                const methodName = 'getTokenBytes'
                const args = {
                  _id: tokenID,
                }
                const res = await xsdk.invokeSolidityContarct(
                  contractName,
                  methodName,
                  'evm',
                  args,
                  '0',
                  acc
                )
                const len = res.preExecutionTransaction.response.responses.length
                if (len > 0) {
                  var result =
                    res.preExecutionTransaction.response.responses[len - 1].body
                  var response = JSON.parse(Buffer.from(result, 'base64').toString())
                  var base64Addr = response[0]._response
                  var data = Buffer.from(base64Addr, 'base64').toString()
                  var dataJson = JSON.parse(data)
                }
            
                var timestamp = parseInt(demo.tx.timestamp / 1000)
                // 用戶(hù)查看交易詳情,前端顯示下述txDetail信息。
                var txDetail = {
                  txID: txID,
                  from: from,
                  to: to,
                  id: tokenID,
                  amount: amount,
                  timestamp: timestamp,
                }
                var nftDetail = {
                  link: dataJson.link,
                  name: dataJson.name,
                  hash: dataJson.hash,
                }
                // 前端展示數(shù)據(jù)
                console.log(txDetail)
                console.log(nftDetail)
                return txDetail, nftDetail
              } catch (err) {
                console.log(err)
              }
            }
             
          • 用戶(hù)新增 action 操作。不用再首頁(yè)展示,只在第三張圖的下拉框顯示即可。用戶(hù)新增功能需要傳入?yún)?shù)較多(TODO)

            // 下述,所有參數(shù)可設(shè)置默認(rèn)值。用戶(hù)新增功能時(shí),用戶(hù)可以設(shè)置是否用戶(hù)輸入。,前端不顯示,不設(shè)置即前端需要輸入。
            
            // 需要傳入?yún)?shù)
            const contractName = '合約名'
            const method = '方法名'
            
            // 調(diào)用方法的參數(shù)。(前端可選多個(gè))
            const from ='';
            const to = '';
            ...
             
          • 切換賬號(hào)功能用戶(hù)點(diǎn)擊頭像,可以新增賬戶(hù),即新增一個(gè) acc 對(duì)象,切換賬戶(hù),即切換 acc 對(duì)象。新增賬戶(hù)也需要指定私鑰,安全碼(非必須)。(TODO)

            // TODO 需要通過(guò)用戶(hù)選擇的私鑰路徑,讀取出來(lái)私鑰的內(nèi)容
            const private = ''
            // 安全碼
            const password = ''
            // 登錄后 生成 賬戶(hù)對(duì)象
            const acc = xsdk.import(password, private)

           

          瀏覽 33
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产品黄色大片免费的 | 蜜桃无码久久久久 | 日韩黄色免费电影 | 日韩黄色真人直播 | 国产18女人水真多免费看 |