【p2p、分布式,区块链笔记 Blockchain】truffle005 调用以太坊测试网上某个地址的合约

ABI

  • ABI(Application Binary Interface,应用二进制接口)是智能合约的接口定义,它描述了智能合约的函数和事件。对于以太坊区块链,ABI 是一个 JSON 格式的对象数组,它定义了如何与已部署的智能合约进行交互。

ABI 的作用:

  1. 合约交互: 当你使用 Web3.js 或其他以太坊库与智能合约交互时,ABI 告诉库如何构造正确的交易,调用合约中的方法,或解析事件和返回值。
  2. 输入和输出定义: ABI 明确描述了合约中函数的输入参数类型、输出类型、函数名称以及函数是否改变区块链状态(即是否需要支付 Gas)。

ABI 的组成部分:

ABI 通常包括以下信息:

  • 函数签名:合约中每个函数的名称和参数类型。
  • 函数类型
    • function: 普通函数,可能是只读(不修改区块链状态)或写入(会修改状态,需要 Gas)。
    • constructor: 构造函数,用于部署合约时调用。
    • event: 事件,用于通知某些操作已发生,通常可以在交易日志中捕获。
    • fallbackreceive:回退函数,当调用合约但没有指定函数时执行。
  • 输入和输出:函数参数的类型和顺序,以及返回值的类型。
  • 状态可见性:定义函数是否是 view(只读)或 pure(纯函数,不读取或修改状态),或者是否需要 Gas。

ABI 示例:

  • 假设有一个智能合约,定义了一个 getValue() 函数和一个 setValue(uint256) 函数,它们的 ABI 可能像下面这样:
