目录

使用 solidity 开发第一个 以太坊智能合约

前言

使用 solidity 开发一个以太坊区块链的智能合约,并且使用Dapp 进行交互。

项目源代码

最终效果



环境搭建

Nodejs 和 Ganache 请自行安装,然后使用npm安装 Truffle 智能合同框架,web3js
npm install -g truffle
npm install -g web3
  • Ganache v7.9.1 个人区块链测试环境
  • Solidity - 0.8.19 (solc-js) 以太坊区块链语言
  • Node v18.14.2
  • Truffle v5.11.5 (core: 5.11.5) 智能合约开发框架
  • Web3.js v1.10.0

智能合约内容

我们要实现在智能合约中存储和检索一个字符串值 setGreeting() 设置值, getGreeting() 获取值

Truffle 创建项目


mkdir sc-demo # 创建目录 truffle init # 项目初始化

初始化项目会生成3个文件夹和一个 配置文件

  • contracts 合同文件
  • migrations 部署文件
  • test 测试文件
  • truffle-config.js 配置文件

Truffle 编码

使用命令创建合同文件,也可以手动创建
# 命令创建
truffle create contract HelloWorld
文件生成的路径
contracts/HelloWorld.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0; contract HelloWorld {
string public greeting; constructor() {
greeting = "Hello world!";
} function setGreeting(string memory _greeting) public{
greeting = _greeting;
} function getGreeting() public view returns (string memory ){
return greeting;
} }

Truffle 打包

修改区块链地址
truffle-config.js
// 地址是你个人区块链测试地址
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*" // Any network (default: none)
}
# 打包命令
truffle compile

Truffle 部署

迁移文件的命名规则
Truffle要求迁移文件遵循一定的命名规则,通常是以数字开头,后跟一个描述性名称,如1_initial_migration.js、2_deploy_contracts.js等。数字用于确保迁移按正确的顺序执行。 编写部署文件
migrations/2_deploy_contracts.js
const HelloWorld = artifacts.require("HelloWorld");

module.exports = function (deployer) {
deployer.deploy(HelloWorld);
};

修改编译器版本 0.8.19

  compilers: {
solc: {
version: "0.8.19" // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: false,
// runs: 200
// },
// evmVersion: "byzantium"
// }
}
}
# 部署命令
truffle migrate

Truffle 测试

创建测试文件

路径 contracts/test/HelloWorld.test.js
const HelloWorld = artifacts.require("HelloWorld");

contract("HelloWorld", (accounts) => {
it("should return the initial greeting", async () => {
const instance = await HelloWorld.deployed();
const greeting = await instance.getGreeting();
assert.equal(
greeting,
"Hello, World!",
"The initial greeting is not correct"
);
}); it("should set a new greeting", async () => {
const instance = await HelloWorld.deployed();
await instance.setGreeting("Hello, Truffle!");
const greeting = await instance.getGreeting();
assert.equal(
greeting,
"Hello, Truffle!",
"The new greeting is not set correctly"
);
});
});

运行测试命令

truffle test

Dapp

使用web3js 于智能合约交互,get()获取值,set()设置值
<!DOCTYPE html>
<html> <head>
<title>Simple Storage DApp</title>
</head> <body>
<h1>Simple Storage DApp</h1>
<input type="text" id="storageValue">
<button onclick="set()">Set Value</button>
<button onclick="get()">Get Value</button>
<p id="value"></p> <script src="https://cdn.jsdelivr.net/npm/web3@1.3.6/dist/web3.min.js"></script>
<script>
const web3 = new Web3(Web3.givenProvider || "http://127.0.0.1:7545");
const contractAddress = '0x0cf35631BF8B3860c0D63Fc7eB03750566023F70'; // 使用你的合约地址替换这里 // 使用你的 abi 替换这里
const contractABI = [
{
"inputs": [],
"name": "greeting",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function",
"constant": true
},
{
"inputs": [
{
"internalType": "string",
"name": "_greeting",
"type": "string"
}
],
"name": "setGreeting",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getGreeting",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function",
"constant": true
}
] // 使用你的合约ABI替换这里 const contract = new web3.eth.Contract(contractABI, contractAddress); async function set() {
const accounts = await web3.eth.getAccounts();
const value = document.getElementById('storageValue').value;
await contract.methods.setGreeting(value).send({ from: accounts[0] });
} async function get() {
const value = await contract.methods.getGreeting().call();
document.getElementById('value').innerText = value;
}
</script>
</body> </html>

命令总结

truffle init #初始化项目

truffle create contract XX #创建合同

truffle compile # 打包

truffle migrate # 部署命令

truffle console --network development # 部署完成后,你可以通过Truffle控制台与智能合约交互

truffle test # 测试

遇到的问题

注意Solidity 0.8.20

这是因为solidity 0.8.20引入了PUSH0(0x5f)操作码,该操作码仅在ETH主网上支持,而在任何其他链上都不支持。这就是为什么其他链找不到PUSH0(0x5f)操作码并抛出此错误的原因。考虑对其他链使用0.8.19。

