目录

使用 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. win10开启窗口左右分屏方法

    首先进入导航栏(等同于按下win徽标): 之后点击电源键上的"设置": 进入"系统" 左边一栏里点击"多任务处理" 打开"贴靠窗囗 ...

  2. redis集群主从之读写分离

    redis集群主从之读写分离 1.集群部署 这里就不详细赘述如何部署主从集群了,一般都是使用slaveOf配置来进行初始化配置. 2.与springboot集成实现读写分离 通过注解实现调用层读写分离 ...

  3. 【YashanDB知识库】statement级别的触发器在jdbc接口调用executeBatch时被多次触发

    问题现象 某客户使用jdbc接口向yashandb的表A插入数据. 表A上有一个语句级触发器,其内容为在触发时执行alter sequence操作:另外还有一个insert时的行级触发器,其内容为将每 ...

  4. 【YashanDB知识库】使用select * 创建的物化视图无法进行查询重写

    问题现象 使用如下语句准备测试数据: alter system set query_rewrite_enabled=force scope=both; drop table test; create ...

  5. spark 解析 kafka message

    备用 https://databricks.com/blog/2018/11/30/apache-avro-as-a-built-in-data-source-in-apache-spark-2-4. ...

  6. C++ weak_ptr除了解决循环引用还能做什么?

    C++: weak_ptr到底有什么用? 很多人对std::weak_ptr的认识只是不增加std::shared_ptr的引用计数,可以用来解决std::shared_ptr可能造成的循环引用问题. ...

  7. JWT单点登录

    单点登录 概念:登录某集团的某一产品之后,访问其他产品的网站时就会是登录状态,比如登录QQ之后,进入QQ游戏的时候就是登录过的状态,具体实现方法有以下: Redis+token实现单点登录: 生成一个 ...

  8. 变“金点子”为“好应用”,合合信息智能文档处理技术助力大学生探索AI创新边界

    谈"糖"色变.追求养生.低卡生活--这些热门词汇频频在社交媒体上掀起讨论热潮.有这样一批年轻人不但捕捉到了这些词汇背后真实的用户需求,并且正在利用AI技术寻找解决之道. 近日,&q ...

  9. Google Maps Embed API & JavaScript API

    前言 很多年前写过一篇 Google Map 谷歌地图, 这篇算是翻新版本. Google Map Registration Google Maps Platform 是整个 Google Map 的 ...

  10. Go runtime 调度器精讲(七):案例分析

    0. 前言 前面用了六讲介绍 Go runtime 调度器,这一讲我们看一个关于调度 goroutine 的程序案例分析下调度器做了什么.需要说明的是,这个程序和抢占有关,抢占目前为止还没有介绍到,如 ...