【区块链】JavaScript连接web3钱包,实现测试网络中的 Sepolia ETH余额查询、转账功能

news2024/11/20 1:35:16

审核看清楚了 ! 这是以太坊测试网络!用于学习的测试网络!!! 有关web3 和区块链的内容为什么要给我审核不通过? 别人凭什么可以发!

目标成果:

实现功能分析:

  1. 显示账户信息,地址、chainID、网络ID、余额
  2. 实现转账功能

需要准备的事情:

  1. 一个有sepolia ETH余额的web3账户,没有可以找水龙头领取或者某鱼购买
  2. 浏览器插件安装了 MetaMask钱包插件(小狐狸钱包)
  3. 准备一个web容器,我这边使用的是nginx

操作环节:

先写出网页大概的内容布局;

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>js连接web3钱包</title>
  </head>
  <body>
    <div>
      <div><h3>详情信息</h3></div>

      <div>
          <div>
            <label>账户地址:<span></span></label>
          </div>
          <div>
            <label>ChainID:<span></span></label>
          </div>
          <div>
            <label>网络ID:<span></span></label>
          </div>
          <div>
            <label>余额:<span></span></label>
          </div>
      </div>

      <div>
        <button>转账</button>
      </div>
    </div>


    <div>
      <label>对手地址<input type="text"></label>
      <br>
      <label>ETH数量<input type="text"></label>
      <br>
      <button>确定</button>
      <button>取消</button>
    </div>



  </body>
</html>

接下来是写js部分

把大概的框架都写出来:

//判断浏览器是否具备MetaMask环境
      const initialize = async ()=>{
        if(!isMetaMaskInstalled()){
          //如果没安装弹出窗口
          alert("请先安装 MetaMask");
        }else{
          await getNetwork(); //获取网络
          await getChainId(); //获取链
          await getAccount(); //获取账户地址
          await getBalance(); //获取余额
        }
      }

在上面这个initialize()方法中,里面我们调用了5个方法,每个方法都有其各自的作用.

方法作用
isMetaMaskInstalled()用来判断浏览器是否安装了MetaMask钱包
getNetwork()获取网络号
getChainId()获取链ID
getAccount()获取账户地址
getBalance()获取账户余额

现在开始着手写这几个方法

  • 判断是否安装
      const isMetaMaskInstalled = () => {
        const { ethereum } = window;
        return Boolean(ethereum && ethereum.isMetaMask);
      }
  • 获取网络号然然后渲染到html页面上

html部分要要加上 对应的id进行innerHTML

<div>
            <label>账户地址:<span id="accountSpan"></span></label>
          </div>
          <div>
            <label>ChainID:<span id="ChainIdSpan"></span></label>
          </div>
          <div>
            <label>网络ID:<span id="NetworkSpan"></span></label>
          </div>
          <div>
            <label>余额:<span id="BalanceSpan"></span></label>
          </div>

js部分

 const getNetwork = async () => {
        try {
          const networkId = await ethereum.request({ method: 'net_version' });
          NetworkSpan.innerHTML = networkId;
        } catch (error) {
          console.error(error);
        }
      }

      const getChainId = async () => {
        try {
          const chainId = await ethereum.request({ method: 'eth_chainId' });
          ChainIdSpan.innerHTML = chainId;
        } catch (error) {
          console.error(error);
        }
      }


      const getAccount = async () => {
        try {
          const accounts = await ethereum.request({ method: 'eth_requestAccounts' });//调用这个方法会弹出MetaMask的一个授权窗口
          accountSpan.innerHTML = accounts[0]; // 显示连接第一个账户
        } catch (error) {
          console.error(error);
        }
      }

      const getBalance = async () => {
        const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
        const balance = await ethereum.request({
          method: 'eth_getBalance',
          params: [accounts[0], 'latest']
        });
        userBalance = parseInt(balance, 16);
        const ethBalance = Web3.utils.fromWei(balance, 'ether');//这里要引入一个web3.js文件
        BalanceSpan.innerHTML = `${ethBalance} ETH`;
      }
      
      window.addEventListener('DOMContentLoaded', initialize);//进入网页后自动调用initialize方法,不调用就无法查询和渲染页面