[
    {
    
    
        "constant": true,
        "inputs": [],
        "name": "getValue",
        "outputs": [
            {
    
    
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
    
    
        "constant": false,
        "inputs": [
            {
    
    
                "name": "_value",
                "type": "uint256"
            }
        ],
        "name": "setValue",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    }
]

解释:

  1. getValue 函数

    • constant: true: 表明这是一个只读函数,不会修改区块链状态(即不需要 Gas)。
    • inputs: []: 没有输入参数。
    • outputs: 返回一个 uint256 类型的值。
    • stateMutability: view: 表示它是只读的函数。
  2. setValue 函数

    • constant: false: 表明这是一个可以修改区块链状态的函数(需要 Gas)。
    • inputs: 需要一个名为 _valueuint256 类型的输入参数。
    • outputs: 没有输出。
    • stateMutability: nonpayable: 表示这个函数不会接收以太币(ETH)。

如何获取 ABI:

  • 从编译合约时生成:当你使用 Solidity 编译器(如 solc 或 Remix)编译合约时,ABI 会自动生成。
    在这里插入图片描述
  • 从区块链浏览器获取:如果合约已经部署在区块链上(如以太坊主网或测试网),你可以通过区块链浏览器(例如 Etherscan)查找合约,通常 ABI 会在合约页面中提供。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fetch Contract ABI</title>
</head>
<body>

<h1>Fetch and Display Contract ABI</h1>
<p id="abiData">Fetching ABI data...</p>

<script>
    async function main() {
    
    
        try {
    
    
            // 发起 API 请求,获取合约的 ABI,注意链接为api-sepolia.etherscan.io,和地址匹配
            const response = await fetch('https://api-sepolia.etherscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken');
            const data = await response.json();
            
            // 获取 ABI 并在页面上显示
            let abi = data.result;
            console.log(abi);
            
            // 更新 HTML 显示 ABI 数据
            document.getElementById('abiData').innerText = abi;
        } catch (error) {
    
    
            console.error('Error fetching ABI:', error);
            document.getElementById('abiData').innerText = 'Error fetching ABI';
        }
    }

    // 执行函数
    main();
</script>

</body>
</html>

在这里插入图片描述

使用 ABI:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实现代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fetch and Add User</title>
    <!-- 在浏览器环境中直接使用 <script> 标签时,需要使用预编译的 UMD(Universal Module Definition)版本,它适用于所有浏览器,而不需要模块打包工具 -->
    <!-- 所以 <script src="https://cdn.jsdelivr.net/npm/ethers/dist/ethers.min.js"></script> 会 Uncaught SyntaxError: Unexpected token 'export' (at ethers.min.js:1:498792)-->
    <!-- <script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"></script> 这个地址无法访问-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ethers/5.2.0/ethers.umd.min.js"></script>


</head>
<body>

<h1>Fetch and Add User to Smart Contract</h1>

<!-- 输入框用于输入用户ID并查询用户名 -->
<h3>Fetch User Name by ID</h3>
<label for="fetchId">Enter ID:</label>
<input type="text" id="fetchId" placeholder="Enter user ID">

<!-- 显示获取的用户名 -->
<p>Fetched User Name: <span id="fetchedName">Not fetched</span></p>

<!-- 按钮调用 get_name() 函数 -->
<button onclick="fetchName()">Fetch Name</button>

<hr>

<!-- 输入框用于添加用户的ID和Name -->
<h3>Add User</h3>
<label for="addId">Enter ID:</label>
<input type="text" id="addId" placeholder="Enter user ID">
<br><br>
<label for="addName">Enter Name:</label>
<input type="text" id="addName" placeholder="Enter user name">
<br><br>

<!-- 显示添加用户的结果 -->
<p>Add User Result: <span id="addResult">Not added</span></p>

<!-- 按钮调用 addUser() 函数 -->
<button onclick="addUser()">Add User</button>

<script>
    let signer, contract;

    async function connect() {
    
     // 请求用户连接 MetaMask 等钱包
        await window.ethereum.enable();
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        signer = provider.getSigner();
    }

    async function connectContract() {
    
    
        if (!signer) await connect();
        // 创建合约实例
        contract = new ethers.Contract(
            '0xd9145CCE52D386f254917e481eB44e9943F39138', // 合约地址
            [
		{
    
    
			"inputs": [
				{
    
    
					"internalType": "uint256",
					"name": "_id",
					"type": "uint256"
				},
				{
    
    
					"internalType": "string",
					"name": "_name",
					"type": "string"
				}
			],
			"name": "addUser",
			"outputs": [],
			"stateMutability": "nonpayable",
			"type": "function"
		},
		{
    
    
			"inputs": [
				{
    
    
					"internalType": "uint256",
					"name": "_id",
					"type": "uint256"
				}
			],
			"name": "get_name",
			"outputs": [
				{
    
    
					"internalType": "string",
					"name": "",
					"type": "string"
				}
			],
			"stateMutability": "view",
			"type": "function"
		},
		{
    
    
			"inputs": [
				{
    
    
					"internalType": "uint256",
					"name": "",
					"type": "uint256"
				}
			],
			"name": "id_of_name",
			"outputs": [
				{
    
    
					"internalType": "string",
					"name": "",
					"type": "string"
				}
			],
			"stateMutability": "view",
			"type": "function"
		},
		{
    
    
			"inputs": [
				{
    
    
					"internalType": "uint256",
					"name": "",
					"type": "uint256"
				}
			],
			"name": "users",
			"outputs": [
				{
    
    
					"internalType": "uint256",
					"name": "id",
					"type": "uint256"
				},
				{
    
    
					"internalType": "string",
					"name": "name",
					"type": "string"
				}
			],
			"stateMutability": "view",
			"type": "function"
		}
	],
            signer
        );
    }

    // 调用 get_name 函数,查询用户名
    async function fetchName() {
    
    
        const userId = document.getElementById('fetchId').value;
        
        if (!contract) await connectContract();

        try {
    
    
            const name = await contract.get_name(userId);
            document.getElementById('fetchedName').innerText = name;
        } catch (error) {
    
    
            console.error("Error fetching name:", error);
            document.getElementById('fetchedName').innerText = "Error fetching name";
        }
    }

    // 调用 addUser 函数,添加用户
    async function addUser() {
    
    
        const userId = document.getElementById('addId').value;
        const userName = document.getElementById('addName').value;
        if (!contract) await connectContract();

        try {
    
    
            const tx = await contract.addUser(userId, userName); // 提交交易
            await tx.wait(); // 等待交易完成
            document.getElementById('addResult').innerText = "User added successfully!";
        } catch (error) {
    
    
            console.error("Error adding user:", error);
            document.getElementById('addResult').innerText = "Error adding user";
        }
    }
</script>

</body>
</html>

猜你喜欢

转载自blog.csdn.net/ResumeProject/article/details/143101411