HTML+web3.js调用智能合约

7,856 阅读2分钟

前言

最近开始了解ETH的智能合约,需要提供一个前端界面供用户使用,因此学习一下这方面知识。其中主要涉及的功能也就这几个:

  • 连接钱包(MetaMask)
  • 转账
  • 调用view合约
  • 调用payable合约

MetaMask web3.js Ethereum的关系

pic1.png
Ethereum定义了一个和Ethereum节点通信的协议 JSON-RPC API
MetaMask界面上实现了协议的部分功能,比如转账,在代码上也提供了一部分协议的封装。
web3.js 用js语言封装了所有协议的请求,这部分和MetaMask提供的封装有一小部分重叠,本质上都是调用JSON-RPC。
MetaMask使用Infura作为节点提供者。 这就是为什么你不需要在电脑上安装以太坊客户端就能与以太坊网络进行交互的原因。

HelloWorld

点击 web3_clientVersion 按钮,输出 MetaMask/v9.3.0。
NOTE:这个页面需要一个简单的server运行,比如 http://localhost:8080/test.html ,直接双击网页文件浏览,无法正常运行(我用的VSCode插件里提供的Preview on Web Server)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Web3.js Test</title>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js@1.3.5/dist/web3.min.js"></script>
</head>

<body>
    <h2>Web3.js Test</h2>
    <hr />

    <div>
        <div>
            <button id="web3_clientVersion">web3_clientVersion</button>
        </div>
    </div>

    <script>
        function showResult(node, msg) {
            node.parent().append(" <span>" + msg + "</span>");
        }

        jQuery("#web3_clientVersion").click(async function () {
            result = await ethereum.request({ method: "web3_clientVersion" });
            showResult(jQuery("#web3_clientVersion"), result);
        });
    </script>
</body>

连接钱包(MetaMask)

点击按钮,会调出MetaMask的连接钱包界面,一路确认后会返回钱包地址,拒绝后会报错。

<div>
    <button id="eth_requestAccounts">eth_requestAccounts</button>
</div>

jQuery("#eth_requestAccounts").click(async function () {
    requestAccounts = await ethereum.request({ method: 'eth_requestAccounts' });
    showResult(jQuery("#eth_requestAccounts"), requestAccounts);
});

转账

建议转账这种操作,使用ethereum.request方式调用,web3需要明文填入密码

<div>
    <button id="eth_sendTransaction">eth_sendTransaction</button>
</div>

jQuery("#eth_sendTransaction").click(async function () {
    result = await ethereum.request({
        method: "eth_sendTransaction",
        params: [{
            "from": "0xffffffffffffffffffffffffffffffffffffffff",
            "to": "0x0000000000000000000000000000000000000000",
            "value": web3.utils.numberToHex(web3.utils.toWei("1", "ether")),
        }],
    });
    showResult(jQuery("#eth_sendTransaction"), result);
});

调用view合约

调用合约的方法,需要合约的abi和地址

<div>
    <button id="HegicETHPool_name">HegicETHPool_name</button>
</div>

// 读取abi.json
function makeRequest(method, url) {
    return new Promise(function (resolve, reject) {
        let xhr = new XMLHttpRequest();
        xhr.open(method, url);
        xhr.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                resolve(xhr.response);
            } else {
                reject({
                    status: this.status,
                    statusText: xhr.statusText
                });
            }
        };
        xhr.onerror = function () {
            reject({
                status: this.status,
                statusText: xhr.statusText
            });
        };
        xhr.send();
    });
}

jQuery("#HegicETHPool_name").click(async function () {
    jsonStr = await makeRequest("GET", "HegicETHPool.json");
    abi = JSON.parse(jsonStr);

    HegicETHPool = new web3.eth.Contract(abi, "0x878F15ffC8b894A1BA7647c7176E4C01f74e140b");
    name = await HegicETHPool.methods.name().call();

    showResult(jQuery("#HegicETHPool_name"), JSON.stringify(name));
});

调用payable合约

<div>
    <button id="HegicETHOptions_create">HegicETHOptions_create</button>
</div>

jQuery("#HegicETHOptions_create").click(async function () {
    jsonStr = await makeRequest("GET", "HegicETHOptions.json");
    abi = JSON.parse(jsonStr);

    HegicETHOptions = new web3.eth.Contract(abi, "0xEfC0eEAdC1132A12c9487d800112693bf49EcfA2");

    create = await HegicETHOptions.methods
        .create(24 * 3600, web3.utils.toWei("1", "ether"), web3.utils.toWei("2100", "ether"), 1)
        .send({
            "from": "0xffffffffffffffffffffffffffffffffffffffff",
            "value": web3.utils.numberToHex(web3.utils.toWei("20000", "ether"))
        });

    showResult(jQuery("#HegicETHOptions_create"), JSON.stringify(create));
});

参考文档

MetaMask文档:docs.metamask.io/guide/
web3.js:web3js.readthedocs.io/en/v1.3.4/
Ethereum Wiki:eth.wiki/json-rpc/AP…