还要引入一个web3.js用于单位转换(其实我们也可以自己计算)

    <script src="https://cdn.jsdelivr.net/npm/web3@1.6.0/dist/web3.min.js"></script>

现在已经完成显示账户信息的功能了!

接下来我们要实现我们的转账功能.,代码如下(还没有美化的版本)

     <!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>js连接web3钱包</title>
    <style>
      #transferModal {
        display: none;
        position: fixed;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        background-color: white;
        padding: 20px;
        box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
      }
    </style>
  </head>
  <body>
    <div>
      <div><h3>详情信息</h3></div>
      <div>
        <div>
          <label>账户地址:<span id="accountSpan"></span></label>
        </div>
        <div>
          <label>ChainID:<span id="ChainIdSpan"></span></label>
        </div>
        <div>
          <label>网络ID:<span id="NetworkSpan"></span></label>
        </div>
        <div>
          <label>余额:<span id="BalanceSpan"></span></label>
        </div>
      </div>
      <div>
        <button id="sendButton">转账</button>
      </div>
    </div>

    <div id="transferModal">
      <label>对手地址<input type="text" id="recipientAddress"></label>
      <br>
      <label>ETH数量<input type="text" id="ethAmount" required min="0" step="0.0001"></label>
      <br>
      <button id="confirmTransferButton" type="submit">确定</button>
      <button id="cancelTransferButton">取消</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/web3@1.6.0/dist/web3.min.js"></script>
    <script>
      //判断浏览器是否具备MetaMask环境
      const initialize = async () => {
        if (!isMetaMaskInstalled()) {
          //如果没安装弹出窗口
          alert("请先安装 MetaMask");
        } else {
          await getNetwork(); //获取网络
          await getChainId(); //获取链
          await getAccount(); //获取账户地址
          await getBalance(); //获取余额
        }
      }

      //判断是否安装
      const isMetaMaskInstalled = () => {
        const { ethereum } = window;
        return Boolean(ethereum && ethereum.isMetaMask);
      }

      const getNetwork = async () => {
        try {
          const networkId = await ethereum.request({ method: 'net_version' });
          NetworkSpan.innerHTML = networkId;
        } catch (error) {
          console.error(error);
        }
      }

      const getChainId = async () => {
        try {
          const chainId = await ethereum.request({ method: 'eth_chainId' });
          ChainIdSpan.innerHTML = chainId;
        } catch (error) {
          console.error(error);
        }
      }

      const getAccount = async () => {
        try {
          const accounts = await ethereum.request({ method: 'eth_requestAccounts' });//调用这个方法会弹出MetaMask的一个授权窗口
          accountSpan.innerHTML = accounts[0]; // 显示连接第一个账户
        } catch (error) {
          console.error(error);
        }
      }

      const getBalance = async () => {
        const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
        const balance = await ethereum.request({
          method: 'eth_getBalance',
          params: [accounts[0], 'latest']
        });
        userBalance = parseInt(balance, 16);
        const ethBalance = Web3.utils.fromWei(balance, 'ether');//这里要引入一个web3.js文件
        BalanceSpan.innerHTML = `${ethBalance} ETH`;
      }

      //获取最新的gas prices
      const getGasPrice = async () => {
        const web3 = new Web3(Web3.givenProvider);
        const gasPrice = await web3.eth.getGasPrice();
        console.log('Current gas prices => ' + gasPrice);
        return gasPrice;
      }

      // 显示和隐藏转账模态窗口
      const sendButton = document.getElementById('sendButton');
      const transferModal = document.getElementById('transferModal');
      const confirmTransferButton = document.getElementById('confirmTransferButton');
      const cancelTransferButton = document.getElementById('cancelTransferButton');

      sendButton.addEventListener('click', () => {
        transferModal.style.display = 'block';
      });

      cancelTransferButton.addEventListener('click', () => {
        transferModal.style.display = 'none';
      });

      // 处理转账逻辑
      confirmTransferButton.addEventListener('click', async () => {
        const recipientAddress = document.getElementById('recipientAddress').value;
        const ethAmount = document.getElementById('ethAmount').value;

        if (!recipientAddress || !ethAmount) {
          alert('请填写所有字段');
          return;
        }

        try {
          const web3 = new Web3(Web3.givenProvider);
          const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
          const senderAddress = accounts[0];

          const transactionParameters = {
            to: recipientAddress,
            from: senderAddress,
            value: web3.utils.toHex(web3.utils.toWei(ethAmount, 'ether')),
            gasPrice: await getGasPrice(),
            gas: '21000', // 默认的gas limit
          };

          await ethereum.request({
            method: 'eth_sendTransaction',
            params: [transactionParameters],
          });

          alert('转账成功');
          transferModal.style.display = 'none';
          await getBalance(); // 更新余额
        } catch (error) {
          console.error(error);
          alert('转账失败');
        }
      });

      // 切换账户的时候触发
      ethereum.on('accountsChanged', function (accounts) {
        console.log('账户已切换');
        window.location.reload();
      });

      // 切换网络的时候触发
      ethereum.on('chainChanged', function (accounts) {
        console.log('网络已切换');
        window.location.reload();
      });

      window.addEventListener('DOMContentLoaded', initialize);
    </script>
  </body>