使用-solidity-开发第一个-以太坊智能合约的更多相关文章

  1. 以太坊智能合约 Solidity 的常用数据类型介绍

    目录 目录 1.数组 1.1.对数组的增删改查操作. 2.String.Bytes.Mapping的使用 3.Enums 和 Structs 的简单应用 4.Ether 单位和 Time 单位 5.A ...

  2. 以太坊智能合约开发,Web3.js API 中文文档 ethereum web3.js入门说明

    以太坊智能合约开发,Web3.js API 中文文档 ethereum web3.js入门说明 为了让你的Ðapp运行上以太坊,一种选择是使用web3.js library提供的web3.对象.底层实 ...

  3. 以太坊智能合约介绍,Solidity介绍

    以太坊智能合约介绍,Solidity介绍 一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. Storage contract SimpleSt ...

  4. 以太坊智能合约Hello World示例程序

    简介 以太坊(Ethereum)是一提供个智能合约(smart contract)功能的公共区块链(BlockChain)平台. 本文介绍了一个简单的以太坊智能合约的开发过程. 开发环境 在以太坊上开 ...

  5. 如何通过以太坊智能合约来进行众筹(ICO)

    前面我们有两遍文章写了如何发行代币,今天我们讲一下如何使用代币来公开募资,即编写一个募资合约. 写在前面 本文所讲的代币是使用以太坊智能合约创建,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还 ...

  6. 深入以太坊智能合约 ABI

    开发 DApp 时要调用在区块链上的以太坊智能合约,就需要智能合约的 ABI.本文希望更多了解 ABI,如为什么需要 ABI?如何解读 Ethereum 的智能合约 ABI?以及如何取得合约的 ABI ...

  7. Go语言打造以太坊智能合约测试框架(level1)

    传送门: 柏链项目学院 Go语言打造以太坊智能合约测试框架 前言 这是什么? 这是一个基于go语言编写的,自动化测试以太坊智能合约的开发框架,使用此框架,可以自动化的部署合约,自动测试合约内的功能函数 ...

  8. rpc接口调用以太坊智能合约

    rpc接口调用以太坊智能合约 传送门: 柏链项目学院   在以太坊摸爬滚打有些日子了,也遇到了各种各样的问题.这几天主要研究了一下如何通过rpc接口编译.部署和调用合约.也遇到了一些困难和问题,下面将 ...

  9. Go语言打造以太坊智能合约测试框架(level3)

    传送门: 柏链项目学院 第三课 智能合约自动化测试 之前课程回顾 我们之前介绍了go语言调用exec处理命令行,介绍了toml配置文件的处理,以及awk处理文本文件获得ABI信息.我们的代码算是完成了 ...

  10. 使用web3.js监听以太坊智能合约event

    传送门: 柏链项目学院 使用web3.js监听以太坊智能合约event   当我们在前端页面调用合约时发现有些数据不会立即返回,这时还需要再调用更新数据的函数.那么这样的方法使用起来非常不便,监听ev ...

随机推荐

  1. 最佳实践:解读GaussDB(DWS) 统计信息自动收集方案

    摘要:现在商用优化器大多都是基于统计信息进行查询代价评估,因此统计信息是否实时且准确对查询影响很大,特别是分布式数据库场景.本文详细介绍GaussDB(DWS)如何实现了一种轻量.实时.准确的统计信息 ...

  2. kubernetes中集成istio出现拉取配置中心数据失败导致服务启动失败 荐

    由于在k8s使用了grpc,所以这里我们集成istio来实现http2的自动发现以及负载均衡,但是随着节点增加,istio之前同步配置时间边长导致第一次启动时,服务启动拉取配置时istio却还没初始化 ...

  3. 使用 prefetchComponents 进行组件预取

    title: 使用 prefetchComponents 进行组件预取 date: 2024/8/17 updated: 2024/8/17 author: cmdragon excerpt: 摘要: ...

  4. 如何诱导AI犯罪-提示词注入

    我们用到的大模型基本把政治类信息.犯罪相关信息都已屏蔽.但是,黑客依旧可以使用提示词诱导和提示词注入的方式对大模型进行攻击. 1.提示词诱导 如果直接让AI提供犯罪过程,AI会直接拒绝.虽然AI对于大 ...

  5. zabbix 应用框架分析

    本文通过源码分析,探究zabbix web应用的整体架构,所有分析基于zabbix 3.0.10进行. 总体而言,zabbix web应用使用PHP开发,大量应用OOP方法,主要采用mvc架构,同时包 ...

  6. 中考游记 & 暑假集训大记

    中考游记 & 暑假集训大记 前言 如今已经回归 \(OI\) ,望着如烟的往事,或是将将知道的讯息,心中早是凄然. 我真的希望这世间有我所期望的浦岛隧道,带回所有的遗憾,同时带走迷茫与害怕,重 ...

  7. Java并发之原子变量及CAS算法-上篇

    Java并发之原子变量及CAS算法-上篇   概述 本文主要讲在Java并发编程的时候,如果保证变量的原子性,在JDK提供的类中式怎么保证变量原子性的呢?.对应Java中的包是:java.util.c ...

  8. Spring:基于注解管理bean

    标记与扫描 注解 和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测 到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作. 本质上:所有一切 ...

  9. C++ 指针基础

    指针 指针具有强大的能力,其本质是协助程序员完成内存的直接操作 指针: 特定类型数据在内存中的存储地址,即内存地址 指针只是一个逻辑概念,其实际应用是:指针变量 语法 * 符号有两种含义: 声明时:* ...

  10. 如何判断一个网站是用的Nginx,还是Apache

    事件起因: 接手了同事移交过来的一个网站,但是不知道这个网站是用什么做代理的,于是就去网上查资料   解决办法: 打开cmd窗口,输入以下命令即可 curl --head 域名/IP 注意,--hea ...