</html>

结果:

完成转账功能

这样就可以完成转账功能了!

美化 二选一 bootstrap or layui.

  • 使用bootstrap 美化一下

code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Web3 钱包</title>    
    <link rel="icon" href="http://u5a.cn/uftiP" type="image/x-icon"></link>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.6.0/css/brands.min.css" rel="stylesheet">
    <style>
      body {
        background-color: #f8f9fa;
      }
      .wallet-info {
        margin-top: 20px;
      }
      .wallet-info label {
        font-weight: bold;
      }
      .wallet-info span {
        font-style: italic;
      }
      .navbar-brand {
        font-weight: bold;
      }
      .copy-icon {
        cursor: pointer;
        margin-left: 10px;
        color: #007bff;
      }
      .copy-icon:hover {
        color: #0056b3;
      }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-expand-sm navbar-light bg-light">
      <div class="container-fluid">
        <span class="navbar-brand">币圈老韭菜</span>
      </div>
    </nav>
    <div class="container wallet-info">
      <div>
        <h3>详情信息</h3>
      </div>
      <div>
        <div class="row">
          <div class="col-md-6 mb-3">
            <label>账户地址:</label>
            <span id="accountSpan"></span>
            <i class="fas fa-copy copy-icon" onclick="copyAddress()"></i>
          </div>
          <div class="col-md-6 mb-3">
            <label>Chain:</label>
            <span id="NetworkSpan"></span>
          </div>
        </div>
        <div class="row">
          <div class="col-md-6 mb-3">
            <label>链ID:</label>
            <span id="ChainIdSpan"></span>
          </div>
          <div class="col-md-6 mb-3">
            <label>余额:</label>
            <span id="BalanceSpan"></span>
          </div>
        </div>
      </div>
      <div>
        <button class="btn btn-primary" id="sendButton">转账</button>
      </div>
    </div>

    <!-- 转账表单模态框 -->
    <div class="modal fade" id="transferModal" tabindex="-1" aria-labelledby="transferModalLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="transferModalLabel">转账</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <form id="transferForm">
              <div class="mb-3">
                <label for="recipientAddress" class="form-label">转账地址</label>
                <input type="text" class="form-control" id="recipientAddress" required>
              </div>
              <div class="mb-3">
                <label for="ethAmount" class="form-label">ETH 数量</label>
                <input type="number" class="form-control" id="ethAmount" required min="0" step="0.0001">
              </div>
              <button type="submit" class="btn btn-primary">确定转账</button>
            </form>
          </div>
        </div>
      </div>
    </div>

   
    <script src="https://cdn.jsdelivr.net/npm/web3@1.6.0/dist/web3.min.js"></script>
    <script>
      let userBalance = 0;

      // 初始化
      const initialize = () => {
        checkMetaMaskClient();
      }

      // 如果安装了小狐狸才可以获取信息
      const checkMetaMaskClient = async () => {
        if (!isMetaMaskInstalled()) {
          alert("请安装 MetaMask");
        } else {
          await getNetworkAndChainId(); // 获取网络ID
          await getAccount(); // 使用 eth_requestAccounts 获取账户
          await getBalance(); // 使用 eth_getBalance 获取余额
        }
      }

      // 验证是不是安装了
      const isMetaMaskInstalled = () => {
        const { ethereum } = window;
        return Boolean(ethereum && ethereum.isMetaMask);
      }

      const getAccount = async () => {
        try {
          const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
          accountSpan.innerHTML = accounts[0]; // 显示第一个账户
        } catch (error) {
          console.error(error);
        }
      }

      const getNetworkAndChainId = async () => {
        try {
          const chainId = await ethereum.request({ method: 'eth_chainId' });
          ChainIdSpan.innerHTML = chainId;
          const networkId = await ethereum.request({ method: 'net_version' });
          NetworkSpan.innerHTML = networkId;
        } catch (error) {
          console.error(error);
        }
      }

      const getBalance = async () => {
        const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
        const balance = await ethereum.request({
          method: 'eth_getBalance',
          params: [accounts[0], 'latest']
        });
        userBalance = parseInt(balance, 16);
        const ethBalance = Web3.utils.fromWei(balance, 'ether');
        BalanceSpan.innerHTML = `${ethBalance} ETH`;
      }

      const getGasPrice = async () => {
        const web3 = new Web3(Web3.givenProvider);
        const gasPrice = await web3.eth.getGasPrice();
        console.log('Current gas prices =>'+gasPrice);
        return gasPrice;
      }

      // 事件触发
      // 点击转账按钮的时候触发
      document.getElementById('sendButton').onclick = () => {
        // 打开模态框
        new bootstrap.Modal(document.getElementById('transferModal')).show();
      }

      // 提交转账表单
      document.getElementById('transferForm').onsubmit = async (e) => {
        e.preventDefault();
        const recipientAddress = document.getElementById('recipientAddress').value;
        const ethAmount = parseFloat(document.getElementById('ethAmount').value);
        const weiAmount = Web3.utils.toWei(ethAmount.toString(), 'ether');

        if (weiAmount <= 0) {
          alert('ETH 数量必须大于 0');
          return;
        }

        if (weiAmount > userBalance) {
          alert('余额不足');
          return;
        }

        const gasPrice = await getGasPrice();
        const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
        const params = [{
          from: accounts[0],
          to: recipientAddress,
          value: Web3.utils.toHex(weiAmount),
          gas: '0x5208', // 21000 gas 的十六进制
          gasPrice: Web3.utils.toHex(gasPrice), // 当前网络 gas price
        }];
        try {
          await ethereum.request({
            method: 'eth_sendTransaction',
            params: params,
          });
          alert('转账成功');
        } catch (error) {
          console.error(error);
          alert('转账失败');
        }
      }

      // 一键复制地址功能
      const copyAddress = () => {
        const address = document.getElementById('accountSpan').textContent;
        navigator.clipboard.writeText(address).then(() => {
          alert('地址已复制');
        }).catch(err => {
          console.error('无法复制地址', err);
        });
      }

      // 切换账户的时候触发
      ethereum.on('accountsChanged', function (accounts) {
        console.log('账户已切换');
        window.location.reload();
      });

      // 切换网络的时候触发
      ethereum.on('chainChanged', function (accounts) {
        console.log('网络已切换');
        window.location.reload();
      });

      window.addEventListener('DOMContentLoaded', initialize);
    </script>

    <script src="https://cdn.staticfile.net/popper.js/2.11.8/umd/popper.min.js"></script> 
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/js/bootstrap.min.js"></script>
    <script src="https://cdn.staticfile.net/font-awesome/6.5.1/js/all.min.js"></script>
  </body>
</html>
  • 使用layui美化的效果 (感觉做的还是太丑了)

code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>js连接web3钱包</title>
    <link rel="stylesheet" href="https://cdn.staticfile.net/layui/2.9.4/css/layui.min.css" rel="stylesheet">
    <style>
      body {
        font-size: 16px;
      }
      .layui-container {
        margin-top: 20px;
      }
      .layui-col-md4 {
        padding: 10px 0;
      }
      #transferModal {
        display: none;
        position: fixed;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        background-color: white;
        padding: 20px;
        box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
        font-size: 16px;
      }
      .layui-form-label {
        width: 100px;
      }
    </style>
  </head>
  <body>
    <div class="layui-container">
      <div><h3>详情信息</h3></div>
      <div class="layui-row layui-col-space10">
        <div class="layui-col-md6">
          <label>账户地址:<span id="accountSpan" class="layui-badge"></span></label>
        </div>
        <div class="layui-col-md6">
          <label>ChainID:<span id="ChainIdSpan" class="layui-badge layui-bg-blue"></span></label>
        </div>
        <div class="layui-col-md6">
          <label>网络ID:<span id="NetworkSpan" class="layui-badge layui-bg-green"></span></label>
        </div>
        <div class="layui-col-md6">
          <label>余额:<span id="BalanceSpan" class="layui-badge layui-bg-orange"></span></label>
        </div>
      </div>
      <div>
        <button id="sendButton" class="layui-btn layui-btn-normal">转账</button>
      </div>
    </div>

    <div id="transferModal" class="layui-card">
      <div class="layui-card-header">转账</div>
      <div class="layui-card-body">
        <div class="layui-form-item">
          <label class="layui-form-label">对手地址</label>
          <div class="layui-input-block">
            <input type="text" id="recipientAddress" class="layui-input" required>
          </div>
        </div>
        <div class="layui-form-item">
          <label class="layui-form-label">ETH数量</label>
          <div class="layui-input-block">
            <input type="text" id="ethAmount" class="layui-input" required min="0" step="0.0001">
          </div>
        </div>
        <div class="layui-form-item">
          <div class="layui-input-block">
            <button id="confirmTransferButton" class="layui-btn" type="submit">确定</button>
            <button id="cancelTransferButton" class="layui-btn layui-btn-primary">取消</button>
          </div>
        </div>
      </div>
    </div>

    <script src="https://cdn.staticfile.net/layui/2.9.4/layui.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/web3@1.6.0/dist/web3.min.js"></script>
    <script>
      layui.use(['layer', 'form'], function(){
        const layer = layui.layer;
        const form = layui.form;

        //判断浏览器是否具备MetaMask环境
        const initialize = async () => {
          if (!isMetaMaskInstalled()) {
            //如果没安装弹出窗口
            layer.alert("请先安装 MetaMask");
          } else {
            await getNetwork(); //获取网络
            await getChainId(); //获取链
            await getAccount(); //获取账户地址
            await getBalance(); //获取余额
          }
        }

        //判断是否安装
        const isMetaMaskInstalled = () => {
          const { ethereum } = window;
          return Boolean(ethereum && ethereum.isMetaMask);
        }

        const getNetwork = async () => {
          try {
            const networkId = await ethereum.request({ method: 'net_version' });
            NetworkSpan.innerHTML = networkId;
          } catch (error) {
            console.error(error);
          }
        }

        const getChainId = async () => {
          try {
            const chainId = await ethereum.request({ method: 'eth_chainId' });
            ChainIdSpan.innerHTML = chainId;
          } catch (error) {
            console.error(error);
          }
        }

        const getAccount = async () => {
          try {
            const accounts = await ethereum.request({ method: 'eth_requestAccounts' });//调用这个方法会弹出MetaMask的一个授权窗口
            accountSpan.innerHTML = accounts[0]; // 显示连接第一个账户
          } catch (error) {
            console.error(error);
          }
        }

        const getBalance = async () => {
          const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
          const balance = await ethereum.request({
            method: 'eth_getBalance',
            params: [accounts[0], 'latest']
          });
          userBalance = parseInt(balance, 16);
          const ethBalance = Web3.utils.fromWei(balance, 'ether');//这里要引入一个web3.js文件
          BalanceSpan.innerHTML = `${ethBalance} ETH`;
        }

        //获取最新的gas prices
        const getGasPrice = async () => {
          const web3 = new Web3(Web3.givenProvider);
          const gasPrice = await web3.eth.getGasPrice();
          console.log('Current gas prices => ' + gasPrice);
          return gasPrice;
        }

        // 显示和隐藏转账模态窗口
        const sendButton = document.getElementById('sendButton');
        const transferModal = document.getElementById('transferModal');
        const confirmTransferButton = document.getElementById('confirmTransferButton');
        const cancelTransferButton = document.getElementById('cancelTransferButton');

        sendButton.addEventListener('click', () => {
          transferModal.style.display = 'block';
        });

        cancelTransferButton.addEventListener('click', () => {
          transferModal.style.display = 'none';
        });

        // 处理转账逻辑
        confirmTransferButton.addEventListener('click', async () => {
          const recipientAddress = document.getElementById('recipientAddress').value;
          const ethAmount = document.getElementById('ethAmount').value;

          if (!recipientAddress || !ethAmount) {
            layer.alert('请填写所有字段');
            return;
          }

          try {
            const web3 = new Web3(Web3.givenProvider);
            const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
            const senderAddress = accounts[0];

            const transactionParameters = {
              to: recipientAddress,
              from: senderAddress,
              value: web3.utils.toHex(web3.utils.toWei(ethAmount, 'ether')),
              gasPrice: await getGasPrice(),
              gas: '21000', // 默认的gas limit
            };

            await ethereum.request({
              method: 'eth_sendTransaction',
              params: [transactionParameters],
            });

            layer.alert('转账成功');
            transferModal.style.display = 'none';
            await getBalance(); // 更新余额
          } catch (error) {
            console.error(error);
            layer.alert('转账失败');
          }
        });

        // 切换账户的时候触发
        ethereum.on('accountsChanged', function (accounts) {
          console.log('账户已切换');
          window.location.reload();
        });

        // 切换网络的时候触发
        ethereum.on('chainChanged', function (accounts) {
          console.log('网络已切换');
          window.location.reload();
        });

        window.addEventListener('DOMContentLoaded', initialize);
      });
    </script>
  </body>
</html>

展望:

后续还会添加切换账户\网络\加入代币\选择转账的币种\转账的历史记录

小结:

关于gas

  1. Gas Price(Gas 价格)
    • 表示为 gwei(1 gwei = 10^-9 ETH),wei是以太坊的最小单位。
    • 用户可以设定他们愿意支付的 gas 价格。Gas 价格越高,交易被矿工处理的速度可能越快,因为矿工更倾向于处理 gas 价格较高的交易以获得更多的报酬。
  2. Gas Limit(Gas 限额)
    • 用户愿意为一个特定交易支付的最大 gas 数量。
    • 防止意外消耗过多的 gas 资源。
  3. Transaction Fee(交易费用)
    • 计算方式:Gas Price * Gas Used
    • 例如,如果 gas 价格是 20 gwei,并且交易消耗了 21,000 gas,那么交易费用将是 20 gwei * 21,000 = 420,000 gwei,大约等于 0.00042 ETH

Gas 的作用

  1. 防止滥用
    • 每个操作都需要支付 gas,防止用户随意发起大量计算资源消耗的操作,确保网络的安全性和稳定性。
  2. 奖励矿工
    • 矿工通过处理交易获得 gas 费用作为奖励,激励他们维护网络。
  3. 确保执行
    • 确保用户为执行智能合约或其他操作付费,智能合约的复杂度越高,所需的 gas 就越多。

功能描述

1. MetaMask 环境检测
  • 功能:检查浏览器是否安装了 MetaMask 插件。
  • 实现:通过 isMetaMaskInstalled 函数检测 ethereum 对象及其 isMetaMask 属性。
2. 获取网络信息
  • 功能:获取并显示当前网络的 Network ID 和 Chain ID。
  • 实现:通过调用 MetaMask 提供的 ethereum.request({ method: 'net_version' })ethereum.request({ method: 'eth_chainId' }) 获取 Network ID 和 Chain ID。
3. 获取账户信息
  • 功能:获取并显示连接的以太坊账户地址。
  • 实现:通过调用 MetaMask 提供的 ethereum.request({ method: 'eth_requestAccounts' }) 获取账户地址,并显示在页面上。
4. 获取账户余额
  • 功能:获取并显示当前账户的 ETH 余额。
  • 实现:通过调用 MetaMask 提供的 ethereum.request({ method: 'eth_getBalance', params: [accounts[0], 'latest'] }) 获取余额,并转换为 ETH 后显示在页面上。
5. 转账功能
  • 功能:用户可以通过输入对手地址和 ETH 数量来进行转账操作。
  • 实现
    • 提供一个按钮用于显示转账模态窗口。
    • 模态窗口中有输入框用于输入对手地址和转账数量。
    • 点击确定按钮后,调用 MetaMask 提供的 ethereum.request({ method: 'eth_sendTransaction', params: [transactionParameters] }) 完成转账。
6. 实时更新
  • 功能:当账户或网络发生变化时,页面会自动刷新。
  • 实现:通过 ethereum.on('accountsChanged')ethereum.on('chainChanged') 事件监听账户和网络变化,并刷新页面以更新显示的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1954969.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CORS-跨域资源共享

CORS-跨域资源共享 什么是CORS &#xff1f; 在前后端分离的项目中&#xff0c;我们往往会遇到跨域问题。 跨域问题只会出现在浏览器发起AJAX&#xff08;XMLHttpRequest、Fetch&#xff09;请求的时候&#xff0c;因为浏览器限制了AJAX只能从同一个源请求资源&#xff0c;除…

DeadSec CTF 2024 Misc Writeup

文章目录 MiscWelcomeMic checkflag_injectionGoLPartyMAN in the middleForgotten Password CryptoFlag killer 好久没做这么爽了噜 DK盾云服务器&#xff1a; https://www.dkdun.cn/ 最近活动是香港的1-1-3 9.9/月 Misc Welcome 进discord群签到即可 Mic check 就是他说…

echarts所遇到的问题,个人记录

TreeMap 矩形树图&#xff0c;label设置富文本之后&#xff0c;无法垂直居中 font-size 支持rem&#xff0c;其余不支持 font-size 支持 rem&#xff0c;但是其余的属性如height&#xff0c;width等不支持 echarts-for-react 绑定事件&#xff0c;会覆盖实例上绑定的 当给cha…

通过服务端注入的广告被拦截 YouTube现在可能会出现黑屏静音视频段

为避免用户使用广告拦截程序直接拦截 YouTube 平台的所有广告&#xff0c;这段时间谷歌正在采取各种措施与社区进行技术对抗&#xff0c;即谷歌不停地开发新的广告检测方式阻止用户使用广告拦截程序&#xff0c;广告拦截程序则不停地开发应对方法用来继续屏蔽广告和各种提示。 …

uni-app全局文件与常用API

文章目录 rpx响应式单位import导入css样式及scss变量用法与static目录import导入css样式uni.scss变量用法 pages.json页面路由globalStyle的属性pages设置页面路径及窗口表现tabBar设置底部菜单选项及iconfont图标 vite.config中安装插件unplugin-auto-import自动导入vue和unia…

AJAX(2)——URL

URL 什么是URL&#xff1f; 定义&#xff1a;统一资源定位符&#xff0c;缩写&#xff1a;URL&#xff0c;或称统一资源定位器、定位地址&#xff0c;URL地址,俗称网页地址&#xff0c;简称网址&#xff0c;是因特网上标准的资源的地址。 概念&#xff1a;URL就是统一资源定…

Linux下C++动态链接库的生成以及使用

目录 一.前言二.生成动态链接库三.使用动态链接库 一.前言 这篇文章简单讨论一下Linux下如何使用gcc/g生成和使用C动态链接库&#xff08;.so文件&#xff09;。 二.生成动态链接库 先看下目录结构 然后看下代码 //demo.h#ifndef DEMO_H #define DEMO_H#include<string&…

【C++】C++应用案例-检验幻方

“幻方”是数学上一个有趣的问题&#xff0c;它让一组不同的数字构成一个方阵&#xff0c;并且每行、每列、每个对角线的所有数之和相等。比如最简单的三阶幻方&#xff0c;就是把1~9的数字填到九宫格里&#xff0c;要求横看、竖看、斜着看和都是15。 口诀&#xff1a;二四为肩…

Pip换源实战指南:加速你的Python开发

1. Pip换源的重要性 在使用Python进行软件开发或数据分析时&#xff0c;pip 是Python的包管理工具&#xff0c;用于安装和管理第三方库。然而&#xff0c;由于网络环境的差异&#xff0c;特别是在某些国家&#xff0c;访问默认的PyPI&#xff08;Python Package Index&#xff…

debain12中安装mysql8

本文安装使用的官方deb&#xff0c;最新的官方安装包地址&#xff1a;https://repo.mysql.com/mysql-apt-config_0.8.29-1_all.deb 前期准备&#xff1a; 1.安装了debain12.6的虚拟机&#xff0c;我是用的virtualBox安装的12.6 Edu的镜像&#xff1b; 开始安装&#xff1a; …

微服务的入门

带着问题进行学习&#xff1a; 1. 对服务进行拆分后&#xff0c;物理上是隔离的&#xff0c;数据上也是隔离的&#xff0c;如何进行不同服务之间进行访问呢&#xff1f; 2.前端是怎么样向后端发送请求的&#xff1f; 通过http请求&#xff0c;通过url&#xff0c;请求的…

最新版Golang pprof使用(引入、抓取、分析,图文结合)

最新版Golang pprof使用 &#x1f525;具体实践: Go调试神器pprof使用教程Golang线上内存爆掉问题排查&#xff08;pprof&#xff09; Github地址:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-pprof 引入pprof:import _ “net/http/pprof” …

python 查询机器python、gpu、安装包等环境版本信息

checkenv.py """Check environment configurations and dependency versions."""import importlib import os import resource import subprocess import sys from collections import OrderedDict, defaultdictimport torch# 查询自己想要的包…

【开源】一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。

基于 LLM 大语言模型的知识库问答系统 基于大语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;的知识库问答系统是一种利用先进的自然语言处理技术来理解用户查询并从知识库中检索出准确答案的系统。这里的LLM指的是能够处理和理解大量文本数据的人工智能…

【Go - 如何查看类型,运行前/运行时】

方式1 - 运行时查看 在Go中&#xff0c;你可以使用reflect.TypeOf()函数来获取变量的类型。这需要导入reflect包。以下是个示例&#xff0c;在运行时打印变量的类型&#xff1a; package mainimport ("context""fmt""reflect""go.mongodb…

精通推荐算法13:图神经网络之GraphSAGE

1 引言 近年来&#xff0c;图神经网络&#xff08;Graph Neural Networks&#xff0c;GNN&#xff09;在NLP、风控和推荐系统等领域的研究十分火热&#xff0c;其对推荐系统、生物医药、社交网络和知识图谱等非结构化数据有十分优秀的处理能力。基于图神经网络的Embedding表征…

用户登录安全是如何保证的?如何保证用户账号、密码安全?

1.HTTP协议直接传输密码&#xff08;无加密&#xff09; 前端 直接发送HTTP请求&#xff08;无加密&#xff09;&#xff0c;攻击者可直接捕获网络包&#xff0c;看到下面的明文信息 因此&#xff0c;使用HTTP协议传输会直接暴露用户敏感信息。 2.HTTPS协议直接传输密码&…

windows环境 python + opencv 加载 onnx 人脸检测模型识别人脸测试

参考博客&#xff1a; 1. OpenCV-Python 4.5.4 人脸识别应用&#xff1a;https://blog.csdn.net/qq_36563273/article/details/121510440( 代码就是在此博客代码基础上改的&#xff0c;主要添加了人脸画框的逻辑 ) 1. windows环境&#xff1a;win11 2. 安装 miniconda2-4.7.1…

用python解释进程与协程(python实例二十八)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.创建进程池&#xff0c;异步执行多个任务 3.1 代码构思 3.2 代码示例 3.3 运行结果 4. 模拟协程堵塞 4.1 代码构思 4.2 代码示例 4.3 运行结果 5.总结 1.认识Python Python 是一个高…

算法019:x的平方根

x的平方根. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/sqrtx/ 这个题乍一看很奇怪&#xff0c;但是换个角度&#xff0c;我们用二分查找的思想来完成这个题。 …