im钱包app下载安装|区块链app开发
如何开发区块链应用程序:分步指南 - 知乎
如何开发区块链应用程序:分步指南 - 知乎切换模式写文章登录/注册如何开发区块链应用程序:分步指南知乎用户的大宝贝开发区块链应用程序区块链技术彻底改变了我们对数据、信任和去中心化系统的思考方式。它是比特币等加密货币的基础,但其潜力远远超出了数字货币的范围。区块链已成为一项突破性技术,可应用于各个行业,从金融和供应链管理到医疗保健等。在这个数字化转型的时代,理解和利用区块链的力量对于开发者和企业来说至关重要。区块链本质上是一种分布式账本技术,可以在计算机网络上实现安全、透明的记录保存。每个数据条目或“块”都链接到前一个数据条目,形成不间断的信息链。区块链的独特之处在于它的去中心化性质,没有任何单一实体或机构可以控制网络。这种去中心化确保了去信任环境中的信任和安全,从而防止欺诈和篡改。区块链应用程序开发涉及创建利用区块链技术独特功能的去中心化软件应用程序。开发人员使用各种区块链平台(例如以太坊、Hyperledger 或币安智能链)来构建这些应用程序。这些平台提供了创建智能合约、数字资产和去中心化应用程序 (DApp) 所需的基础设施和工具,这些应用程序可以通过提高透明度、安全性和效率来改变行业。区块链技术的潜在用例是巨大的。它可用于金融交易,确保更快、更安全的跨境支付。在供应链管理中,区块链可以实现端到端的可见性和可追溯性,减少欺诈和错误。医疗保健可以通过安全地管理患者记录和简化提供商之间的数据共享来受益于区块链。此外,区块链有可能颠覆投票系统、知识产权和数字身份验证等行业。区块链应用程序开发简介将探讨区块链技术的基础知识、其各种平台以及创建创新且安全的去中心化应用程序所需的开发工具和实践。无论您是寻求利用区块链力量的开发人员,还是希望在数字时代保持领先地位的企业,了解区块链应用程序开发都是拥抱技术未来的关键一步。加入我们的旅程,释放区块链在现代世界的无限可能性。区块链应用程序如何工作?区块链应用程序通常称为去中心化应用程序或 DApp,根据区块链技术的原理运行。了解其工作原理需要分解所涉及的关键组件和流程:去中心化网络:区块链应用程序在去中心化的计算机网络(通常称为节点)上运行。这些节点可以由全球不同的个人或实体拥有和运营。缺乏中央机构或服务器是区块链技术的基本特征。区块链协议:应用程序运行在特定的区块链协议上,该协议定义了管理网络的规则和共识机制。例如,以太坊是最流行的区块链平台之一,它使用以太坊虚拟机(EVM)和称为权益证明(PoS)或工作量证明(PoW)的共识机制,具体取决于版本。智能合约:智能合约是自动执行的合约,协议条款直接写入代码中。它们是许多区块链应用程序的关键功能。当满足预定义条件时,这些合约会自动执行,无需中介机构。例如,在金融 DApp 中,当买家确认收到货物时,智能合约可以自动向卖家发放资金。交易:用户通过创建交易与区块链应用程序进行交互。这些交易可能涉及发送数字资产(例如加密货币)、与智能合约交互或更新区块链上的数据。每笔交易均由用户进行加密签名,以验证其身份和意图。共识机制:区块链上的交易被分组为区块。网络上的节点竞相验证这些交易并向链中添加新块。共识机制(例如,PoW、PoS、委托权益证明等)决定了该验证过程如何运作。一旦添加了一个块,它就是不可变的,这使得它非常安全。数据存储:区块链本身充当分布式账本,存储所有经过验证的交易和数据。该账本在网络中的所有节点上进行复制,确保数据具有高度弹性和防篡改能力。每个区块都引用前一个区块,创建按时间顺序排列的区块链(因此称为“区块链”)。去中心化应用程序 (DApp) 层:在此区块链基础设施之上,开发人员使用特定于所选区块链平台的编程语言和工具构建 DApp。这些 DApp 通过发送和接收交易以及执行智能合约与区块链进行交互。用户界面: DApp 通常具有用户友好的界面,例如 Web 或移动应用程序,以允许用户与区块链无缝交互。这些接口通过 API 和钱包连接到区块链网络,使用户能够创建交易并监控其活动。钱包:要参与区块链应用,用户需要一个数字钱包。该钱包存储加密密钥,使他们能够签署交易并访问其数字资产。钱包可以基于硬件(物理设备)、基于软件(移动或桌面应用程序)或基于网络。区块链代币:许多区块链应用程序都有自己的原生代币或数字资产。这些令牌可以代表应用程序中的所有权、访问权或其他形式的价值。它们通过区块链上的交易在用户之间转移。总之,区块链应用程序通过利用去中心化网络、区块链协议、智能合约和用户友好的界面来使用户能够与区块链进行交互和交易。区块链技术的不变性、透明度和安全性支撑了这些应用程序的可信度,使其适用于传统金融交易之外的广泛用例。区块链应用程序开发平台区块链应用程序开发平台为开发人员在区块链网络上创建去中心化应用程序(DApp)和智能合约提供了必要的工具、框架和基础设施。这些平台简化了开发过程,并提供了更轻松地构建和部署基于区块链的解决方案的功能。以下是一些著名的区块链应用程序开发平台:以太坊:以太坊是 DApp 开发中最受欢迎且使用最广泛的区块链平台之一。它支持用 Solidity 编写的智能合约,并提供强大的开发生态系统。以太坊的原生加密货币以太币 (ETH) 通常用于 DApp 内的交易。币安智能链(BSC):币安智能链是一个与以太坊EVM兼容的区块链平台,使以太坊开发者可以轻松地将他们的DApp移植到BSC。与以太坊相比,它以其快速的交易速度和较低的费用而闻名。Hyperledger Fabric: Hyperledger Fabric是专为企业应用程序设计的开源区块链框架。它专注于隐私、可扩展性和许可网络,使其适合供应链管理和身份验证等业务用例。Polkadot: Polkadot 是一个多链网络,连接各种区块链,使它们能够互操作。它提供了一个用于构建自定义区块链(平行链)的框架以及与其他区块链连接的桥梁。Tezos: Tezos 是一个自我修正的区块链平台,以其链上治理模型而闻名。开发者可以用 Michelson 这种领域特定语言编写智能合约,并通过社区共识升级协议。Cardano: Cardano 是一个强调研究驱动开发和同行评审代码的区块链平台。它提供了一种独特的智能合约方法,通常用于金融和治理领域的应用。Tron: Tron 是一个区块链平台,以专注于去中心化内容和娱乐应用而闻名。它使用委托权益证明(DPoS)共识机制并支持智能合约开发的 Solidity。Avalanche: Avalanche 是一个高度可扩展和可定制的区块链平台,允许开发人员使用其共识机制创建自定义区块链。它的目标是提供亚秒级的交易最终确定性。Algorand: Algorand 是一个专为速度和效率而设计的区块链平台。它采用纯粹的权益证明共识算法,支持多种语言编写的智能合约,包括SmartPy和Reach。EOS: EOS是一个区块链平台,旨在为DApp提供高吞吐量和可扩展性。它使用委托权益证明(DPoS)并提供用户友好的开发环境。Cosmos: Cosmos 是一个由可以相互通信的互连区块链组成的生态系统。它允许开发人员创建可以通过 Cosmos Hub 进行互操作的主权区块链(区域)。NEO: NEO,通常被称为“中国以太坊”,是一个旨在数字化资产和创建数字身份的区块链平台。它支持多种编程语言进行智能合约开发。Stellar: Stellar是一个针对跨境支付和资产代币化进行优化的区块链平台。它简化了代表现实世界资产的代币的发行和转让。这些区块链应用程序开发平台迎合各种用例和偏好,从公共区块链到私有区块链,从未经许可的网络到经过许可的网络。开发人员选择符合其项目需求的平台,包括可扩展性、共识机制和编程语言支持等因素。每个平台都提供自己的一套开发工具、文档和社区来支持基于区块链的应用程序的创建。区块链应用程序开发要考虑的语言区块链应用程序开发需要一组特定的编程语言来与区块链网络交互、编写智能合约并构建去中心化应用程序(DApp)。以下是区块链开发通常考虑的一些语言:Solidity: Solidity 是以太坊智能合约开发中使用最广泛的语言。它是专门为编写以太坊智能合约而设计的,是一种静态类型的高级语言。Solidity 的语法与 JavaScript 类似,并且在大型开发者社区中有详细的文档记录。Vyper: Vyper 是以太坊智能合约的另一种语言。它的目标是通过消除某些功能并使用类似 Python 的语法,比 Solidity 更安全、更易读。对于优先考虑安全性和简单性的开发人员来说,这是一个不错的选择。Rust: Rust 以其内存安全性和性能而闻名,使其成为区块链开发的绝佳选择。Polkadot 和 Solana 等项目使用 Rust 来构建区块链基础设施和智能合约。C/C++:这些语言用于区块链核心协议和某些智能合约平台的开发。比特币的核心代码库主要是用C++编写的,而EOS和其他一些平台也支持C/C++进行智能合约开发。Go(Golang): Go用于构建区块链基础设施和工具。以太坊 2.0、币安智能链和 Hyperledger Fabric 等都使用 Go 作为各种组件。Go 的简单性和高效性使其适合此目的。JavaScript/TypeScript: JavaScript和TypeScript通常用于开发区块链应用程序的前端接口和后端服务。Web3.js 和 ethers.js 是使用 JavaScript 与基于以太坊的 DApp 进行交互的流行库。Python:虽然不像其他语言那么常见,但 Python 可用于区块链开发,特别是在研究、脚本编写和构建工具方面。Web3.py 等库使 Python 开发人员能够与以太坊网络进行交互。Java: Java 用于一些区块链平台,例如 Corda,它是为企业区块链解决方案设计的。它适合需要隐私和对数据进行细粒度控制的企业。LLL(Low-Level Lisp-like Language): LLL 是以太坊智能合约的低级语言。它不像 Solidity 或 Vyper 那样常用,但提供了对合约执行的更多控制。Michelson: Michelson 是 Tezos 区块链上用于编写智能合约的特定领域语言。它是一种基于堆栈的语言,设计时考虑到了安全性和形式验证。Plutus: Plutus 是 Cardano 区块链的智能合约开发语言。它结合了用于合约逻辑的 Haskell 和用于金融合约的 Marlowe,从而允许高级且安全的合约开发。在选择用于区块链开发的编程语言时,请考虑多种因素,例如您的目标区块链平台、项目的具体要求、团队的专业知识以及所需的安全性和可扩展性级别。此外,许多区块链平台提供多种语言的 SDK 和开发工具,为开发人员在构建区块链应用程序时提供语言选择的灵活性。区块链应用程序开发需要考虑的因素区块链应用程序开发是一个复杂的过程,需要仔细规划和考虑各种因素,以确保项目的成功。开始区块链应用程序开发时需要记住以下关键因素:区块链平台选择:选择符合您项目目标和要求的适当区块链平台。考虑可扩展性、共识机制、社区支持和编程语言支持等因素。使用案例和行业重点:明确定义项目的用例和目标行业。不同的行业有特定的需求和法规,可能会影响您的设计选择。安全:安全性在区块链开发中至关重要。实施安全智能合约编码、数据加密以及防范重入攻击和抢先交易等常见漏洞的最佳实践。智能合约开发:如果您的项目涉及智能合约,请仔细设计、编码和测试它们。确保它们高效、安全并实现预期目的。考虑使用正式验证工具来提高安全性。共识机制:了解所选区块链平台的共识机制。它影响交易速度、最终性和去中心化等因素。选择最适合您项目需求的共识机制。可扩展性:考虑应用程序的可扩展性要求。评估所选的区块链平台是否可以处理预期的交易量,以及是否支持第 2 层扩展解决方案(如果需要)。用户体验(UX/UI):为您的 DApp 创建直观的用户界面 (UI) 和用户体验 (UX),以确保其用户友好且可供更广泛的受众使用。监管合规性:了解目标市场的监管环境。确保您的区块链应用程序符合相关法律法规,特别是在金融和医疗保健等领域。数据隐私:谨慎处理用户数据和私人信息。探索以隐私为中心的解决方案和加密技术来保护区块链上的敏感数据。互操作性:考虑您的区块链应用程序是否需要与其他区块链或遗留系统交互。互操作性对于某些用例来说至关重要。代币经济学:如果您的 DApp 包含原生代币或加密货币,请仔细设计代币经济学,包括对用户和利益相关者的供应、分配和激励。社区和生态系统:参与区块链社区并利用现有工具、库和资源。建立在已建立的生态系统上可以节省时间和精力。测试和审核:彻底测试您的智能合约和区块链应用程序。考虑由安全专家进行外部审计来识别和修复漏洞。可扩展性和维护:规划长期可扩展性和维护。随着用户群的增长,区块链应用程序通常需要持续更新和改进。用户入门和教育:确保用户了解如何使用您的区块链应用程序。如有必要,提供资源和教程来教育用户区块链技术。成本管理:估算在区块链上部署和维护 DApp 的相关成本。请注意交易费用和基础设施成本。市场策略:制定明确的营销和采用策略,以吸引用户和利益相关者使用您的区块链应用程序。法律和知识产权:解决法律问题,包括知识产权、许可以及与合作伙伴或协作者的合同。治理模式:如果您的项目涉及去中心化网络或基于代币的治理,请建立决策和协议升级的治理模型。用户反馈和迭代:收集早期用户的反馈,并准备根据他们的输入和不断变化的市场条件迭代您的区块链应用程序。成功的区块链应用程序开发需要采用涵盖技术、法律和业务考虑因素的整体方法。通过仔细评估和解决这些因素,您可以增加创建满足目标受众需求的安全、实用且可持续的区块链应用程序的机会。区块链应用市场概述在区块链技术跨行业变革潜力的推动下,区块链应用市场一直在稳步增长和发展。该市场包含广泛的应用程序、平台和服务,它们利用区块链提供去中心化、安全和透明的解决方案。以下是区块链应用市场的关键方面:多样化的用例:区块链应用程序市场涵盖众多领域,包括金融、供应链、医疗保健、房地产、游戏、身份管理、投票系统等。每个用例都为基于区块链的解决方案提供了独特的机会,以提高透明度、安全性和效率。加密货币和数字资产:区块链应用程序市场的很大一部分围绕加密货币和数字资产。这包括加密货币钱包、交易所、交易平台和允许用户借出、借入和交易数字资产的 DeFi(去中心化金融)应用程序。NFT(不可替代代币):不可替代代币在区块链应用市场中获得了极大关注。这些独特的数字资产代表了收藏品、数字艺术、游戏内物品等的所有权。NFT 市场和平台支持 NFT 的创建、销售和交易。智能合约和DApp:去中心化应用程序(DApp)和智能合约是区块链应用市场的核心组成部分。DApp 提供各种服务,例如去中心化交易所、预测市场和治理平台,而智能合约则实现协议和交易的自动化。区块链平台:该市场包括以太坊、币安智能链、Polkadot 和 Cardano 等区块链平台,它们是 DApp 和智能合约的基础。开发人员根据平台的功能、共识机制和目标用例来选择平台。企业区块链解决方案:许多企业探索用于供应链管理、身份验证和记录保存的区块链应用程序开发。企业区块链解决方案提供根据企业需求量身定制的私有和许可网络。区块链即服务(BaaS): BaaS 提供商提供基于云的区块链基础设施,为企业和开发人员简化区块链应用程序的开发和部署。去中心化金融(DeFi):区块链应用市场中的 DeFi 领域出现了爆炸性增长。DeFi 应用提供去中心化的借贷、借贷、交易和流动性挖矿服务,往往回报较高,但风险也较高。监管环境:监管环境在区块链应用市场中起着至关重要的作用。世界各国政府正在制定法规来解决可能影响市场参与者的加密货币、代币产品和区块链应用程序。用户采用和教育:用户采用仍然是区块链应用程序市场的一个关键挑战。对用户进行区块链技术教育并提供用户友好的界面对于广泛采用至关重要。市场竞争:区块链应用市场竞争激烈,众多初创公司和老牌公司争夺市场份额。竞争推动创新以及新功能和服务的开发。投资和融资:区块链初创公司通常依靠风险投资资金、首次代币发行(ICO)或代币销售来确保发展和扩张的资金。投资者对区块链应用市场的兴趣依然浓厚。互操作性:随着市场的增长,不同区块链网络和应用程序之间的互操作性需求变得更加明显。Polkadot 和 Cosmos 等项目旨在应对这一挑战。可扩展性解决方案:可扩展性仍然是区块链应用程序市场关注的一个问题,因为需要更快、更高效的网络来处理不断增加的交易量。环境问题:区块链挖矿对环境的影响,尤其是在比特币等工作量证明 (PoW) 网络中,引起了人们的担忧。一些项目正在探索更加环保的共识机制。区块链应用程序市场是动态的,并且随着新技术、用例和监管发展的出现而不断发展。它通过采用区块链技术为传统行业的创新、颠覆和转型提供了一个充满希望的前景。然而,它也面临着与可扩展性、监管和用户采用相关的挑战,必须解决这些挑战才能实现持续增长和成功。 这两个工具可以自行查验========================================suhui4792结论总而言之,区块链应用市场是一个充满活力且多元化的生态系统,应用涵盖各个行业。它涵盖加密货币、NFT、智能合约和企业解决方案。尽管它在创新方面有着巨大的前景,但用户采用、监管和可扩展性仍然是关键挑战。尽管存在这些挑战,区块链应用程序市场仍在不断发展,为变革性解决方案和颠覆性技术提供了机会。发布于 2023-10-19 10:08・IP 属地陕西区块链(Blockchain)Android 开发iOS 开发赞同添加评论分享喜欢收藏申请
如何基于区块链技术开发应用 - 知乎
如何基于区块链技术开发应用 - 知乎首发于猿论切换模式写文章登录/注册如何基于区块链技术开发应用慕课网已认证账号随着区块链的火热,相信很多同学已经跃跃欲试想投入到区块链开发队伍当中来,可是又感觉无从下手,本文就基于以太坊平台,轻松带大家入区块链技术开发应用的大门。以太坊是什么我们要开发一个区块链应用,如果要从头开发一个区块链,是不现实的,这时我们就需要以太坊这样的平台。以太坊(Ethereum)是一个建立在区块链技术之上的应用平台。它允许任何人在平台中建立和使用通过区块链技术运行的去中心化应用。对这句话不理解的同学,姑且可以理解为以太坊是区块链里的Android,它是一个开发平台,让我们就可以像基于Android Framework一样基于区块链技术写应用。在没有以太坊之前,写区块链应用是这样的:拷贝一份比特币代码,然后去改底层代码如加密算法,共识机制,网络协议等等(很多山寨币就是这样,改改就出来一个新币)。以太坊平台对底层区块链技术进行了封装,让区块链应用开发者可以直接基于以太坊平台进行开发,开发者只要专注于应用本身的开发,从而大大降低了难度。以太坊是目前最流行的区块链应用平台,围绕以太坊已经形成了一个较为完善的开发生态圈:有众多开发框架、工具可以选择。智能合约是什么对区块链稍有了解的同学,肯定约到过这个词:智能合约,简单来说,智能合约就是跑在区块链上的一段程序。智能合约英文是Smart Contract,和人工智能( AI:Artificial Intelligence )的智能并没有什么关系,智能合约的概念最早是尼克萨博在95年就提出的,它的概念很简单,就是将法律条文写成可执行代码。当时并没有区块链,不过智能合约与区块链几乎是天生一对,因为区块链上程序就像法律条文都是按规则运行。那如何来编写智能合约呢?以太坊上编写智能合约官方推荐的语言是Solidity,这个语言大家也许没有听说过,不用怕的,如果你对Python 或 JavaScript 有一点点了解,那么学习Solidity就很简单。先来看看一个合约Solidity文件会包含哪些内容,我用了一张思维导图来表示:再对照代码看看, 有合约文件simplestorage.sol如下:pragma solidity ^0.4.0; // 编译器版本声明
import "someotherfile.sol"
// 定义一个合约(就像其他语言里定义一个类一样)
contract SimpleStorage {
uint storedData; // 这是一个状态变量
// 这是一个函数
function set(uint x) public {
storedData = x;
}
function get() public constant returns (uint) {
return storedData;
}
}这段智能合约的作用是保存了一个变量在区块链中,然后提供了两个函数:set() 和 get() 来设置和获取变量。然而,这样一段智能合约程序并不能称之为一个应用,我们平时看到应用,如微信,微博,知乎等都至少需要有一个和用户交互的界面以便用户来进行使用,不管这个界面是APP、Web、还是小程序,区块链应用既然是应用同样也需要有这样的交互UI。区块链(去中心化)应用区块链应用,由于其运行在去中心化区块链网络上,通常称为去中心化应用程序(Decentralized App)。去中心化应用程序虽然每个人对它的定义不一样,通常认为如果一个应用的关键(核心)的数据存储在区块链网络中(不再由一个单一的机构掌握),这样的应用都可以认为是区块链应用。我们可以把区块链理解为一个存取应用数据的不可篡改的分布式数据库。因此一个去中心化应用一般应该这么几个组成部分,我用了一张思维导图来表示:前面我们已经了解如何编写智能合约,而应用的UI展现部分,如编写HTML5等,这一部分也有大量的教程,关键的一个部分是如何让UI和智能合约进行交互呢?这就需要使用web3.js库web3.jsWeb3.js是以太坊官方的Javascript API,可以帮助智能合约开发者使用HTTP或者IPC与本地的或者远程的以太坊节点交互。应用的整个通信交互过程可以抽象为下图:如果一个前端界面需要和上面的智能合约进行交互,核心的JavaScript代码如下:
// 初始化web3
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider);
} else {
web3 = new Web3(new Web3.providers.HttpProvider("节点ip"));
}
// 设置一个调用合约的默认账号
web3.eth.defaultAccount = web3.eth.accounts[0];
var simpleStorage = web3.eth.contract(合约ABI);
var simple = simpleStorage.at('合约地址');
simple.get(function(error, result){
// result 为获取的合约的结果数据
});
// 假设按钮点击时,调用合约的set方法
$("#button").click(function() {
simple.set(1);
});
交互代码主要有下面这几个步骤:初始化web3设置一个调用合约的默认账号使用合约的ABI(二进制接口信息)及合约地址 创建一个合约对象使用合约对象调用合约函数(如:把从合约中获取的值显示在界面中,用户点击界面调用相应的合约函数)总结我们来做一下总结,编写一个完整的区块链(去中心化)应用,归纳一下就是需要编写3个部分的代码: 1. 编写智能合约; 2: 编写应用UI; 3: 编写UI月合约交互代码。当然,在实际开发过程,我们还会需要非常多的问题,如怎么搭建开发环境,怎么进行测试,怎么部署等等。为此我专门为大家准备了非常实用的区块链应用开发课程:区块链入门与去中心化应用实战-慕课网实战作者:Tiny熊链接:https://www.imooc.com/article/29573来源:慕课网本文原创发布于慕课网 ,转载请注明出处,谢谢合作推荐阅读:【重磅】认证作者招募 | 打造个人品牌 so easy !有奖征文003期|程序员进阶路上,哪本书你认为很不错,对你帮助很大?区块链教程—以太坊(三):应用代码解析区块链教程(二):比特币、区块链、以太坊、Hyperledger的关系区块链教程—以太坊(一):Windows搭建以太坊私有链编辑于 2018-05-17 11:58区块链(Blockchain)金融应用开发赞同 22添加评论分享喜欢收藏申请转载文章被以下专栏收录猿论汇集前沿、专业、有广度、有深度的IT
百度超级链-区块链开放平台
百度超级链-区块链开放平台
产品
可信基础设施
超级链BaaS
可信数字身份
可信跨链
智能预言机
开放网络
可信数据流通
智能链网
隐私计算
可信数字经济
数字商品可信登记平台
电子签约
可信存证
解决方案
司法
版权
金融
政务
溯源
教育
教程
开源社区
XuperChain
链桨
技术论坛
文档中心
服务与支持
充值
工作台
首页
产品
超级链BaaS
开放网络
可信存证
电子签约
隐私计算
可信跨链
可信数字身份
数字商品可信登记平台
超级链智能预言机
智能链网
解决方案
司法
版权
金融
政务
溯源
教育
教程
开源社区
XuperChain
链桨
技术论坛
文档中心
服务与支持
视频介绍
XuperOS
开放网络
提供区块链的快速部署和运行环境,只花2元立即体验区块链服务
查看详情
XuperChain
XuperChain开源
自研可控 / 四大核心技术支持 / 灵活高效支持各类业务应用场景
查看详情
【最新消息】
星际社区悄然预备:AI聊天机器人即将上线,共创社交新篇章
【最新消息】
XuperOS新年致辞
【最新消息】
百度超级链DAPP互通计划发布
超级链数据动态
-
用户数
-
区块高度
-
历史并发峰值
-
总交易笔数
超级链技术优势
超级节点技术
利用超级计算机和分布式架构
具备计算力和储存力
对外呈现为节点,内部为分布式网络
链内并行技术
事务能并行处理的核心技术
能够充分利用多核和多机的计算资源
可插拔共识机制
支持单链上多种共识机制无缝切换
当前支持:DPOS、授权共识、PBFT
支持根据需求定制开发插件
立体网络技术
基于平行链、侧链、链内 DAG 并行技术的逻辑处理
单链:8.7万TPS
整体网络:20万TPS
一体化智能合约
智能合约和核心架构分离技术
具备合约生命周期管理、预执行等特色
合约语言:C++、Go、Solidity等
账号权限系统
去中心化的账号权限系统
可扩展的权限模型,支持多种权限模型配置
产品介绍
超级链BaaS
超级链BaaS提供的标准化区块链产品,可以简单快速的实现业务与区块链的融合,帮助您便捷地完成区块链网络的部署、监控和运维。
查看更多
开放网络
自主研发的开源技术搭建的区块链基础服务网络,为开发者提供区块链应用快速部署和运行的环境。
查看更多
可信存证
通过司法权威节点见证,发挥区块链防篡改、安全的优势,使电子数据作为电子证据对接到互联网法院,具备全链路可信
查看更多
数据协同平台
数据协同平台是基于百度超级链、多方安全计算、数据隐私保护等技术打造的国内首个多企业数据安全协同计算方案
查看更多
解决方案
司法
是由法院、公证处、司法鉴定中心等为节点构建的区块链法院联盟体系,实现数据从生成、存储、传输到最终提交的整个环节真实可信,并具有法律效力。全链路可信,全流程司法权威节点见证
查看详情 >
版权
基于区块链技术,为原创作者和机构提供版权保护、传播变现到监控维权的全链路服务。全方位推动版权存证、监控取证及司法维权全链条。图片机构、确权机构、司法机构三类联盟节点加持,提升版权链公信力,打造真正可信、可靠的版权保护。
查看详情 >
金融
百度超级链与可信计算技术的集成,实现数据不出库,即可完成多方安全建模和共享,为金融机构提供安全可控、保护隐私的数据流通共享的解决方案。大大提升金融机构的风险定价、信用评估,反欺诈系统等金融风控能力
查看详情 >
政务
百度区块链能够助力政府构建“一号申请、一窗受理、一网通办”的政务体系,实现政务数据互认。通过百度超级链的数据协同平台能够在保护用户隐私不受侵害、国家机密安全可靠基础上,用跨链计算方式实现协同工作,提升社会运转效率。
查看详情 >
溯源
通过区块链与物联网技术,将农产品从生产,加工,质检,运输,经销商,零售商一直到消费者手里全流程信息的可信记录,解决了信息孤岛,信息流转不畅,信息缺乏透明度等行业问题。构建数字化一站式消费生态
查看详情 >
开源社区
百度超级链开源技术是百度自主研发创新的产物,拥有链内并行技术、可插拔共识机制、一体化智能合约等业内领先技术支撑,让区块链应用搭建更灵活、性能更高效、安全性更强,全面赋能区块链开发者
进入开源社区
超级链历程
2015年
启动战略投资和方向布局
2017年
区块链技术部门成立
2017年3月
支持长安新生公募ABS发行
2018年3月
区块链版权保护平台上线
2018年9月
百度区块链白皮书V1.0发布
2018年12月
与北京互联网法院共建“天平链”
2019年4月
获得网信办首批区块链信息服务备案
2019年5月
XuperChain宣布开源
2019年7月
通过工信部电子一所安全性、性能测评
2019年8月
与重庆市达成区块链医疗处方流转平台合作
2019年12月
中国唯一代表出席WTO区块链论坛
2020年1月
开放网络正式发布
2020年2月
首个区块链广告监播案例落地
2020年4月
推动区块链首次写入防伪溯源国家标准
2020年6月
牵头制定IEEE跨链国际标准
2020年9月
捐赠开放原子开源基金会
2021年3月
超级链动态内核发布
2021年5月
超级链累计接入全国百余家法院电子证据平台
2021年7月
超级链创新中心落户上海
2021年9月
首个NFT产品发布
2021年12月
首个区块链+AI产品链桨发布
2022年1月
百度超级链数字藏品平台上线
合作伙伴
咨询反馈
请留下您的联系方式与需求,我们将尽快联系您
业务咨询类型*
超级链BaaS开放网络可信存证合作咨询问题反馈可信跨链可信数字身份数字商品可信登记平台超级链智能预言机智能链网
错误信息
姓名*
错误信息
手机号码*
错误信息
邮箱地址*
错误信息
企业名称*
错误信息
行业*
错误信息
咨询反馈*
错误信息
错误信息
提交
关闭
提交成功
xchain-help@baidu.com
邮件联系我们
联系小助手
扫二维码下载
产品
超级链BaaS
开放网络
可信存证
电子签约
隐私计算
可信跨链
可信数字身份
数字商品可信登记平台
教育实训
超级链智能预言机
智能链网
解决方案
司法
版权
金融
政务
溯源
开源社区
XuperChain
链桨
技术论坛
文档中心
服务与支持
服务与支持
关于我们
联系我们
加入我们
官方微信
联系邮箱
xchain-help@baidu.com
友情链接
京公网安备 11000002000001号
北京ICP证030173号
京网信备 11010819390879370022号
使用百度前必读
© Baidu
如何学习区块链开发? - 知乎
如何学习区块链开发? - 知乎首页知乎知学堂发现等你来答切换模式登录/注册区块链(Blockchain)区块链革命(书籍)区块链开发指南(书籍)区块链创业公司区块链技术如何学习区块链开发?准备一颗心扑在区块链上面了,自学了go语言和solidity但是不知道能干什么显示全部 关注者382被浏览352,708关注问题写回答邀请回答好问题 213 条评论分享40 个回答默认排序知乎用户闲话少说,这篇将告诉你一个完整的 Web3.0 开发路线图,让你成为一个合格的区块链开发者最基础的部分前后端开发知识去中心化应用 DApp智能合约开发知识一些重要的工具0x01 最基础的部分要想成为一个区块链开发者,首先要成为一个开发者,这就需要理解计算机科学(Computer Science)。《哈佛大学 CS50 公开课》能帮助你理解最基础的计算机及数据处理。当你对计算机基础有了一定了解后,就可以开始学习区块链基础了,因为你必须要理解什么是区块链,它如何工作以及它为什么能打破交易方式。目前区块链技术已经不局限于数字货币,它越来越多地多的具备了分布式云计算的能力,使之能够运行各种去中心化的应用程序(DApp)学习区块链基础技术,可以参考我的另一篇文章《区块链学习资源(基础篇)》0x02 前后端开发知识在学习开发 DApp 之前,我们需要了解一定的前后端的知识,前端方面需要掌握 HTML、CSS、纯 JavaScript 语言以及 React 或 Vue 之类的框架。这里推荐免费的《FreeCodeCamp 课程》,可以从零开始学习前端知识。而去中心化应用的后端,与一般应用的后端不太一样,主要区别在于区块链技术使用的是去中心化存储,而普通应用往往使用中心化的数据库或对象存储。尽管如此,但他们背后的技术思想是类似的,因此不太建议直接跳过普通 Web 应用的基础开发原理而投身于 Web 3.0 的开发,你依然需要明白如何连接数据库、如何创建 RESTful API 以及编写各种业务逻辑等。因此学习下 NodeJS、Express、各种数据库(MySQL、PostgreSQL等),练习编写应用接口等是最佳路径。0x03 去中心化应用 DApp在学习完最基础的区块链、节点、共识等一系列知识后,就是时候来学习如何在此之上构建应用程序了,而构建在区块链之上的应用程序我们通常称为去中心化应用(DApp),它包括:应用的前端页面:使用 JavaScript 或 React、Vue 等框架构建的前端应用程序应用的后端系统:使用 Solidity 或者 Rust 构建在区块链上的智能合约系统学习开发 DApp 之前,建议了解一下以太坊的知识,如果把区块链比做计算机,那以太坊可视为操作系统,任何应用程序都需要运行在操作系统上,以太坊就是其中一种,也是最为人所知的一种。《以太坊官网中文版》有助于了解以太坊的知识0x04 智能合约开发知识所谓智能合约,就是跑在以太坊网络上的小程序。每个 Web 3.0 开发者都必须了解以太坊的工作原理。智能合约通常是自动执行的,它可以使用 Solidity 或者 Rust 等语言编写,通过编写业务逻辑把信息存储到区块链上,就像普通应用把数据存到数据库中一样。以下是一些学习 Solidity 合约的资源:CryptoZombies (极力推荐)FreeCodeCamp 的 16 小时智能合约课程0x05 一些重要的工具工欲善其事,必先利其器,学习完智能合约的课程手边总要经常使用一些工具:开发语言的工具Solidity 文档OpenZeppelinChainlink重要框架Remix - Ethereum IDEHardhat | Ethereum development environment for professionals by Nomic LabsBrownieDApp Tools高级概念NFTDAODeFiUpgradeability其他工具Faucets | ChainlinkEtherscanAlchemy - Blockchain API and Node ServiceMoralis » The Ultimate Web3 Development Platform编辑于 2023-06-09 17:16赞同 54824 条评论分享收藏喜欢收起汇智网学习软件编程 关注先看你的目的是什么,再决定接下来做什么。发布于 2020-03-11 22:23赞同1 条评论分享收藏喜欢
从零开始创建一个区块链 - 知乎
从零开始创建一个区块链 - 知乎切换模式写文章登录/注册从零开始创建一个区块链时间戳河图公众号同名|区块链不仅是一种技术更是一种思维理念和经济范式。本文将告诉你如何从零开始创建一个完整的区块链,如果你有一些编程基础,可以按照文章方法进行尝试;以及帮助初学者理解这项颠覆性技术背后的关键概念。作者:joao zsigmond编译:区块链范式01做什么?在本文中,我们将分析区块链技术背后的关键概念。我们将一起了解区块链的内部运作,并探索信息如何在服务器的分布式网络上公开存储。02怎么做?这一切将通过从头开始构建一个简单的区块链来完成。我们将通过创建区块链的基本步骤,我将添加一些代码片段,以帮助你遵循 Python编程语言。但是,每一步都会有很好的记录,所以你可以用任何你喜欢的语言来进行操作。本文中使用的源代码网址:https://github.com/jzsiggy/blockchain-from-scratch第一章:区块链有什么了不起?区块链在当今市场上越来越受欢迎。亚马逊、微软、谷歌和其他巨头公司已经开始提供区块链技术的相关服务。很多人经常将区块链与比特币等加密货币联系起来,但很多时候,事实并非如此。现在,你可能会问自己,为什么区块链会得到这么多关注?有什么大不了的?那么,事情是这样的--区块链允许我们创建安全的、公开的、分散的 "数据库 "来存储任何类型的信息。在区块链之前,大量的数据必须由某种形式的中间人或中介机构进行存储和验证。就具有金融属性的数据而言,中介是银行、金融中介机构。我们依靠银行来跟踪我们所有的金融数据,我们相信他们不会以任何方式篡改或滥用我们的数据。这种方法是可行的,但是在这些机构的手中却拥有很大的权力。区块链技术的核心思想是利用密码学和复杂的计算机算法,创造出一种安全透明的方法,将这些中介机构剔除出去,让数据由一个巨大的开放的服务器网络进行存储和验证。让我们潜心研究,我们就会明白怎么做!第二章:数据是如何存储的?区块是什么?在我们开始之前--让我快速解释一下哈希函数(散列函数)。它们对我们的区块链工作非常非常重要!哈希函数(散列函数)是一个函数,它接收一个任意长度的字符串作为输入,并返回一个固定长度的字符串,看起来非常随机,但不是随机的固定长度的字符串。每一个字符串都有它自己的输出哈希值,这个哈希值总是相同的。字符串“ Hello world”的哈希如下所示:输入字符串 "Hello world "得到的SHA256哈希函数需要注意的是,即使是对输入字符串的微小改动,输出的哈希值也是完全不同的。例如,我们少输入了一个“l”,如下所示:比较"Hello world "和"Helo world "两个字符串的哈希值All right! Now let’s dive in!好了!让我们现在开始吧!一个区块里有什么?区块链中的一个区块存储了写入它的数据、前一个区块的哈希值和自己的哈希值。一旦数据写入区块,是很难更改的,因为每一个写入区块链的区块都会引用它之前区块的哈希值。这样一来,即使你轻描淡写地修改了一个区块,它的哈希值也会完全改变,所以后面的区块也要改变--因为它必须有前一个区块的哈希值--后面的区块以此类推。如果你修改了区块链的任何一个区块,你必须重写整个链。当我们把这个逻辑转化为代码时,在Python中,一个块的数据结构看起来就是现在这样的Python3中一个代码块的代码段在我们的 Blockchain类的构造函数中,我们实例化了插入在块中的数据、前一个块的哈希值,我们对自己的块应用哈希函数,并将输出保存到哈希变量中。我们还可以创建一个to_string方法,返回一个包含数据和前一个块的哈希值的字符串。这意味着我们可以通过运行来创建一个块的数据结构。使用Python3中的Block类创建一个区块在继续之前,让我指出每个区块链都必须有一个初始块,对吗?没有以前的块。此块称为“创世纪”块,通常将指向空哈希作为其前一个块。第三章:工作证明为什么改写区块链如此困难?在上一章中,我们了解到,如果要改变单个区块中的数据,我们必须从改变一个区块的点开始重写整个区块链。你可能会有疑问,既然不涉及复杂和耗时的操作,那么重写整个区块链的过程为什么会如此困难呢?在本章中,我们将深入研究一个区块必须遵守的其他一些必要条件,这些条件使得区块非常难以伪造。在开始之前,我们先回到我们的哈希函数。这个函数还有一个重要的特性,我还没有提到,这个特性就是:无法进行反向计算。(区块链范式:散列函数是一个单项函数,这道函数题只能进行单项运算求解,无法进行逆向求值)这意味着,虽然计算机从一个输入字符串中生成一个哈希是非常简单的,但仅仅通过知道输出结果来找到 "输入的字符串 "是非常困难的。实际上,除了猜测字符串并检查输出的哈希值是否是预期值之外,没有其他更好的方法来找到输入字符串。总而言之,要找到满足所需哈希值的输入字符串,需要2²⁵⁶次的猜测,即使对于计算机来说,这也只是一个无法形容的巨量猜测。为了防止冒名顶替者修改区块并快速重写整个区块链,要成功伪造区块,其哈希必须遵循一个简单的规则:它必须以一定数量的零开头(零的位数决定了我们创建一个新的区块难度值「也就是挖矿的难度值」)。举例,假设我们定义一个区块在我们的区块链中有效,它(哈希值)必须以 4个零开始。现在,每次我们想要向我们的区块链添加一个新的区块时,我们必须对其应用哈希函数,并查看输出的哈希是否以 4个零开始。如果不是,我们必须稍稍更改一下区块,然后重试。重复此过程,直到该块有效为止。这就是工作证明背后的基本概念,也是为什么区块如此难以创建、篡改。该规则意味着要创建一个新块,需要花费大量的时间、精力和计算力。这也意味着,在对块进行哈希处理时,我们必须添加其他信息:每次我们猜测时数字都会改变。这是确保每次猜测输入字符串都略有不同的必要条件,因此每次我们都有不同的哈希值。此数字称为Nonce(区块链范式:我们常说的随机数)。挖矿在进入代码之前,我们先来看看最后一个基础理论,以构成我们的区块链:区块挖矿。如果你之前读过一篇关于区块链的深度文章,这个词肯定会出现。在区块链网络上,粉碎这些计算复杂的算法以创建新区块的服务器被称为矿工。很多时候,在大型区块链中,这些矿工都是非常大的仓库,里面装满了服务器,24小时不眠不休地粉碎这些算法,以确保区块链的发展。本章的理论就是这样!现在,让我们返回代码并修复 Blockchain类,以使其哈希服从我们的区块链规则,并以一定数量的零开始。我们将 Blockchain类中添加一个新的方法,名为 calculate_valid_hash ,在这个方法中,我们将把 hash变量初始化为一个空字符串,nonce(随机数)为 0。当哈希值没有被 is_hash_valid 方法批准时,我们将递增 nonce值并再次尝试。当我们找到一个 nonce值,当它与块的数据进行哈希时,会被 is_hash_valid 方法批准,我们将停止循环,并将块的哈希值设置为我们计算的值。「区块链范式:本段大意为矿机不断循环的调整随机数来得出正确的哈希值」我们将把这个新方法添加到我们的构造函数中。计算我们区块的有效哈希通过这些修改,每次我们实例化一个新的区块时,我们都必须经过生成工作量证明的过程才能挖掘该块。现在是时候创建一个新类:区块链。当我们实例化 Blockchain类时,我们将把区块属性初始化为一个空数组。为此,我们将在构造函数中添加以下代码行。Blockchain类现在,让我们在区块链类中添加一个方法来创建“创世区块”!这个方法将在我们区块链的构造函数中调用。为此,我们必须创建 set_genesis_block 方法,并将数据变量初始化为 "创世块"(或任何你喜欢的变量)。我们还将初始化 prev_hash 变量为 64个零的字符串。现在我们将从这些数据中实例化一个区块,并将其添加为我们区块链的第一个区块。由于我们 Blockchain类的构造函数中的 calculate_valid_hash方法,我们可以保证这个区块将有一个有效的哈希值。初始化区块链时创建创世块最后,为了完成我们的区块链,让我们添加一种方法来向我们的区块链添加一个块。这个方法将只接收区块中的输入数据。然后,它将获得上一个区块的哈希值,并根据先前的哈希和数据创建一个新块。与创世区块一样,由于 calculate_valid_hash方法的存在,我们可以保证新区块的哈希值是有效的。最后,我们将把新挖出的区块添加到我们的区块数组中。向我们的区块链添加一个新块现在我们已经成功创建了整个区块链结构,我们可以像这样初始化!我们的主程序会初始化区块链并添加一些区块我在 Blockchain类中创建了一个名为 get_blocks的可选方法,它可以返回一个包含所有区块的列表。这对我们调试、测试和可视化我们的区块链可能会很有趣。当我们在终端或命令提示符上运行这段代码时,我们会得到这样的结果:main.py的输出如果我们分析我们区块链中所有的区块哈希值,我们会发现它们都是以3个0开始的! 这向我们证明了这个区块确实是一个有效的区块,我们的机器必须做一些工作来挖掘这个区块。比特币区块链中的区块哈希值是这样的:比特币区块链网络上(05/17/2020) 最后开采的区块在我们的 Blockchain类的完整代码如下所示:请注意,我给Block添加了一个新的信息:时间戳而我们的Blockchain类的完整代码将如下所示:我们区块链的完整代码代码就到这里了!在下一章,我将解释我们如何改进这个实现,让区块链分布在节点网络上!第四章:改进实施我们已经成功地从头开始创建了一个完整的区块链,并在短时间内让它运行起来,但它仍然不是去中心化的,由许多节点组成。将我们的区块链实现转换为去中心化的实现会稍微复杂一些,因此我将另一篇文章中解答,但是现在我们可以讨论必须考虑的其他一些因素。目前,我们的电脑是这个区块链中唯一工作的节点。当我们调用 add_new_block方法时,所有的数据都来自我们的机器,我们的处理器也完成了所有的区块挖掘。在分布式网络上的区块链,我们会有特定的节点进行挖矿。这些节点将监听网络中正在广播的新数据或交易,并将不断尝试找到使区块有效的随机数nonce。当一个矿工找到这个随机数值时,它将向网络中广播新的区块。网络中的所有其他节点很容易验证该区块是否有效,因为他们所要做的就是将散列函数应用到具有给定随机数的块上。如果区块以 X个零开始,那么这个区块就是有效的。我们分布式网络上区块链的一个关键规则是,如果一个节点收到两个相互冲突的区块,并且两个区块都有有效的哈希值,则它必须信任具有最长历史记录的块(区块链范式:我们常说的最长链原则)。这意味着,如果我们想在我们的区块链中插入一个带有欺诈信息的区块,我们不仅必须在网络开采一个真实的区块之前开采虚假区块,而且我们必须永远继续开采区块到我们伪造的这一条区块链上。考虑到这一点,我们可以肯定,伪造一条区块链的唯一方法是拥有超过一半的网络算力。只有当你恰好拥有一半以上的网络算力时,你才会有必要的计算能力将伪造的区块插入链中,并从那里继续计算下去,添加新的区块,成为最长的那条链。在像比特币或以太坊区块链这样的大型可信区块链网络中,拥有超过一半的网络实际上是不可能的,所以我们可以保证区块链是安全的。结 论现在我们已经了解了区块链的工作原理,以及为什么区块链如此重要。我们已经建立了自己的功能区块链,可以在区块中存储数据,并通过工作量证明来挖掘区块。本文的代码网址:https://github.com/jzsiggy/blockchain-from-scratch。欢迎克隆、分叉或复制代码。如果你有任何建议,也欢迎给出您的反馈!希望这篇文章能对你有所帮助或启发! 参考文献:1.学习和构建Javascripthttps://medium.com/@spenserhuang/learn-build-a-javascript-blockchain-part-1-ca61c285821e2.用Java 编程区块链https://medium.com/digitalcrafts/programming-blockchain-in-javascript-8051cab272da3.Carbon制作的代码段— https://carbon.now.sh/4.视频资料在公众号内发布于 2020-06-16 23:30区块链技术区块链(Blockchain)区块链价值赞同 251 条评论分享喜欢收藏申请
Dapps - 去中心化应用 | ethereum.org
s - 去中心化应用 | ethereum.org跳转至主要内容学习用法构建参与研究搜索语言 ZH帮助更新此页面本页面有新版本,但现在只有英文版。请帮助我们翻译最新版本。翻译页面没有错误!此页面未翻译,因此特意以英文显示。不再显示Dapps - 去中心化应用由以太坊提供支持的工具和服务去中心化应用程序是运用以太坊网络来打破传统商业模式或发明新商业模式的蓬勃发展的应用新运动。探索去中心化应用程序什么是Dapp?开始体验如果想要使用去中心化应用程序,你得先有一个钱包以及一些以太币。钱包可以使你连接并登录,而以太币可以用来支付任何交易费。 什么是交易费?1. 获取一些以太币去中心化应用程序的操作有交易费用作为成本获取以太币2. 创建一个钱包一个钱包地址是你“登录”去中心化应用程序的凭证查找钱包3. 准备好了吗?选择一个去中心化应用程序来尝试出发适合初学者 一些去中心化应用程序适合新手。在下面探索更多去中心化应用程序。Uniswap轻松交换你的代币。一个社区的宠儿,让你可以和全网的人交换代币。financeOpen Uniswap(opens in a new tab)OpenSea购买、出售、发现和交易限量版商品。collectiblesOpen OpenSea(opens in a new tab)Gods Unchained策略性的交易卡游戏。通过玩,赚取卡,你可以在现实生活中出售。gamingOpen Gods Unchained(opens in a new tab)Ethereum Name Service用户友好的以太坊地址和去中心化网站的名称。socialOpen Ethereum Name Service(opens in a new tab)探索去中心化应用程序很多去中心化应用程序还在实验中,测试去中心化网络的可能性。但在科技、金融、游戏和收藏品类中,已经有一些成功的先行者。选择分类金融艺术品和收藏品游戏元宇宙社交科技去中心化金融 这些是专注在构建使用加密货币进行金融服务的应用,它们提供像借、贷、赚取利息,以及不需要个人信息的私密支付等服务。坚持独立思考和研究以太坊是一种新技术,大多数应用程序都是新的。在存放大量资金之前,请确保你了解风险。贷款与借贷Aave借出你的代币赚取利息,并可随时提取。出发to Aave website(opens in a new tab)Compound借出你的代币赚取利息,并可随时提取。出发to Compound website(opens in a new tab)Oasis用Dai这个以太坊稳定币进行交易、借贷和储蓄。出发to Oasis website(opens in a new tab)PWN轻松贷由以太坊上的任意代币或非同质化代币提供支持。出发to PWN website(opens in a new tab)YearnYearn Finance 是一个收益聚合器。它为个人、DAO 和其他协议提供了一种存入数字资产并获得收益的方式。出发to Yearn website(opens in a new tab)ConvexConvex 可以让 Curve 流动性提供商在不锁定 CRV 的情况下赚取交易费用,并申请增强版 CRV。出发to Convex website(opens in a new tab)交易所Uniswap简单地交换代币或提供代币换取%的奖励。出发to Uniswap website(opens in a new tab)Loopring点对点交易平台,为速度而生。出发to Loopring website(opens in a new tab)BalancerBalancer 是一个自动化投资组合管理和交易平台。出发to Balancer website(opens in a new tab)CurveCurve 是一家专注于稳定币的去中心化交易所出发to Curve website(opens in a new tab)DODODODO 是一个链上流动性提供商,它采用的是主动做市商算法 (PMM)出发to DODO website(opens in a new tab)需求聚合器KyberSwap以最佳汇率兑换并获利。出发to KyberSwap website(opens in a new tab)Matcha搜索多个交易所,帮你找到最佳价格。出发to Matcha website(opens in a new tab)1inch通过聚合最优价格,帮助你避免高的滑点。出发to 1inch website(opens in a new tab)链桥Rubic面向用户和去中心化应用程序的跨链技术聚合器。出发to Rubic website(opens in a new tab)投资基金Token Sets自动再平衡的加密投资策略。出发to Token Sets website(opens in a new tab)PoolTogether你不会输的彩票。每周都有奖。出发to PoolTogether website(opens in a new tab)Index Coop一个加密指数基金,让你的组合获取高价值去中心化金融代币的曝光度。出发to Index Coop website(opens in a new tab)YearnYearn Finance 是一个收益聚合器。它为个人、DAO 和其他协议提供了一种存入数字资产并获得收益的方式。出发to Yearn website(opens in a new tab)ConvexConvex 可以让 Curve 流动性提供商在不锁定 CRV 的情况下赚取交易费用,并申请增强版 CRV。出发to Convex website(opens in a new tab)投资组合管理Zapper追踪你的投资组合,从同一个界面使用一系列去中心化金融产品。出发to Zapper website(opens in a new tab)Zerion管理你的投资组合,简单地评估市场上的每一项去中心化金融资产。出发to Zerion website(opens in a new tab)Rotki开源投资组合跟踪、分析、会计和税务报告工具,会尊重你的隐私。出发to Rotki website(opens in a new tab)Krystal一个可访问所有你最欢的去中心化金融服务的一站式平台。出发to Krystal website(opens in a new tab)保险Nexus Mutual无保险公司投保。免受智能合约漏洞和黑客的影响。出发to Nexus Mutual website(opens in a new tab)Etherisc去中心化的保险模板,任何人都可以用其来建立自己的保险赔付范围。出发to Etherisc website(opens in a new tab)支付Sablier实时流转资金。出发to Sablier website(opens in a new tab)众筹Gitcoin Grants为以太坊社区项目进行众筹,并扩大捐献。出发to Gitcoin Grants website(opens in a new tab)衍生品SynthetixSynthetix 是一个用于发行和交易合成资产的协议出发to Synthetix website(opens in a new tab)流动性质押Lido简便安全的数字资产质押。出发to Lido website(opens in a new tab)Ankr一系列完全存在于区块链上的不同的 Web3 基础设施产品,用于构建、获利、游戏等。出发to Ankr website(opens in a new tab)预测市场Polymarket在结果上下注。在信息市场上交易。出发to Polymarket website(opens in a new tab)Augur投注体育、经济和更多世界事件的结果。出发to Augur website(opens in a new tab)SynthetixSynthetix 是一个用于发行和交易合成资产的协议出发to Synthetix website(opens in a new tab)查看钱包钱包同样也是去中心化应用程序,根据功能最适合你的原则选择一个钱包。查找钱包魔法 背后 去中心化金融以太坊为什么可以让分散式金融应用得以蓬勃发展?开源你无需注册便可使用以太坊的交易服务。只要你有资金和网络连接,就可以进行交易了。一个新的代币经济你可以通过这些金融产品和全世界的代币互动,人们随时随刻在以太网络的基础上铸造新的代币稳定币团队新推出的稳定币 — 一种更稳定的加密货币。这允许你可以在没有风险和不确定性的情况下去实验并使用加密货币。互联金融服务以太坊领域的金融产品都是模块化并且彼此兼容的。这些模块的配置在不断地更新,赋予了你手中加密货币更多的能力。关于去中心化金融的更多信息去中心化应用程序的魔法去中心化应用程序可能会让人觉得是普通的应用。但在背后,它们有一些不一样的优秀特性,因为它们继承了所有以太坊的超能力。点击这里了解为什么去中心化应用程序不同于一般应用。为什么我们说以太坊伟大?没有所有者一旦部署到以太坊上,去中心化应用程序代码就无法删除。而且任何人都可以使用去中心化应用程序的功能。即使去中心化应用程序背后的团队解散了,你仍然可以使用它。一旦在以太坊上,它就会留在那里。免审查内置付款即插即用匿名登录加密保护无需下载去中心化应用程序工作原理去中心化应用程序的后端代码(智能合约)运行在一个去中心化的网络上,而非中心化的服务器。他们使用以太坊区块链网络作为数据存储端,并且用智能合约实现app的业务逻辑。一个智能合约像是一套设立在区块链上的规则,所有人都可以准确地观察和运行这套规则。设想一下,有一台自动贩卖机:如果向它提供足够的资金和正确的选择,你将得到你想要的货品。正如自动贩卖机一样,智能合约可以像你的以太坊帐户一样存储持有资金。这允许代码之间协议和交易。一旦去中心化应用程序部署到以太坊网络,你将无法更改他们。去中心化应用程序之所以可以被去中心化就是因为他们被合约中的逻辑所控制,而不是公司或者个人。去中心化应用程序简介智能合约学习创建一个去中心化应用程序我们的社区开发者门户拥有文档、工具和框架来帮助你开始构建一个去中心化应用程序。开始构建本页面对你有帮助吗?是否网站最后更新: 2024年2月16日(opens in a new tab)(opens in a new tab)(opens in a new tab)使用以太坊查找钱包获取以太币Dapps - 去中心化应用二层网络运行节点稳定币质押ETH学习学习中心什么是以太坊?什么是以太币 (ETH)?以太坊钱包Gas fees以太坊安全和预防欺诈措施什么是 Web3?智能合约以太坊能源消耗以太坊路线图以太坊改进提案 (Eip)以太坊的历史以太坊白皮书以太坊词汇表以太坊治理区块链桥零知识证明测试中心开发者开始体验相关文档教程通过编码来学习设置本地环境生态系统社区中心以太坊基金会以太坊基金会的博客(opens in a new tab)生态系统支持方案(opens in a new tab)以太坊漏洞悬赏计划生态系统资助计划以太坊品牌资产Devcon(opens in a new tab)企业级应用主网以太坊私密以太坊企业级应用关于ethereum.org关于我们工作机会参与贡献语言支持隐私政策使用条款缓存政策联系我们(opens in a new t如何做好区块链APP开发-腾讯云开发者社区-腾讯云
区块链APP开发-腾讯云开发者社区-腾讯云软银云商项目包装如何做好区块链APP开发关注作者腾讯云开发者社区文档建议反馈控制台首页学习活动专区工具TVP最新优惠活动文章/答案/技术大牛搜索搜索关闭发布登录/注册首页学习活动专区工具TVP最新优惠活动返回腾讯云官网软银云商项目包装首页学习活动专区工具TVP最新优惠活动返回腾讯云官网社区首页 >专栏 >如何做好区块链APP开发如何做好区块链APP开发软银云商项目包装关注发布于 2023-03-24 08:37:578440发布于 2023-03-24 08:37:57举报文章被收录于专栏:用户6321607的专栏用户6321607的专栏随着区块链在各个产业的应用,区块链在各行各业发挥出重要的作用。去中心化,加密是区块链最重要的特性。如何开发区块链的APP和DAPP,是每一个项目负责人最为关心的事情。2023年以来,区块链项目得到了市场的火热追捧,更多去中心化的项目踊跃出现,这其中不乏佼佼者。例如defi、gamefi、dao等,都有着不俗的表现。在众多新项目中,区块链将会是最受欢迎的产品之一。那么如何开发出好的区块链APP,我们软银云商从以下几个方面为您解析:1、提高数据传输速度我们都知道,区块链可以提升我们的数据传输速度,并且对区块链的节点进行了加密,因此其存储性能是非常高的。我们现在使用手机来进行视频、图片等一些数据存储的话,那么就需要把数据写入到区块链中。如果我们把数据发送到云端之后,然后再将数据传输到本地,就会变得非常慢。而使用普通电脑进行数据传输时是很麻烦又浪费时间且不准确的。但是在区块链上就不会有这样的问题出现。因为区块链本身就是一个分布式账本数据库。每一个节点都在自己保存下自己的原始档案信息,并保存在自己的数据库里。当它们想要发送信息时,就需要在他们自己的数据库里面进行操作,这就保证了一个高效而不会有任何延迟。因此整个数据传输都是非常迅速的。因此不管是对于用户还是对于电脑和服务器来说速度都是非常快同时还可以很好地保护我们自己的数据。2、保证数据安全区块链 APP开发技术在数据安全上也是非常值得重视的。由于智能合约的使用规则,不能修改数据,在用户使用时有可能会存在一定安全风险。所以一定要严格执行规则及流程。在数据存储上也是要做好安全防护。因为在网络世界里,如果出现数据泄露,那是非常严重的。区块链是一个基于区块结构而建立的系统,而非一种算法。这意味着只要有人能使用网络,那么就可以对其进行篡改。并且可以很容易地利用该漏洞窃取用户数据。同时,区块链拥有一个独特而先进的技术,所以可以防止被黑客攻击或窃取。3、为行业发展提供保障在互联网发展的过程中,不可避免地出现了一些问题。在这种情况下,区块链可以为整个行业服务。行业未来可能会出现许多新的技术革新,但始终不会改变。区块链的应用将会为整个行业提供保障。例如:去中心化网络的建立。这将保证整个网络不会被任何人控制。也就意味着整个网络中很少有哪个用户或者组织拥有所有权和控制权。所以我们将能有效地避免这些问题的出现,区块链产品对行业产生重大影响。4、设计好应用功能和应用架构其实我们一开始在开发APP初期时,就应该规划好用户的体验,当我们要开发APP时,我们要想好哪些是我们APP的主要需求,提出必实现的核心功能即可,开发一个APP并不是花里胡哨的功能越多越好,真正核心的逻辑和功能才能为客户带来最棒的价值,捋顺好最主要的功能,才能做好应用的架构,我们的APP性能不好,可能是因为扩展性受到了限制,不能够匹配技术的选择,过低的网络配置和UI设计不符合用户使用的习惯等等的因素,只要有清楚的APP架构规划才能构建出用户所需要的功能本文系转载,前往查看如有侵权,请联系 cloudcommunity@tencent.com 删除。区块链app开发数据网络本文系转载,前往查看如有侵权,请联系 cloudcommunity@tencent.com 删除。区块链app开发数据网络评论作者已关闭评论0 条评论热度最新作者已关闭评论推荐阅读LV.关注文章0获赞0相关产品与服务区块链云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。产品介绍2024新春采购节领券社区专栏文章阅读清单互动问答技术沙龙技术视频团队主页腾讯云TI平台活动自媒体分享计划邀请作者入驻自荐上首页技术竞赛资源技术周刊社区标签开发者手册开发者实验室关于社区规范免责声明联系我们友情链接腾讯云开发者扫码关注腾讯云开发者领取腾讯云代金券热门产品域名注册云服务器区块链服务消息队列网络加速云数据库域名解析云存储视频直播热门推荐人脸识别腾讯会议企业云CDN加速视频通话图像分析MySQL 数据库SSL 证书语音识别更多推荐数据安全负载均衡短信文字识别云点播商标注册小程序开发网站监控数据迁移Copyright © 2013 - 2024 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有 深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档Copyright © 2013 - 2024 Tencent Cloud.All Rights Reserved. 腾讯云 版权所有作者已关闭评论00开发第一个区块链应用 — FISCO BCOS 2.0 v2.9.0 文档
开发第一个区块链应用 — FISCO BCOS 2.0 v2.9.0 文档
FISCO BCOS 2.0
latest
平台介绍
FISCO BCOS 区块链
版本信息
快速开始
搭建第一个区块链网络
开发第一个区块链应用
1. 了解应用需求
2. 设计与开发智能合约
第一步. 设计智能合约
第二步. 开发源码
3. 编译智能合约
4. 创建区块链应用项目
第一步. 安装环境
第二步. 创建一个Java工程
第三步. 引入FISCO BCOS Java SDK
第四步. 配置SDK证书
5. 业务逻辑开发
第一步.将3编译好的Java合约引入项目中
第二步.开发业务逻辑
6. 运行应用
构建和管理区块链网络
关键概念
网络搭建
配置管理
网络维护
开发区块链应用
创建和使用账户
开发和使用智能合约
多种语言SDK
区块链功能接口列表
使用链上信使
开发期问题排查
使用工具
开发部署工具(build_chain.sh)
命令行交互控制台
WeBASE管理平台
区块链浏览器
运维部署工具
数据治理通用组件
多方协作治理组件
区块链应用开发组件
系统设计
整体架构
区块链交易流程
数据结构与编码协议
核心模块设计解析
社区
MVP
贡献者
合作伙伴
深入浅出FISCO BCOS
社区资源和更多开源工具
FISCO BCOS 2.0
»
开发第一个区块链应用
Edit on GitHub
开发第一个区块链应用¶
标签:开发第一个应用 合约开发 区块链应用 教程
重要
相关软件和环境版本说明!请查看
本章将会介绍一个基于FISCO BCOS区块链的业务应用场景开发全过程,从业务场景分析,到合约的设计实现,然后介绍合约编译以及如何部署到区块链,最后介绍一个应用模块的实现,通过我们提供的Java SDK实现对区块链上合约的调用访问。
本教程要求用户熟悉Linux操作环境,具备Java开发的基本技能,能够使用Gradle工具,熟悉Solidity语法。
如果您还未搭建区块链网络,或未下载控制台,请先走完教程搭建第一个区块链网络,再回到本教程。
1. 了解应用需求¶
区块链天然具有防篡改,可追溯等特性,这些特性决定其更容易受金融领域的青睐。本示例中,将会提供一个简易的资产管理的开发示例,并最终实现以下功能:
能够在区块链上进行资产注册
能够实现不同账户的转账
可以查询账户的资产金额
2. 设计与开发智能合约¶
在区块链上进行应用开发时,结合业务需求,首先需要设计对应的智能合约,确定合约需要储存的数据,在此基础上确定智能合约对外提供的接口,最后给出各个接口的具体实现。
第一步. 设计智能合约¶
存储设计
FISCO BCOS提供合约CRUD接口开发模式,可以通过合约创建表,并对创建的表进行增删改查操作。针对本应用需要设计一个存储资产管理的表t_asset,该表字段如下:
account: 主键,资产账户(string类型)
asset_value: 资产金额(uint256类型)
其中account是主键,即操作t_asset表时需要传入的字段,区块链根据该主键字段查询表中匹配的记录。t_asset表示例如下:
account
asset_value
Alice
10000
Bob
20000
接口设计
按照业务的设计目标,需要实现资产注册,转账,查询功能,对应功能的接口如下:
// 查询资产金额
function select(string account) public constant returns(int256, uint256)
// 资产注册
function register(string account, uint256 amount) public returns(int256)
// 资产转移
function transfer(string from_asset_account, string to_asset_account, uint256 amount) public returns(int256)
第二步. 开发源码¶
根据我们第一步的存储和接口设计,创建一个Asset的智能合约,实现注册、转账、查询功能,并引入一个叫Table的系统合约,这个合约提供了CRUD接口。
# 进入console/contracts目录
cd ~/fisco/console/contracts/solidity
# 创建Asset.sol合约文件
vi Asset.sol
# 将Assert.sol合约内容写入。
# 并键入wq保存退出。
Asset.sol的内容如下:
pragma solidity ^0.4.24;
import "./Table.sol";
contract Asset {
// event
event RegisterEvent(int256 ret, string account, uint256 asset_value);
event TransferEvent(int256 ret, string from_account, string to_account, uint256 amount);
constructor() public {
// 构造函数中创建t_asset表
createTable();
}
function createTable() private {
TableFactory tf = TableFactory(0x1001);
// 资产管理表, key : account, field : asset_value
// | 资产账户(主键) | 资产金额 |
// |-------------------- |-------------------|
// | account | asset_value |
// |---------------------|-------------------|
//
// 创建表
tf.createTable("t_asset", "account", "asset_value");
}
function openTable() private returns(Table) {
TableFactory tf = TableFactory(0x1001);
Table table = tf.openTable("t_asset");
return table;
}
/*
描述 : 根据资产账户查询资产金额
参数 :
account : 资产账户
返回值:
参数一: 成功返回0, 账户不存在返回-1
参数二: 第一个参数为0时有效,资产金额
*/
function select(string account) public constant returns(int256, uint256) {
// 打开表
Table table = openTable();
// 查询
Entries entries = table.select(account, table.newCondition());
uint256 asset_value = 0;
if (0 == uint256(entries.size())) {
return (-1, asset_value);
} else {
Entry entry = entries.get(0);
return (0, uint256(entry.getInt("asset_value")));
}
}
/*
描述 : 资产注册
参数 :
account : 资产账户
amount : 资产金额
返回值:
0 资产注册成功
-1 资产账户已存在
-2 其他错误
*/
function register(string account, uint256 asset_value) public returns(int256){
int256 ret_code = 0;
int256 ret= 0;
uint256 temp_asset_value = 0;
// 查询账户是否存在
(ret, temp_asset_value) = select(account);
if(ret != 0) {
Table table = openTable();
Entry entry = table.newEntry();
entry.set("account", account);
entry.set("asset_value", int256(asset_value));
// 插入
int count = table.insert(account, entry);
if (count == 1) {
// 成功
ret_code = 0;
} else {
// 失败? 无权限或者其他错误
ret_code = -2;
}
} else {
// 账户已存在
ret_code = -1;
}
emit RegisterEvent(ret_code, account, asset_value);
return ret_code;
}
/*
描述 : 资产转移
参数 :
from_account : 转移资产账户
to_account : 接收资产账户
amount : 转移金额
返回值:
0 资产转移成功
-1 转移资产账户不存在
-2 接收资产账户不存在
-3 金额不足
-4 金额溢出
-5 其他错误
*/
function transfer(string from_account, string to_account, uint256 amount) public returns(int256) {
// 查询转移资产账户信息
int ret_code = 0;
int256 ret = 0;
uint256 from_asset_value = 0;
uint256 to_asset_value = 0;
// 转移账户是否存在?
(ret, from_asset_value) = select(from_account);
if(ret != 0) {
ret_code = -1;
// 转移账户不存在
emit TransferEvent(ret_code, from_account, to_account, amount);
return ret_code;
}
// 接受账户是否存在?
(ret, to_asset_value) = select(to_account);
if(ret != 0) {
ret_code = -2;
// 接收资产的账户不存在
emit TransferEvent(ret_code, from_account, to_account, amount);
return ret_code;
}
if(from_asset_value < amount) {
ret_code = -3;
// 转移资产的账户金额不足
emit TransferEvent(ret_code, from_account, to_account, amount);
return ret_code;
}
if (to_asset_value + amount < to_asset_value) {
ret_code = -4;
// 接收账户金额溢出
emit TransferEvent(ret_code, from_account, to_account, amount);
return ret_code;
}
Table table = openTable();
Entry entry0 = table.newEntry();
entry0.set("account", from_account);
entry0.set("asset_value", int256(from_asset_value - amount));
// 更新转账账户
int count = table.update(from_account, entry0, table.newCondition());
if(count != 1) {
ret_code = -5;
// 失败? 无权限或者其他错误?
emit TransferEvent(ret_code, from_account, to_account, amount);
return ret_code;
}
Entry entry1 = table.newEntry();
entry1.set("account", to_account);
entry1.set("asset_value", int256(to_asset_value + amount));
// 更新接收账户
table.update(to_account, entry1, table.newCondition());
emit TransferEvent(ret_code, from_account, to_account, amount);
return ret_code;
}
}
Asset.sol所引用的Table.sol已在~/fisco/console/contracts/solidity目录下。该系统合约文件中的接口由FISCO BCOS底层实现。当业务合约需要操作CRUD接口时,均需要引入该接口合约文件。Table.sol 合约详细接口参考这里。
运行ls命令,确保Asset.sol和Table.sol在目录~/fisco/console/contracts/solidity下。
3. 编译智能合约¶
.sol的智能合约需要编译成ABI和BIN文件才能部署至区块链网络上。有了这两个文件即可凭借Java SDK进行合约部署和调用。但这种调用方式相对繁琐,需要用户根据合约ABI来传参和解析结果。为此,控制台提供的编译工具不仅可以编译出ABI和BIN文件,还可以自动生成一个与编译的智能合约同名的合约Java类。这个Java类是根据ABI生成的,帮助用户解析好了参数,提供同名的方法。当应用需要部署和调用合约时,可以调用该合约类的对应方法,传入指定参数即可。使用这个合约Java类来开发应用,可以极大简化用户的代码。
# 创建工作目录~/fisco
mkdir -p ~/fisco
# 下载控制台
cd ~/fisco && curl -#LO https://github.com/FISCO-BCOS/console/releases/download/v2.9.2/download_console.sh && bash download_console.sh
# 切换到fisco/console/目录
cd ~/fisco/console/
# 若控制台版本大于等于2.8.0,编译合约方法如下:(可通过bash sol2java.sh -h命令查看该脚本使用方法)
bash sol2java.sh -p org.fisco.bcos.asset.contract
# 若控制台版本小于2.8.0,编译合约(后面指定一个Java的包名参数,可以根据实际项目路径指定包名)如下:
./sol2java.sh org.fisco.bcos.asset.contract
运行成功之后,将会在console/contracts/sdk目录生成java、abi和bin目录,如下所示。
# 其它无关文件省略
|-- abi # 生成的abi目录,存放solidity合约编译生成的abi文件
| |-- Asset.abi
| |-- Table.abi
|-- bin # 生成的bin目录,存放solidity合约编译生成的bin文件
| |-- Asset.bin
| |-- Table.bin
|-- contracts # 存放solidity合约源码文件,将需要编译的合约拷贝到该目录下
| |-- Asset.sol # 拷贝进来的Asset.sol合约,依赖Table.sol
| |-- Table.sol # 实现系统CRUD操作的合约接口文件
|-- java # 存放编译的包路径及Java合约文件
| |-- org
| |--fisco
| |--bcos
| |--asset
| |--contract
| |--Asset.java # Asset.sol合约生成的Java文件
| |--Table.java # Table.sol合约生成的Java文件
|-- sol2java.sh
java目录下生成了org/fisco/bcos/asset/contract/包路径目录,该目录下包含Asset.java和Table.java两个文件,其中Asset.java是Java应用调用Asset.sol合约需要的文件。
Asset.java的主要接口:
package org.fisco.bcos.asset.contract;
public class Asset extends Contract {
// Asset.sol合约 transfer接口生成
public TransactionReceipt transfer(String from_account, String to_account, BigInteger amount);
// Asset.sol合约 register接口生成
public TransactionReceipt register(String account, BigInteger asset_value);
// Asset.sol合约 select接口生成
public Tuple2
// 加载Asset合约地址,生成Asset对象
public static Asset load(String contractAddress, Client client, CryptoKeyPair credential);
// 部署Assert.sol合约,生成Asset对象
public static Asset deploy(Client client, CryptoKeyPair credential) throws ContractException;
}
其中load与deploy函数用于构造Asset对象,其他接口分别用来调用对应的solidity合约的接口。
4. 创建区块链应用项目¶
第一步. 安装环境¶
首先,我们需要安装JDK以及集成开发环境
Java:JDK 14 (JDK1.8 至JDK 14都支持)
首先,在官网上下载JDK14并安装
然后,修改环境变量
# 确认您当前的java版本
$ java -version
# 确认您的java路径
$ ls /Library/Java/JavaVirtualMachines
# 返回
# jdk-14.0.2.jdk
# 如果使用的是bash
$ vim .bash_profile
# 在文件中加入JAVA_HOME的路径
# export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-14.0.2.jdk/Contents/Home
$ source .bash_profile
# 如果使用的是zash
$ vim .zashrc
# 在文件中加入JAVA_HOME的路径
# export JAVA_HOME = Library/Java/JavaVirtualMachines/jdk-14.0.2.jdk/Contents/Home
$ source .zashrc
# 确认您的java版本
$ java -version
# 返回
# java version "14.0.2" 2020-07-14
# Java(TM) SE Runtime Environment (build 14.0.2+12-46)
# Java HotSpot(TM) 64-Bit Server VM (build 14.0.2+12-46, mixed mode, sharing)
IDE:IntelliJ IDE.
进入IntelliJ IDE官网,下载并安装社区版IntelliJ IDE
第二步. 创建一个Java工程¶
在IntelliJ IDE中创建一个gradle项目,勾选Gradle和Java,并输入工程名asset-app。
注意:该项目的源码可以用以下方法获得并参考。(此步骤为非必须步骤)
$ cd ~/fisco
$ curl -#LO https://github.com/FISCO-BCOS/LargeFiles/raw/master/tools/asset-app.tar.gz
# 解压得到Java工程项目asset-app
$ tar -zxf asset-app.tar.gz
注解
如果因为网络问题导致长时间无法下载,请尝试将`199.232.28.133 raw.githubusercontent.com`追加到`/etc/hosts`中,或者请尝试 curl -#LO https://osp-1257653870.cos.ap-guangzhou.myqcloud.com/FISCO-BCOS/FISCO-BCOS/tools/asset-app.tar.gz
第三步. 引入FISCO BCOS Java SDK¶
在build.gradle文件中的dependencies下加入对FISCO BCOS Java SDK的引用。
repositories {
mavenCentral()
maven {
allowInsecureProtocol = true
url "http://maven.aliyun.com/nexus/content/groups/public/"
}
maven {
allowInsecureProtocol = true
url "https://oss.sonatype.org/content/repositories/snapshots"
}
}
引入Java SDK jar包
testImplementation group: 'junit', name: 'junit', version: '4.12'
implementation ('org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:2.9.1')
第四步. 配置SDK证书¶
修改build.gradle文件,引入Spring框架。
def spring_version = "4.3.27.RELEASE"
List spring = [
"org.springframework:spring-core:$spring_version",
"org.springframework:spring-beans:$spring_version",
"org.springframework:spring-context:$spring_version",
"org.springframework:spring-tx:$spring_version",
]
dependencies {
testImplementation group: 'junit', name: 'junit', version: '4.12'
implementation ("org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:2.9.1")
implementation spring
}
在asset-app/test/resources目录下创建配置文件applicationContext.xml,写入配置内容。各配置项的内容可参考Java SDK 配置说明,该配置说明以toml配置文件为例,本例中的配置项与该配置项相对应。
applicationContext.xml的内容如下:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
注意: 如果搭链时设置的jsonrpc_listen_ip为127.0.0.1或者0.0.0.0,channel_port为20200, 则applicationContext.xml配置不用修改。若区块链节点配置有改动,需要同样修改配置applicationContext.xml的network属性下的peers配置选项,配置所连接节点的IP:channel_listen_port。
在以上配置文件中,我们指定了证书存放的位certPath的值为conf。接下来我们需要把SDK用于连接节点的证书放到指定的conf目录下。
# 假设我们将asset-app放在~/fisco目录下 进入~/fisco目录
$ cd ~/fisco
# 创建放置证书的文件夹
$ mkdir -p asset-app/src/test/resources/conf
# 拷贝节点证书到项目的资源目录
$ cp -r nodes/127.0.0.1/sdk/* asset-app/src/test/resources/conf
# 若在IDE直接运行,拷贝证书到resources路径
$ mkdir -p asset-app/src/main/resources/conf
$ cp -r nodes/127.0.0.1/sdk/* asset-app/src/main/resources/conf
5. 业务逻辑开发¶
我们已经介绍了如何在自己的项目中引入以及配置Java SDK,本节介绍如何通过Java程序调用合约,同样以示例的资产管理说明。
第一步.将3编译好的Java合约引入项目中¶
cd ~/fisco
# 将编译好的合约Java类引入项目中。
cp console/contracts/sdk/java/org/fisco/bcos/asset/contract/Asset.java asset-app/src/main/java/org/fisco/bcos/asset/contract/Asset.java
第二步.开发业务逻辑¶
在路径/src/main/java/org/fisco/bcos/asset/client目录下,创建AssetClient.java类,通过调用Asset.java实现对合约的部署与调用
AssetClient.java 代码如下:
package org.fisco.bcos.asset.client;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Properties;
import org.fisco.bcos.asset.contract.Asset;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
public class AssetClient {
static Logger logger = LoggerFactory.getLogger(AssetClient.class);
private BcosSDK bcosSDK;
private Client client;
private CryptoKeyPair cryptoKeyPair;
public void initialize() throws Exception {
@SuppressWarnings("resource")
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
bcosSDK = context.getBean(BcosSDK.class);
client = bcosSDK.getClient(1);
cryptoKeyPair = client.getCryptoSuite().createKeyPair();
client.getCryptoSuite().setCryptoKeyPair(cryptoKeyPair);
logger.debug("create client for group1, account address is " + cryptoKeyPair.getAddress());
}
public void deployAssetAndRecordAddr() {
try {
Asset asset = Asset.deploy(client, cryptoKeyPair);
System.out.println(
" deploy Asset success, contract address is " + asset.getContractAddress());
recordAssetAddr(asset.getContractAddress());
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println(" deploy Asset contract failed, error message is " + e.getMessage());
}
}
public void recordAssetAddr(String address) throws FileNotFoundException, IOException {
Properties prop = new Properties();
prop.setProperty("address", address);
final Resource contractResource = new ClassPathResource("contract.properties");
FileOutputStream fileOutputStream = new FileOutputStream(contractResource.getFile());
prop.store(fileOutputStream, "contract address");
}
public String loadAssetAddr() throws Exception {
// load Asset contact address from contract.properties
Properties prop = new Properties();
final Resource contractResource = new ClassPathResource("contract.properties");
prop.load(contractResource.getInputStream());
String contractAddress = prop.getProperty("address");
if (contractAddress == null || contractAddress.trim().equals("")) {
throw new Exception(" load Asset contract address failed, please deploy it first. ");
}
logger.info(" load Asset address from contract.properties, address is {}", contractAddress);
return contractAddress;
}
public void queryAssetAmount(String assetAccount) {
try {
String contractAddress = loadAssetAddr();
Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);
Tuple2
if (result.getValue1().compareTo(new BigInteger("0")) == 0) {
System.out.printf(" asset account %s, value %s \n", assetAccount, result.getValue2());
} else {
System.out.printf(" %s asset account is not exist \n", assetAccount);
}
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
logger.error(" queryAssetAmount exception, error message is {}", e.getMessage());
System.out.printf(" query asset account failed, error message is %s\n", e.getMessage());
}
}
public void registerAssetAccount(String assetAccount, BigInteger amount) {
try {
String contractAddress = loadAssetAddr();
Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);
TransactionReceipt receipt = asset.register(assetAccount, amount);
List
if (!response.isEmpty()) {
if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) {
System.out.printf(
" register asset account success => asset: %s, value: %s \n", assetAccount, amount);
} else {
System.out.printf(
" register asset account failed, ret code is %s \n", response.get(0).ret.toString());
}
} else {
System.out.println(" event log not found, maybe transaction not exec. ");
}
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
logger.error(" registerAssetAccount exception, error message is {}", e.getMessage());
System.out.printf(" register asset account failed, error message is %s\n", e.getMessage());
}
}
public void transferAsset(String fromAssetAccount, String toAssetAccount, BigInteger amount) {
try {
String contractAddress = loadAssetAddr();
Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);
TransactionReceipt receipt = asset.transfer(fromAssetAccount, toAssetAccount, amount);
List
if (!response.isEmpty()) {
if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) {
System.out.printf(
" transfer success => from_asset: %s, to_asset: %s, amount: %s \n",
fromAssetAccount, toAssetAccount, amount);
} else {
System.out.printf(
" transfer asset account failed, ret code is %s \n", response.get(0).ret.toString());
}
} else {
System.out.println(" event log not found, maybe transaction not exec. ");
}
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
logger.error(" registerAssetAccount exception, error message is {}", e.getMessage());
System.out.printf(" register asset account failed, error message is %s\n", e.getMessage());
}
}
public static void Usage() {
System.out.println(" Usage:");
System.out.println(
"\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient deploy");
System.out.println(
"\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient query account");
System.out.println(
"\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient register account value");
System.out.println(
"\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient transfer from_account to_account amount");
System.exit(0);
}
public static void main(String[] args) throws Exception {
if (args.length < 1) {
Usage();
}
AssetClient client = new AssetClient();
client.initialize();
switch (args[0]) {
case "deploy":
client.deployAssetAndRecordAddr();
break;
case "query":
if (args.length < 2) {
Usage();
}
client.queryAssetAmount(args[1]);
break;
case "register":
if (args.length < 3) {
Usage();
}
client.registerAssetAccount(args[1], new BigInteger(args[2]));
break;
case "transfer":
if (args.length < 4) {
Usage();
}
client.transferAsset(args[1], args[2], new BigInteger(args[3]));
break;
default:
{
Usage();
}
}
System.exit(0);
}
}
让我们通过AssetClient这个例子,来了解FISCO BCOS Java SDK的调用:
初始化
初始化代码的主要功能为构造Client与CryptoKeyPair对象,这两个对象在创建对应的合约类对象(调用合约类的deploy或者load函数)时需要使用。
// 函数initialize中进行初始化
// 初始化BcosSDK
@SuppressWarnings("resource")
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
bcosSDK = context.getBean(BcosSDK.class);
// 初始化可向群组1发交易的Client
client = bcosSDK.getClient(1);
// 随机生成发送交易的公私钥对
cryptoKeyPair = client.getCryptoSuite().createKeyPair();
client.getCryptoSuite().setCryptoKeyPair(cryptoKeyPair);
logger.debug("create client for group1, account address is " + cryptoKeyPair.getAddress());
构造合约类对象
可以使用deploy或者load函数初始化合约对象,两者使用场景不同,前者适用于初次部署合约,后者在合约已经部署并且已知合约地址时使用。
// 部署合约
Asset asset = Asset.deploy(client, cryptoKeyPair);
// 加载合约地址
Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);
接口调用
使用合约对象调用对应的接口,处理返回结果。
// select接口调用
Tuple2
// register接口调用
TransactionReceipt receipt = asset.register(assetAccount, amount);
// transfer接口
TransactionReceipt receipt = asset.transfer(fromAssetAccount, toAssetAccount, amount);
在asset-app/tool目录下添加一个调用AssetClient的脚本asset_run.sh。
#!/bin/bash
function usage()
{
echo " Usage : "
echo " bash asset_run.sh deploy"
echo " bash asset_run.sh query asset_account "
echo " bash asset_run.sh register asset_account asset_amount "
echo " bash asset_run.sh transfer from_asset_account to_asset_account amount "
echo " "
echo " "
echo "examples : "
echo " bash asset_run.sh deploy "
echo " bash asset_run.sh register Asset0 10000000 "
echo " bash asset_run.sh register Asset1 10000000 "
echo " bash asset_run.sh transfer Asset0 Asset1 11111 "
echo " bash asset_run.sh query Asset0"
echo " bash asset_run.sh query Asset1"
exit 0
}
case $1 in
deploy)
[ $# -lt 1 ] && { usage; }
;;
register)
[ $# -lt 3 ] && { usage; }
;;
transfer)
[ $# -lt 4 ] && { usage; }
;;
query)
[ $# -lt 2 ] && { usage; }
;;
*)
usage
;;
esac
java -Djdk.tls.namedGroups="secp256k1" -cp 'apps/*:conf/:lib/*' org.fisco.bcos.asset.client.AssetClient $@
接着,配置好log。在asset-app/src/test/resources目录下创建log4j.properties
### set log levels ###
log4j.rootLogger=DEBUG, file
### output the log information to the file ###
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern='_'yyyyMMddHH'.log'
log4j.appender.file.File=./log/sdk.log
log4j.appender.file.Append=true
log4j.appender.file.filter.traceFilter=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n
###output the log information to the console ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n
接着,通过配置gradle中的Jar命令,指定复制和编译任务。并引入日志库,在asset-app/src/test/resources目录下,创建一个空的contract.properties文件,用于应用在运行时存放合约地址。
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile ("org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:2.9.1")
compile spring
compile ('org.slf4j:slf4j-log4j12:1.7.25')
runtime ('org.slf4j:slf4j-log4j12:1.7.25')
}
jar {
destinationDir file('dist/apps')
archiveName project.name + '.jar'
exclude '**/*.xml'
exclude '**/*.properties'
exclude '**/*.crt'
exclude '**/*.key'
doLast {
copy {
from configurations.runtime
into 'dist/lib'
}
copy {
from file('src/test/resources/')
into 'dist/conf'
}
copy {
from file('tool/')
into 'dist/'
}
copy {
from file('src/test/resources/contract')
into 'dist/contract'
}
}
}
至此,我们已经完成了这个应用的开发。最后,我们得到的assert-app的目录结构如下:
|-- build.gradle // gradle配置文件
|-- gradle
| |-- wrapper
| |-- gradle-wrapper.jar // 用于下载Gradle的相关代码实现
| |-- gradle-wrapper.properties // wrapper所使用的配置信息,比如gradle的版本等信息
|-- gradlew // Linux或者Unix下用于执行wrapper命令的Shell脚本
|-- gradlew.bat // Windows下用于执行wrapper命令的批处理脚本
|-- src
| |-- main
| | |-- java
| | | |-- org
| | | |-- fisco
| | | |-- bcos
| | | |-- asset
| | | |-- client // 放置客户端调用类
| | | |-- AssetClient.java
| | | |-- contract // 放置Java合约类
| | | |-- Asset.java
| | |-- resources
| | |-- conf
| | |-- ca.crt
| | |-- node.crt
| | |-- node.key
| | |-- sdk.crt
| | |-- sdk.key
| | |-- sdk.publickey
| | |-- applicationContext.xml // 项目配置文件
| | |-- contract.properties // 存储部署合约地址的文件
| | |-- log4j.properties // 日志配置文件
| | |-- contract //存放solidity约文件
| | |-- Asset.sol
| | |-- Table.sol
| |-- test
| |-- resources // 存放代码资源文件
| |-- conf
| |-- ca.crt
| |-- node.crt
| |-- node.key
| |-- sdk.crt
| |-- sdk.key
| |-- sdk.publickey
| |-- applicationContext.xml // 项目配置文件
| |-- contract.properties // 存储部署合约地址的文件
| |-- log4j.properties // 日志配置文件
| |-- contract //存放solidity约文件
| |-- Asset.sol
| |-- Table.sol
|
|-- tool
|-- asset_run.sh // 项目运行脚本
6. 运行应用¶
至此我们已经介绍使用区块链开发资产管理应用的所有流程并实现了功能,接下来可以运行项目,测试功能是否正常。
编译
# 切换到项目目录
$ cd ~/fisco/asset-app
# 编译项目
$ ./gradlew build
编译成功之后,将在项目根目录下生成dist目录。dist目录下有一个asset_run.sh脚本,简化项目运行。现在开始一一验证本文开始定下的需求。
部署Asset.sol合约
# 进入dist目录
$ cd dist
$ bash asset_run.sh deploy
Deploy Asset successfully, contract address is 0xd09ad04220e40bb8666e885730c8c460091a4775
注册资产
$ bash asset_run.sh register Alice 100000
Register account successfully => account: Alice, value: 100000
$ bash asset_run.sh register Bob 100000
Register account successfully => account: Bob, value: 100000
查询资产
$ bash asset_run.sh query Alice
account Alice, value 100000
$ bash asset_run.sh query Bob
account Bob, value 100000
资产转移
$ bash asset_run.sh transfer Alice Bob 50000
Transfer successfully => from_account: Alice, to_account: Bob, amount: 50000
$ bash asset_run.sh query Alice
account Alice, value 50000
$ bash asset_run.sh query Bob
account Bob, value 150000
总结: 至此,我们通过合约开发,合约编译,SDK配置与业务开发构建了一个基于FISCO BCOS联盟区块链的应用。
Next
Previous
© Copyright FISCO BCOS 2019.
本技术文档适用于FISCO BCOS 2.x版本,FISCO BCOS 3.x版本技术文档请查看 这里, FISCO BCOS 1.3版本技术文档请查看 这里。
Revision e4c99c1c.
Built with Sphinx using a theme
provided by Read the Docs.
Read the Docs
v: latest
Versions
latest
stable
v2.8.0
v2.6.0
v2.5.0
v2.4.0
v2.3.0
v2.2.0
v2.1.0
v2.0.0
release-3.6.0
release-3.0.0-rc2
release-2-dev
release-2.9.0
release-2.8.0
release-2.7.0
release-2.1.0
release-1.3
dev
Downloads
epub
On Read the Docs
Project Home
Builds
使用 React 和 ethers.js 构建DApp | 登链社区 | 区块链技术社区
使用 React 和 ethers.js 构建DApp | 登链社区 | 区块链技术社区
文章
问答
讲堂
专栏
集市
更多
提问
发表文章
活动
文档
招聘
发现
Toggle navigation
首页 (current)
文章
问答
讲堂
专栏
活动
招聘
文档
集市
搜索
登录/注册
使用 React 和 ethers.js 构建DApp
张小风
更新于 2022-07-04 14:56
阅读 5708
使用 React 开发 DApp 入门教程
[scaffold-eth](https://github.com/scaffold-eth/scaffold-eth) 因为引入内容太多了,对于我来说太复杂了, 不知道大家有没有同感,找到一篇使用 React 开发 DApp 的非常简单入门教程。翻译一下.
在本教程中,我们将使用Hardhat、React和ethers.js[构建DAPP](https://learnblockchain.cn/article/1113),它可以与用户控制的钱包如MetaMask一起使用。
DAPP通常由三部分组成:
- 部署在链上的智能合约
- 用Node.js、React和Next.js构建的Webapp(用户界面)
- 钱包(用户在浏览器中控制的/移动钱包App)
我们使用`ethers.js`来连接各个:
![DApp解释](https://img.learnblockchain.cn/pics/20220704111811.jpeg)
在DApp(webapp)的用户界面中,MetaMask等钱包给开发者提供了一个以太坊的提供者,我们可以在`Ethers.js`中使用,与区块链进行交互。(具体来说,钱包提供的是一个 "连接器",ethers.js创建 "提供者(provider)"和/或 "签名者(signer)"供我们使用)。
作为用户,我们可能已经知道了MetaMask的用法,作为开发者,我们将学习如何使用MetaMask和它注入浏览器的`window.ethereum`([MetaMask开发者文档](https://docs.metamask.io/guide/ethereum-provider.html#using-the-provider)。
本教程的代码库在:
Hardhat项目:https://github.com/fjun99/chain-tutorial-hardhat-starter
Webapp项目:https://github.com/fjun99/web3app-tutorial-using-ethers
> **特别感谢**在准备webapp代码库时,Wesley的[Proof-of-Competence, POC](https://github.com/wslyvh/proof-of-competence)项目学到了很多。我们也像他的项目一样使用Chakra UI。你可能也会发现网页与POC几乎一样。
---
## 前置知识和工具
在我们开始之前,你需要对一下内容有一些了解:
知识:
- 区块链
- 以太坊
- 钱包
- [Solidity](https://learnblockchain.cn/docs/solidity/)
- ERC20 & ERC721
- [Ethers.js](https://learnblockchain.cn/docs/ethers.js/)
工具:
- MetaMask (钱包浏览器插件)
- Node.js, yarn, TypeScript
- OpenZeppelin (Solidity库)
- Etherscan区块浏览器
让我们开始建立一个DApp
## 任务1:设置开发环境
为了建立一个DApp,我们要做两个工作:
- 使用Hardhat和Solidity构建智能合约
- 使用Node.js、React和Next.js构建Web 应用。
我们将把目录组织成两个子目录`chain`和`webapp`:
```
- hhproject
- chain (working dir for hardhat)
- contracts
- test
- scripts
- webapp (working dir for NextJS app)
- src
- pages
- components
```
### 任务1.1 安装Hardhat并启动Hardhat项目
安装Hardhat,这是一个以太坊开发环境。
要使用Hardhat,你需要在电脑上有`node.js`和`yarn`:
- 第1步:建立一个目录并在其中安装Hardhat
```bash
mkdir hhproject && cd hhproject
mkdir chain && cd chain
yarn init -y
```
安装Hardhat:
```bash
yarn add hardhat
```
- 第2步:创建一个Hardhat样本项目
```bash
yarn hardhat
//choose: Create an advanced sample project that uses TypeScript
```
用我们将在任务3中使用的样本智能合约`Greeter.sol`创建一个hardhat项目。
- 第3步:运行Harhat网络(本地testnet)
```
yarn hardhat node
```
将运行一个本地测试网(**chainId: 31337**)。
> 开始了HTTP和WebSocket JSON-RPC服务器,地址是http://127.0.0.1:8545/
它提供了20个账户,每个账户有`10000.0测试ETH`。
```
Account #0: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 (10000 ETH)
Account #1: 0x70997970c51812dc3a010c7d01b50e0d17dc79c8
...
```
请注意,Hardhat Network本地testnet有两种模式:进程中模式和独立模式。我们用命令行`yarn hardhat node`运行一个独立的testnet。当运行像`yarn hardhat compile`这样的命令行时,如果没有网络参数(`--network localhost`),我们就运行一个进程内测试网。
### 任务1.2:在Hardhat的开发
我们将在Hardhat开发环境中体验智能合约的开发过程。
在Hardhat启动的项目中,默认包含有智能合约、测试脚本和部署脚本的样本。
```
├── contracts
│ └── Greeter.sol
├── scripts
│ └── deploy.ts
├── test
│ └── index.ts
├── hardhat.config.ts
```
我想改变测试和部署脚本的文件名:
```
- contracts
- Greeter.sol
- test
- Greeter.test.ts (<-index.ts)
- scripts
- deploy_greeter.ts (<-deploy.ts)
```
第1步:运行命令,显示账户:
```
yarn hardhat accounts
```
这是在`hardhat.config.ts`中添加的hardhat 样本任务。
第2步:编译智能合约
```
yarn hardhat compile
```
第3步:运行单元测试
```
yarn hardhat test
```
第4步:尝试部署到进程中的测试网
```
yarn hardhat run ./scripts/deploy_greeter.ts
```
在接下来的两个步骤中,将运行一个独立的Hardhat网络,并将智能合约部署上去。
第5步:运行一个独立的本地测试网
在另一个终端,运行:
```bash
yarn hardhat node
//Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
```
第6步: 部署到独立的本地测试网
```bash
yarn hardhat run ./scripts/deploy.ts --network localhost
//Greeter deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
```
如果你多次运行部署,你会发现合约实例被部署到不同的地址。
### 任务1.3:将MetaMask切换到本地测试网
确保Hardhat Network 本地测试网仍在运行(你可以通过命令`yarn hardhat node`来运行它)。
- 第1步:在MataMask浏览器插件中,点击顶部栏的网络选择。将网络从`mainnet`切换到`localhost 8545`。
- 第2步:点击顶栏上的账户图标,进入 `设置/网络/`。选择 `localhost 8445`。
注意:确保链ID是**31337**。在MetaMask中,它可能默认为 `1337`。
### 任务 1.4: 用Next.js和Chakra UI创建webapp
我们将使用`Node.js`、`React`、`Next.js`和`Chakra UI`框架创建一个webapp。(你可以选择你喜欢的任何其他UI框架,如`Material UI`,`Ant Design`等。你也可能想选择前端框架`Vue`而不是`Next.js`)
- 第1步:创建Next.js项目`webapp`。
在`hhproject/`目录下,运行:
```bash
yarn create next-app webapp --typescript
//will make a sub-dir webapp and create an empty Next.js project in it
cd webapp
```
- 第2步:改变一些默认值并运行webapp
我们将使用`src`作为应用程序目录,而不是`pages`(关于`src`和`pages`的更多信息[在Next.js docs](https://nextjs.org/docs/advanced-features/src-directory))。
```
mkdir src
mv pages src/pages
mv styles src/styles
vim tsconfig.json
//in "compilerOptions" add:
// "baseUrl": "./src"
```
运行Next.js应用程序并在浏览器中查看。
```
yarn dev
//ready - started server on 0.0.0.0:3000, url: http://localhost:3000
```
浏览`http://localhost:3000`。
- 第3步:安装Chakra UI
通过运行Chakra UI([文档](https://chakra-ui.com/docs/getting-started))来安装:
```
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
```
我们将在下一个子任务中编辑next.js应用程序,使其适合我们的项目。
### 任务1.5:编辑webapp
webapp 会包含头部、layout、_app.tsx、index.tsx 等
- 第1步:添加一个页眉组件
```
mkdir src/components
touch src/components/header.tsx
```
编辑`header.tsx`为:
```typescript
//src/components/header.tsx
import NextLink from "next/link"
import { Flex, Button, useColorModeValue, Spacer, Heading, LinkBox, LinkOverlay } from '@chakra-ui/react'
const siteTitle="FirstDAPP"
export default function Header() {
return (
)
}
```
- 第2步:添加Next.js布局
添加布局([Next.js文档](https://nextjs.org/docs/basic-features/layouts))
```
touch src/components/layout.tsx
```
编辑`layout.tsx`为:
```typescript
// src/components/layout.tsx
import React, { ReactNode } from 'react'
import { Text, Center, Container, useColorModeValue } from '@chakra-ui/react'
import Header from './header'
type Props = {
children: ReactNode
}
export function Layout(props: Props) {
return (
{props.children}
)
}
```
- 第3步:在`_app.tsx `和布局中添加Chakra UI Provider
编辑`_app.tsx`
```typescript
// src/pages/_app.tsx
import { ChakraProvider } from '@chakra-ui/react'
import type { AppProps } from 'next/app'
import { Layout } from 'components/layout'
function MyApp({ Component, pageProps }: AppProps) {
return (
)
}
export default MyApp
```
- 第4步:编辑 `index.tsx`
```typescript
// src/pages/index.tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import NextLink from "next/link"
import { VStack, Heading, Box, LinkOverlay, LinkBox} from "@chakra-ui/layout"
import { Text, Button } from '@chakra-ui/react'
const Home: NextPage = () => {
return (
<>
>
)
}
export default Home
```
你可能还想添加`_documents.tsx`([docs](https://nextjs.org/docs/advanced-features/custom-document))来定制你的Next.js应用程序中的页面。
你可能想删除这个项目中不需要的文件,如`src/styles`。
- 第5步:运行webapp
```
yarn dev
```
在http://localhost:3000/ 的页面将看起来像:
![DAPP webapp](https://img.learnblockchain.cn/pics/20220704111340.jpeg)
你可以从github [scaffold repo](https://github.com/fjun99/web3app-tutorial-starter-scaffold)下载代码:
在你的'hhproject/'目录下。
```bash
git clone git@github.com:fjun99/web3app-tutorial-using-ethers.git webapp
cd webapp
yarn install
yarn dev
```
## 任务2:通过MetaMask将DApp连接到区块链上
在这个任务中,我们将创建一个DAPP,它可以通过MetaMask连接到区块链(本地测试网)。
我们将使用Javascript API库`Ethers.js`与区块链交互。
### 任务2.1:安装`Ethers.js`
在`webapp/`目录下,添加`Ethers.js`:
```bash
yarn add ethers
```
### 任务2.2:连接到MetaMask钱包
![显示ETH余额](https://img.learnblockchain.cn/pics/20220704111403.jpeg)
我们将在`index.tsx`上添加一个按钮:
- 当未连接时,按钮文本为 `Connect Wallet(连接钱包)`。点击即可通过MetaMask链接区块链。
- 当连接时,按钮文本是连接的账户地址。用户可以点击断开连接。
我们将获得当前账户的ETH余额并显示在页面上,以及区块链网络信息。
有关于连接MetaMask的以太坊文档([文档链接](https://docs.ethers.io/v5/getting-started/#getting-started--connecting))。
我写了一张PPT来解释`connector`、`provider`、`signer`和`ethers.js`中的wallet之间的关系!
![connector, provider, signer](https://img.learnblockchain.cn/pics/20220704111232.jpeg)
我们将使用[react hook](https://reactjs.org/docs/hooks-intro.html)功能`useState`和`useEffect`。
相关代码片段在 `src/pages/index.tsx`中:
```typescript
// src/pages/index.tsx
...
import { useState, useEffect} from 'react'
import {ethers} from "ethers"
declare let window:any
const Home: NextPage = () => {
const [balance, setBalance] = useState
const [currentAccount, setCurrentAccount] = useState
const [chainId, setChainId] = useState
const [chainname, setChainName] = useState
useEffect(() => {
if(!currentAccount || !ethers.utils.isAddress(currentAccount)) return
//client side code
if(!window.ethereum) return
const provider = new ethers.providers.Web3Provider(window.ethereum)
provider.getBalance(currentAccount).then((result)=>{
setBalance(ethers.utils.formatEther(result))
})
provider.getNetwork().then((result)=>{
setChainId(result.chainId)
setChainName(result.name)
})
},[currentAccount])
const onClickConnect = () => {
//client side code
if(!window.ethereum) {
console.log("please install MetaMask")
return
}
/*
//change from window.ethereum.enable() which is deprecated
//see docs: https://docs.metamask.io/guide/ethereum-provider.html#legacy-methods
window.ethereum.request({ method: 'eth_requestAccounts' })
.then((accounts:any)=>{
if(accounts.length>0) setCurrentAccount(accounts[0])
})
.catch('error',console.error)
*/
//we can do it using ethers.js
const provider = new ethers.providers.Web3Provider(window.ethereum)
// MetaMask requires requesting permission to connect users accounts
provider.send("eth_requestAccounts", [])
.then((accounts)=>{
if(accounts.length>0) setCurrentAccount(accounts[0])
})
.catch((e)=>console.log(e))
}
const onClickDisconnect = () => {
console.log("onClickDisConnect")
setBalance(undefined)
setCurrentAccount(undefined)
}
return (
<>
{currentAccount
?
Account:{currentAccount}
:
Connect MetaMask
}
{currentAccount
?
:<>>
}
...
>
)
}
export default Home
```
解释一下:
- 我们添加了两个UI组件:一个用于连接钱包,一个用于显示账户和链的信息。
- 当 `连接MetaMask `按钮被点击时,执行:
- 通过连接器(即`window.ethereum`, 他是MetaMask注入到页面的)获得`Web3Provider`,。
- 调用`eth_requestAccounts`,这将要求MetaMask确认分享账户信息。用户在MetaMask的弹出窗口确认或拒绝该请求。
- 将返回的账户设置为`currentAccount`。
- 当断开连接被调用时,我们重置currentAccount和余额。
- 每次改变currentAccount时,都会调用副作用函数(useEffect),在这里执行查询:
- 通过调用`getBalance`查询当前账户的ETH余额。
- 通过调用`getNetwork()`来查询网络信息。
请注意:
- 在页面中断开连接,不会改变MetaMask的连接和该页面的权限。打开MetaMask扩展,你会发现你的钱包仍然连接到这个页面。下次你再点击 `连接MetaMask `按钮时,MetaMask不会弹出确认窗口(因为你的确认仍然有效)。你智能通过MetaMask来断开钱包和页面的连接。
- 当用户在MetaMask中切换网络时,我们没有编写代码来显示变化。
- 我们没有存储这个页面的状态。因此,当页面被刷新时,连接被重置。
## 任务3:使用OpenZeppelin构建ERC20智能合约
在任务3中,我们将使用OpenZeppelin库构建ERC20智能合约([ERC20 docs](https://docs.openzeppelin.com/contracts/4.x/api/token/erc20))。
### 任务3.1: 编写一个ERC20智能合约 - ClassToken
添加`OpenZeppelin/contract`:
```
yarn add @openzeppelin/contracts
```
到`chain/`目录下,添加`ccontracts/ClassToken.sol`:
```solidity
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ClassToken is ERC20 {
constructor(uint256 initialSupply)
ERC20("ClassToken", "CLT")
{
_mint(msg.sender, initialSupply);
}
}
```
### 任务 3.2 编译智能合约
```
yarn hardhat compile
//Solidity compilation should succeed
```
### 任务 3.3 添加单元测试脚本
添加单元测试脚本`test/ClassToken.test.ts`。
```typescript
import { expect } from "chai";
import { ethers } from "hardhat";
describe("ClassToken", function () {
it("Should have the correct initial supply", async function () {
const initialSupply = ethers.utils.parseEther('10000.0')
const ClassToken = await ethers.getContractFactory("ClassToken");
const token = await ClassToken.deploy(initialSupply);
await token.deployed();
expect(await token.totalSupply()).to.equal(initialSupply);
});
});
```
运行单元测试。
```shell
yarn hardhat test
// ClassToken
// ✓ Should have the correct initial supply (392ms)
// 1 passing (401ms)
```
### 任务 3.4 添加部署脚本
添加部署脚本 `scripts/deploy_classtoken.ts`。
```typescript
import { ethers } from "hardhat";
async function main() {
const initialSupply = ethers.utils.parseEther('10000.0')
const ClassToken = await ethers.getContractFactory("ClassToken");
const token = await ClassToken.deploy(initialSupply);
await token.deployed();
console.log("ClassToken deployed to:", token.address);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
```
我们部署ClassToken,并将initialSupply `10000.0 CLT`发送到部署者(`msg.sender`)。
尝试运行合约部署到进程中的Hardhat Network本地测试网(进程中模式)。
```
yarn hardhat run scripts/deploy_classtoken.ts
```
### 任务3.5 运行独立的测试网,向其部署智能合约
在另一个终端,在`chain/`目录下运行:
```
yarn hardhat node
```
在当前终端,运行连接到localhost `--network localhost`的hardhat任务。
```
yarn hardhat run scripts/deploy_classtoken.ts --network localhost
//ClassToken deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
```
### 任务3.6 在hardhat控制台与ClassToken交互
运行连接到独立的本地测试网的hardhat控制台。
```
yarn hardhat console --network localhost
```
在控制台中与 `ClassToken `交互:
```
formatEther = ethers.utils.formatEther;
address = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
token = await ethers.getContractAt("ClassToken", address);
totalSupply = await token.totalSupply();
formatEther(totalSupply)
//'10000.0'
```
`ethers.getContractAt()`是Hardhat插件`hardhat-ethers`提供的一个辅助函数,[文档链接](https://hardhat.org/plugins/nomiclabs-hardhat-ethers.html#helpers)。
### 任务3.7:将代币添加到MetaMask中
添加Token到MetaMask,地址为:`0x5FbDB2315678afecb367f032d93F642f64180aa3`。(**请使用你得到的部署合约地址。**)
我们可以看到0号账户(`0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266`)有`10000.0 CLT`。
你也可以从[github repo](https://github.com/fjun99/chain-tutorial-hardhat-starter)下载hardhat示例项目。
```
git clone git@github.com:fjun99/chain-tutorial-hardhat-starter.git chain
yarn install
// then, you can run stand-alone testnet and
// go through the compile-test-deploy circle
```
## 任务4:读取合约数据--在webapp中与智能合约交互
在任务4和任务5中,我们将继续构建我们的webapp。
我们将允许用户与新部署的ERC20代币智能合约--`ClassToken(CLT)`进行交互。
![DApp ERC20](https://img.learnblockchain.cn/pics/20220704143242.jpeg)
### 任务4.1: 添加空的`ReadERC20`组件来读取ClassToken
在webapp目录中,添加一个空组件`components/ReadERC20.tsx`。
```typescript
import React, { useEffect,useState } from 'react'
import { Text} from '@chakra-ui/react'
interface Props {
addressContract: string,
currentAccount: string | undefined
}
export default function ReadERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
return (
)
}
```
导入并添加这个组件到`index.tsx`:
```typescript
addressContract='0x5FbDB2315678afecb367f032d93F642f64180aa3'
currentAccount={currentAccount}
/>
```
在下面的子任务中,我们将逐步添加`ReadERC20`组件的功能。
### 任务4.2:准备智能合约ABI
要在Javascript中与智能合约交互,我们需要它的[ABI](https://docs.soliditylang.org/en/v0.8.11/abi-spec.html)。
> 合约**应用二进制接口**(ABI)是与以太坊生态系统中的合约交互的标准方式。数据是根据其类型进行编码的。
ERC20智能合约是一个标准,我们将使用一个文件而不是Hardhat项目中输出的编译工件。我们添加的是[人类可读的ABI](https://docs.ethers.io/v5/api/utils/abi/formats/#abi-formats--human-readable-abi)。
添加一个目录`src/abi`并添加文件`src/abi/ERC20ABI.tsx`:
```typescript
export const ERC20ABI = [
// Read-Only Functions
"function balanceOf(address owner) view returns (uint256)",
"function totalSupply() view returns (uint256)",
"function decimals() view returns (uint8)",
"function symbol() view returns (string)",
// Authenticated Functions
"function transfer(address to, uint amount) returns (bool)",
// Events
"event Transfer(address indexed from, address indexed to, uint amount)"
];
```
### 任务4.3: 当组件加载时查询智能合约信息
我们使用React钩子`useEffect`来查询组件加载时的智能合约信息。
编辑`ReadERC20.tsx`:
```typescript
// src/components/ReadERC20.tsx
import React, {useEffect, useState } from 'react';
import {Text} from '@chakra-ui/react'
import {ERC20ABI as abi} from 'abi/ERC20ABI'
import {ethers} from 'ethers'
interface Props {
addressContract: string,
currentAccount: string | undefined
}
declare let window: any;
export default function ReadERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
const [totalSupply,setTotalSupply]=useState const [symbol,setSymbol]= useState
useEffect( () => {
if(!window.ethereum) return
const provider = new ethers.providers.Web3Provider(window.ethereum)
const erc20 = new ethers.Contract(addressContract, abi, provider);
erc20.symbol().then((result:string)=>{
setSymbol(result)
}).catch('error', console.error)
erc20.totalSupply().then((result:string)=>{
setTotalSupply(ethers.utils.formatEther(result))
}).catch('error', console.error);
//called only once
},[])
return (
)
}
```
解释一下:
- 钩子`useEffect(()=>{},[])`将只被调用一次。
- 用`window.ethereum`(通过MetaMask注入到页面)创建一个[Web3Provider](https://docs.ethers.io/v5/api/providers/other/#Web3Provider)。
- 在`ethers.js`中用`addressContract`、`abi`、`provider`创建一个合约实例。
- 调用只读函数`symbol()`, `totalSupply()`,并将结果设置为反应状态的变量,可以在页面上显示。
### 任务 4.3: 当账户变化时,查询当前账户的CLT余额
编辑`ReadERC20.tsx`:
```typescript
// src/components/ReadERC20.tsx
const [balance, SetBalance] =useState
...
//call when currentAccount change
useEffect(()=>{
if(!window.ethereum) return
if(!currentAccount) return
queryTokenBalance(window)
},[currentAccount])
async function queryTokenBalance(window:any){
const provider = new ethers.providers.Web3Provider(window.ethereum)
const erc20 = new ethers.Contract(addressContract, abi, provider);
erc20.balanceOf(currentAccount)
.then((result:string)=>{
SetBalance(Number(ethers.utils.formatEther(result)))
})
.catch('error', console.error)
}
...
return (
)
```
解释一下:
- 当`currentAccount`改变时,副作用钩子函数`useEffect(()=>{},[currentAccount]`被调用,调用`balanceOf(address)`来获得余额。
- 当我们刷新页面时,没有当前账户,也没有显示余额。在我们连接钱包后,余额被查询到并显示在页面上。
还有更多的工作要做:
- 当MetaMask切换账户时,我们的Web 应用不知道,也不会改变页面的显示,因此需要监听MetaMask的账户变化事件。
- 当当前账户的余额发生变化时,由于当前账户没有被改变,我们的Web应用程序将不会更新。
你可以使用MetaMask将CLT发送给其他人,你会发现我们需要在页面上更新CLT的账户余额。我们将在任务6中完成这一工作。在任务5中,我们将首先为用户创建转账组件。
## 任务5:执行写操作(转账)
继续在Web App中与智能合约交互,现在执行一个写操作
### 任务5.1:添加空的`TransferERC20`组件
```typescript
// src/component/TransferERC20.tsx
import React, { useEffect,useState } from 'react';
import { Text, Button, Input , NumberInput, NumberInputField, FormControl, FormLabel } from '@chakra-ui/react'
interface Props {
addressContract: string,
currentAccount: string | undefined
}
export default function ReadERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
const [amount,setAmount]=useState
const [toAddress, setToAddress]=useState
async function transfer(event:React.FormEvent) {
event.preventDefault()
console.log("transfer clicked")
}
const handleChange = (value:string) => setAmount(value)
return (
)
}
```
导入并添加这个组件到index.tsx:
```typescript
addressContract='0x5FbDB2315678afecb367f032d93F642f64180aa3'
currentAccount={currentAccount}
/>
```
### 任务5.2: 实现transfer()函数
在`TransferERC20.tsx`中实现转移函数:
```typescript
// src/component/TransferERC20.tsx
import React, { useState } from 'react'
import {Button, Input , NumberInput, NumberInputField, FormControl, FormLabel } from '@chakra-ui/react'
import {ethers} from 'ethers'
import {parseEther } from 'ethers/lib/utils'
import {ERC20ABI as abi} from 'abi/ERC20ABI'
import { Contract } from "ethers"
import { TransactionResponse,TransactionReceipt } from "@ethersproject/abstract-provider"
interface Props {
addressContract: string,
currentAccount: string | undefined
}
declare let window: any;
export default function TransferERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
const [amount,setAmount]=useState const [toAddress, setToAddress]=useState
async function transfer(event:React.FormEvent) {
event.preventDefault()
if(!window.ethereum) return
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
const erc20:Contract = new ethers.Contract(addressContract, abi, signer)
erc20.transfer(toAddress,parseEther(amount))
.then((tr: TransactionResponse) => {
console.log(`TransactionResponse TX hash: ${tr.hash}`)
tr.wait().then((receipt:TransactionReceipt)=>{console.log("transfer receipt",receipt)})
})
.catch((e:Error)=>console.log(e))
}
const handleChange = (value:string) => setAmount(value)
return (
setToAddress(e.target.value)} my={3}/>
)
}
```
解释一下:
- 我们调用`transfer(address recipient, uint256 amount) → bool`,这是ERC20智能合约的状态变化函数。
正如你所看到的,转移后ClassToken的余额没有改变。我们将在任务6中解决这个问题:
## 任务6:监听事件:在Web 应用中与智能合约交互
我们可以通过智能合约事件的设计来更新CLT余额。对于ERC20代币智能合约,当转账在链上被确认时,会发出一个事件`Transfer(address from, address to, uint256 value)`([文档](https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#IERC20-Transfer-address-address-uint256-))。
我们可以在Node.js webapp中监听这个事件并更新页面显示。
### 任务6.1: 了解智能合约事件
简单解释事件:当我们调用会智能合约的状态变化函数时,有三个步骤:
- 第1步:链外调用。我们使用JavaScript API(ethers.js)在链外调用智能合约的状态变化函数。
- 第2步:链上确认。状态改变交易需要由矿工使用共识算法在链上的几个区块进行确认。所以我们不能立即得到结果。
- 第3步:触发事件。一旦交易被确认,就会发出一个事件。你可以通过监听事件来获得链外的结果。
![事件解释](https://img.learnblockchain.cn/pics/20220704111319.png)
### 任务6.2:当当前账户变化时,添加事件监听器
编辑`ReadERC20.tsx`:
```typescript
//call when currentAccount change
useEffect(()=>{
if(!window.ethereum) return
if(!currentAccount) return
queryTokenBalance(window)
const provider = new ethers.providers.Web3Provider(window.ethereum)
const erc20 = new ethers.Contract(addressContract, abi, provider)
// listen for changes on an Ethereum address
console.log(`listening for Transfer...`)
const fromMe = erc20.filters.Transfer(currentAccount, null)
provider.on(fromMe, (from, to, amount, event) => {
console.log('Transfer|sent', { from, to, amount, event })
queryTokenBalance(window)
})
const toMe = erc20.filters.Transfer(null, currentAccount)
provider.on(toMe, (from, to, amount, event) => {
console.log('Transfer|received', { from, to, amount, event })
queryTokenBalance(window)
})
// remove listener when the component is unmounted
return () => {
provider.removeAllListeners(toMe)
provider.removeAllListeners(fromMe)
}
}, [currentAccount])
```
这个代码片段改编自[How to Fetch and Update Data From 以太坊 with React and SWR](https://consensys.net/blog/developers/how-to-fetch-and-update-data-from-ethereum-with-react-and-swr/)。
解释一下:
- 当`currentAccount`改变时(useEffect),我们添加两个监听器:一个用于从currentAccount转移的事件,另一个用于转移到currentAccount。
- 当监听到一个事件时,查询currentAccount的token余额并更新页面。
你可以在页面上或在MetaMask中从当前账户转账,你会看到页面在事件发生时正在更新。
当完成任务6时,你已经建立了一个简单而实用的DAPP,它有智能合约和Web页面。
综上所述,DAPP有三个部分:
- 智能合约和区块链
- Web 应用(用户界面),通过智能合约获取和设置数据
- 用户控制的钱包(这里是MetaMask),作为资产管理工具和用户的签名者,以及区块链的连接器。
通过这些任务,我们还了解到3种与智能合约交互的方式:
- 读取:从智能合约中获取数据
- 写:在智能合约中更新数据
- 监听,监听智能合约发出的事件
在本教程中,我们直接使用`ethers.js`来连接到区块链。作者还有一篇使用 Web3-react 库进行连接的文章,有机会在翻译。
英文原文:https://dev.to/yakult/a-tutorial-build-dapp-with-hardhat-react-and-ethersjs-1gmi
scaffold-eth 因为引入内容太多了,对于我来说太复杂了, 不知道大家有没有同感,找到一篇使用 React 开发 DApp 的非常简单入门教程。翻译一下.
在本教程中,我们将使用Hardhat、React和ethers.js构建DAPP,它可以与用户控制的钱包如MetaMask一起使用。
DAPP通常由三部分组成:
部署在链上的智能合约
用Node.js、React和Next.js构建的Webapp(用户界面)
钱包(用户在浏览器中控制的/移动钱包App)
我们使用ethers.js来连接各个:
在DApp(webapp)的用户界面中,MetaMask等钱包给开发者提供了一个以太坊的提供者,我们可以在Ethers.js中使用,与区块链进行交互。(具体来说,钱包提供的是一个 "连接器",ethers.js创建 "提供者(provider)"和/或 "签名者(signer)"供我们使用)。
作为用户,我们可能已经知道了MetaMask的用法,作为开发者,我们将学习如何使用MetaMask和它注入浏览器的window.ethereum(MetaMask开发者文档。
本教程的代码库在:
Hardhat项目:https://github.com/fjun99/chain-tutorial-hardhat-starter
Webapp项目:https://github.com/fjun99/web3app-tutorial-using-ethers
特别感谢在准备webapp代码库时,Wesley的Proof-of-Competence, POC项目学到了很多。我们也像他的项目一样使用Chakra UI。你可能也会发现网页与POC几乎一样。
前置知识和工具
在我们开始之前,你需要对一下内容有一些了解:
知识:
区块链
以太坊
钱包
Solidity
ERC20 & ERC721
Ethers.js
工具:
MetaMask (钱包浏览器插件)
Node.js, yarn, TypeScript
OpenZeppelin (Solidity库)
Etherscan区块浏览器
让我们开始建立一个DApp
任务1:设置开发环境
为了建立一个DApp,我们要做两个工作:
使用Hardhat和Solidity构建智能合约
使用Node.js、React和Next.js构建Web 应用。
我们将把目录组织成两个子目录chain和webapp:
- hhproject
- chain (working dir for hardhat)
- contracts
- test
- scripts
- webapp (working dir for NextJS app)
- src
- pages
- components
任务1.1 安装Hardhat并启动Hardhat项目
安装Hardhat,这是一个以太坊开发环境。
要使用Hardhat,你需要在电脑上有node.js和yarn:
第1步:建立一个目录并在其中安装Hardhat
mkdir hhproject && cd hhproject
mkdir chain && cd chain
yarn init -y
安装Hardhat:
yarn add hardhat
第2步:创建一个Hardhat样本项目
yarn hardhat
//choose: Create an advanced sample project that uses TypeScript
用我们将在任务3中使用的样本智能合约Greeter.sol创建一个hardhat项目。
第3步:运行Harhat网络(本地testnet)
yarn hardhat node
将运行一个本地测试网(chainId: 31337)。
开始了HTTP和WebSocket JSON-RPC服务器,地址是http://127.0.0.1:8545/
它提供了20个账户,每个账户有10000.0测试ETH。
Account #0: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 (10000 ETH)
Account #1: 0x70997970c51812dc3a010c7d01b50e0d17dc79c8
...
请注意,Hardhat Network本地testnet有两种模式:进程中模式和独立模式。我们用命令行yarn hardhat node运行一个独立的testnet。当运行像yarn hardhat compile这样的命令行时,如果没有网络参数(--network localhost),我们就运行一个进程内测试网。
任务1.2:在Hardhat的开发
我们将在Hardhat开发环境中体验智能合约的开发过程。
在Hardhat启动的项目中,默认包含有智能合约、测试脚本和部署脚本的样本。
├── contracts
│ └── Greeter.sol
├── scripts
│ └── deploy.ts
├── test
│ └── index.ts
├── hardhat.config.ts
我想改变测试和部署脚本的文件名:
- contracts
- Greeter.sol
- test
- Greeter.test.ts (<-index.ts)
- scripts
- deploy_greeter.ts (<-deploy.ts)
第1步:运行命令,显示账户:
yarn hardhat accounts
这是在hardhat.config.ts中添加的hardhat 样本任务。
第2步:编译智能合约
yarn hardhat compile
第3步:运行单元测试
yarn hardhat test
第4步:尝试部署到进程中的测试网
yarn hardhat run ./scripts/deploy_greeter.ts
在接下来的两个步骤中,将运行一个独立的Hardhat网络,并将智能合约部署上去。
第5步:运行一个独立的本地测试网
在另一个终端,运行:
yarn hardhat node
//Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
第6步: 部署到独立的本地测试网
yarn hardhat run ./scripts/deploy.ts --network localhost
//Greeter deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
如果你多次运行部署,你会发现合约实例被部署到不同的地址。
任务1.3:将MetaMask切换到本地测试网
确保Hardhat Network 本地测试网仍在运行(你可以通过命令yarn hardhat node来运行它)。
第1步:在MataMask浏览器插件中,点击顶部栏的网络选择。将网络从mainnet切换到localhost 8545。
第2步:点击顶栏上的账户图标,进入 设置/网络/。选择 localhost 8445。
注意:确保链ID是31337。在MetaMask中,它可能默认为 1337。
任务 1.4: 用Next.js和Chakra UI创建webapp
我们将使用Node.js、React、Next.js和Chakra UI框架创建一个webapp。(你可以选择你喜欢的任何其他UI框架,如Material UI,Ant Design等。你也可能想选择前端框架Vue而不是Next.js)
第1步:创建Next.js项目webapp。
在hhproject/目录下,运行:
yarn create next-app webapp --typescript
//will make a sub-dir webapp and create an empty Next.js project in it
cd webapp
第2步:改变一些默认值并运行webapp
我们将使用src作为应用程序目录,而不是pages(关于src和pages的更多信息在Next.js docs)。
mkdir src
mv pages src/pages
mv styles src/styles
vim tsconfig.json
//in "compilerOptions" add:
// "baseUrl": "./src"
运行Next.js应用程序并在浏览器中查看。
yarn dev
//ready - started server on 0.0.0.0:3000, url: http://localhost:3000
浏览http://localhost:3000。
第3步:安装Chakra UI
通过运行Chakra UI(文档)来安装:
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
我们将在下一个子任务中编辑next.js应用程序,使其适合我们的项目。
任务1.5:编辑webapp
webapp 会包含头部、layout、_app.tsx、index.tsx 等
第1步:添加一个页眉组件
mkdir src/components
touch src/components/header.tsx
编辑header.tsx为:
//src/components/header.tsx
import NextLink from "next/link"
import { Flex, Button, useColorModeValue, Spacer, Heading, LinkBox, LinkOverlay } from '@chakra-ui/react'
const siteTitle="FirstDAPP"
export default function Header() {
return (
<Flex as='header' bg={useColorModeValue('gray.100', 'gray.900')} p={4} alignItems='center'>
<LinkBox>
<NextLink href={'/'} passHref>
<LinkOverlay>
<Heading size="md">{siteTitle}</Heading>
</LinkOverlay>
</NextLink>
</LinkBox>
<Spacer />
<Button >Button for Account </Button>
</Flex>
)
}
第2步:添加Next.js布局
添加布局(Next.js文档)
touch src/components/layout.tsx
编辑layout.tsx为:
// src/components/layout.tsx
import React, { ReactNode } from 'react'
import { Text, Center, Container, useColorModeValue } from '@chakra-ui/react'
import Header from './header'
type Props = {
children: ReactNode
}
export function Layout(props: Props) {
return (
<div>
<Header />
<Container maxW="container.md" py='8'>
{props.children}
</Container>
<Center as="footer" bg={useColorModeValue('gray.100', 'gray.700')} p={6}>
<Text fontSize="md">first dapp by W3BCD - 2022</Text>
</Center>
</div>
)
}
第3步:在_app.tsx和布局中添加Chakra UI Provider
编辑_app.tsx
// src/pages/_app.tsx
import { ChakraProvider } from '@chakra-ui/react'
import type { AppProps } from 'next/app'
import { Layout } from 'components/layout'
function MyApp({ Component, pageProps }: AppProps) {
return (
<ChakraProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</ChakraProvider>
)
}
export default MyApp
第4步:编辑 index.tsx
// src/pages/index.tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import NextLink from "next/link"
import { VStack, Heading, Box, LinkOverlay, LinkBox} from "@chakra-ui/layout"
import { Text, Button } from '@chakra-ui/react'
const Home: NextPage = () => {
return (
<>
<Head>
<title>My DAPP</title>
</Head>
<Heading as="h3" my={4}>Explore Web3</Heading>
<VStack>
<Box my={4} p={4} w='100%' borderWidth="1px" borderRadius="lg">
<Heading my={4} fontSize='xl'>Task 1</Heading>
<Text>local chain with hardhat</Text>
</Box>
<Box my={4} p={4} w='100%' borderWidth="1px" borderRadius="lg">
<Heading my={4} fontSize='xl'>Task 2</Heading>
<Text>DAPP with React/NextJS/Chakra</Text>
</Box>
<LinkBox my={4} p={4} w='100%' borderWidth="1px" borderRadius="lg">
<NextLink href="https://github.com/NoahZinsmeister/web3-react/tree/v6" passHref>
<LinkOverlay>
<Heading my={4} fontSize='xl'>Task 3 with link</Heading>
<Text>Read docs of Web3-React V6</Text>
</LinkOverlay>
</NextLink>
</LinkBox>
</VStack>
</>
)
}
export default Home
你可能还想添加_documents.tsx(docs)来定制你的Next.js应用程序中的页面。
你可能想删除这个项目中不需要的文件,如src/styles。
第5步:运行webapp
yarn dev
在http://localhost:3000/ 的页面将看起来像:
你可以从github scaffold repo下载代码:
在你的'hhproject/'目录下。
git clone git@github.com:fjun99/web3app-tutorial-using-ethers.git webapp
cd webapp
yarn install
yarn dev
任务2:通过MetaMask将DApp连接到区块链上
在这个任务中,我们将创建一个DAPP,它可以通过MetaMask连接到区块链(本地测试网)。
我们将使用Javascript API库Ethers.js与区块链交互。
任务2.1:安装Ethers.js
在webapp/目录下,添加Ethers.js:
yarn add ethers
任务2.2:连接到MetaMask钱包
我们将在index.tsx上添加一个按钮:
当未连接时,按钮文本为 Connect Wallet(连接钱包)。点击即可通过MetaMask链接区块链。
当连接时,按钮文本是连接的账户地址。用户可以点击断开连接。
我们将获得当前账户的ETH余额并显示在页面上,以及区块链网络信息。
有关于连接MetaMask的以太坊文档(文档链接)。
我写了一张PPT来解释connector、provider、signer和ethers.js中的wallet之间的关系!
我们将使用react hook功能useState和useEffect。
相关代码片段在 src/pages/index.tsx中:
// src/pages/index.tsx
...
import { useState, useEffect} from 'react'
import {ethers} from "ethers"
declare let window:any
const Home: NextPage = () => {
const [balance, setBalance] = useState<string | undefined>()
const [currentAccount, setCurrentAccount] = useState<string | undefined>()
const [chainId, setChainId] = useState<number | undefined>()
const [chainname, setChainName] = useState<string | undefined>()
useEffect(() => {
if(!currentAccount || !ethers.utils.isAddress(currentAccount)) return
//client side code
if(!window.ethereum) return
const provider = new ethers.providers.Web3Provider(window.ethereum)
provider.getBalance(currentAccount).then((result)=>{
setBalance(ethers.utils.formatEther(result))
})
provider.getNetwork().then((result)=>{
setChainId(result.chainId)
setChainName(result.name)
})
},[currentAccount])
const onClickConnect = () => {
//client side code
if(!window.ethereum) {
console.log("please install MetaMask")
return
}
/*
//change from window.ethereum.enable() which is deprecated
//see docs: https://docs.metamask.io/guide/ethereum-provider.html#legacy-methods
window.ethereum.request({ method: 'eth_requestAccounts' })
.then((accounts:any)=>{
if(accounts.length>0) setCurrentAccount(accounts[0])
})
.catch('error',console.error)
*/
//we can do it using ethers.js
const provider = new ethers.providers.Web3Provider(window.ethereum)
// MetaMask requires requesting permission to connect users accounts
provider.send("eth_requestAccounts", [])
.then((accounts)=>{
if(accounts.length>0) setCurrentAccount(accounts[0])
})
.catch((e)=>console.log(e))
}
const onClickDisconnect = () => {
console.log("onClickDisConnect")
setBalance(undefined)
setCurrentAccount(undefined)
}
return (
<>
<Head>
<title>My DAPP</title>
</Head>
<Heading as="h3" my={4}>Explore Web3</Heading>
<VStack>
<Box w='100%' my={4}>
{currentAccount
? <Button type="button" w='100%' onClick={onClickDisconnect}>
Account:{currentAccount}
</Button>
: <Button type="button" w='100%' onClick={onClickConnect}>
Connect MetaMask
</Button>
}
</Box>
{currentAccount
?<Box mb={0} p={4} w='100%' borderWidth="1px" borderRadius="lg">
<Heading my={4} fontSize='xl'>Account info</Heading>
<Text>ETH Balance of current account: {balance}</Text>
<Text>Chain Info: ChainId {chainId} name {chainname}</Text>
</Box>
:<></>
}
...
</VStack>
</>
)
}
export default Home
解释一下:
我们添加了两个UI组件:一个用于连接钱包,一个用于显示账户和链的信息。
当 连接MetaMask按钮被点击时,执行:
通过连接器(即window.ethereum, 他是MetaMask注入到页面的)获得Web3Provider,。
调用eth_requestAccounts,这将要求MetaMask确认分享账户信息。用户在MetaMask的弹出窗口确认或拒绝该请求。
将返回的账户设置为currentAccount。
当断开连接被调用时,我们重置currentAccount和余额。
每次改变currentAccount时,都会调用副作用函数(useEffect),在这里执行查询:
通过调用getBalance查询当前账户的ETH余额。
通过调用getNetwork()来查询网络信息。
请注意:
在页面中断开连接,不会改变MetaMask的连接和该页面的权限。打开MetaMask扩展,你会发现你的钱包仍然连接到这个页面。下次你再点击 连接MetaMask按钮时,MetaMask不会弹出确认窗口(因为你的确认仍然有效)。你智能通过MetaMask来断开钱包和页面的连接。
当用户在MetaMask中切换网络时,我们没有编写代码来显示变化。
我们没有存储这个页面的状态。因此,当页面被刷新时,连接被重置。
任务3:使用OpenZeppelin构建ERC20智能合约
在任务3中,我们将使用OpenZeppelin库构建ERC20智能合约(ERC20 docs)。
任务3.1: 编写一个ERC20智能合约 - ClassToken
添加OpenZeppelin/contract:
yarn add @openzeppelin/contracts
到chain/目录下,添加ccontracts/ClassToken.sol:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ClassToken is ERC20 {
constructor(uint256 initialSupply)
ERC20("ClassToken", "CLT")
{
_mint(msg.sender, initialSupply);
}
}
任务 3.2 编译智能合约
yarn hardhat compile
//Solidity compilation should succeed
任务 3.3 添加单元测试脚本
添加单元测试脚本test/ClassToken.test.ts。
import { expect } from "chai";
import { ethers } from "hardhat";
describe("ClassToken", function () {
it("Should have the correct initial supply", async function () {
const initialSupply = ethers.utils.parseEther('10000.0')
const ClassToken = await ethers.getContractFactory("ClassToken");
const token = await ClassToken.deploy(initialSupply);
await token.deployed();
expect(await token.totalSupply()).to.equal(initialSupply);
});
});
运行单元测试。
yarn hardhat test
// ClassToken
// ✓ Should have the correct initial supply (392ms)
// 1 passing (401ms)
任务 3.4 添加部署脚本
添加部署脚本 scripts/deploy_classtoken.ts。
import { ethers } from "hardhat";
async function main() {
const initialSupply = ethers.utils.parseEther('10000.0')
const ClassToken = await ethers.getContractFactory("ClassToken");
const token = await ClassToken.deploy(initialSupply);
await token.deployed();
console.log("ClassToken deployed to:", token.address);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
我们部署ClassToken,并将initialSupply 10000.0 CLT发送到部署者(msg.sender)。
尝试运行合约部署到进程中的Hardhat Network本地测试网(进程中模式)。
yarn hardhat run scripts/deploy_classtoken.ts
任务3.5 运行独立的测试网,向其部署智能合约
在另一个终端,在chain/目录下运行:
yarn hardhat node
在当前终端,运行连接到localhost --network localhost的hardhat任务。
yarn hardhat run scripts/deploy_classtoken.ts --network localhost
//ClassToken deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
任务3.6 在hardhat控制台与ClassToken交互
运行连接到独立的本地测试网的hardhat控制台。
yarn hardhat console --network localhost
在控制台中与 ClassToken交互:
formatEther = ethers.utils.formatEther;
address = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
token = await ethers.getContractAt("ClassToken", address);
totalSupply = await token.totalSupply();
formatEther(totalSupply)
//'10000.0'
ethers.getContractAt()是Hardhat插件hardhat-ethers提供的一个辅助函数,文档链接。
任务3.7:将代币添加到MetaMask中
添加Token到MetaMask,地址为:0x5FbDB2315678afecb367f032d93F642f64180aa3。(请使用你得到的部署合约地址。)
我们可以看到0号账户(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)有10000.0 CLT。
你也可以从github repo下载hardhat示例项目。
git clone git@github.com:fjun99/chain-tutorial-hardhat-starter.git chain
yarn install
// then, you can run stand-alone testnet and
// go through the compile-test-deploy circle
任务4:读取合约数据--在webapp中与智能合约交互
在任务4和任务5中,我们将继续构建我们的webapp。
我们将允许用户与新部署的ERC20代币智能合约--ClassToken(CLT)进行交互。
任务4.1: 添加空的ReadERC20组件来读取ClassToken
在webapp目录中,添加一个空组件components/ReadERC20.tsx。
import React, { useEffect,useState } from 'react'
import { Text} from '@chakra-ui/react'
interface Props {
addressContract: string,
currentAccount: string | undefined
}
export default function ReadERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
return (
<div>
<Text >ERC20 Contract: {addressContract}</Text>
<Text>token totalSupply:</Text>
<Text my={4}>ClassToken in current account:</Text>
</div>
)
}
导入并添加这个组件到index.tsx:
<Box mb={0} p={4} w='100%' borderWidth="1px" borderRadius="lg">
<Heading my={4} fontSize='xl'>Read ClassToken Info</Heading>
<ReadERC20
addressContract='0x5FbDB2315678afecb367f032d93F642f64180aa3'
currentAccount={currentAccount}
/>
</Box>
在下面的子任务中,我们将逐步添加ReadERC20组件的功能。
任务4.2:准备智能合约ABI
要在Javascript中与智能合约交互,我们需要它的ABI。
合约应用二进制接口(ABI)是与以太坊生态系统中的合约交互的标准方式。数据是根据其类型进行编码的。
ERC20智能合约是一个标准,我们将使用一个文件而不是Hardhat项目中输出的编译工件。我们添加的是人类可读的ABI。
添加一个目录src/abi并添加文件src/abi/ERC20ABI.tsx:
export const ERC20ABI = [
// Read-Only Functions
"function balanceOf(address owner) view returns (uint256)",
"function totalSupply() view returns (uint256)",
"function decimals() view returns (uint8)",
"function symbol() view returns (string)",
// Authenticated Functions
"function transfer(address to, uint amount) returns (bool)",
// Events
"event Transfer(address indexed from, address indexed to, uint amount)"
];
任务4.3: 当组件加载时查询智能合约信息
我们使用React钩子useEffect来查询组件加载时的智能合约信息。
编辑ReadERC20.tsx:
// src/components/ReadERC20.tsx
import React, {useEffect, useState } from 'react';
import {Text} from '@chakra-ui/react'
import {ERC20ABI as abi} from 'abi/ERC20ABI'
import {ethers} from 'ethers'
interface Props {
addressContract: string,
currentAccount: string | undefined
}
declare let window: any;
export default function ReadERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
const [totalSupply,setTotalSupply]=useState<string>()
const [symbol,setSymbol]= useState<string>("")
useEffect( () => {
if(!window.ethereum) return
const provider = new ethers.providers.Web3Provider(window.ethereum)
const erc20 = new ethers.Contract(addressContract, abi, provider);
erc20.symbol().then((result:string)=>{
setSymbol(result)
}).catch('error', console.error)
erc20.totalSupply().then((result:string)=>{
setTotalSupply(ethers.utils.formatEther(result))
}).catch('error', console.error);
//called only once
},[])
return (
<div>
<Text><b>ERC20 Contract</b>: {addressContract}</Text>
<Text><b>ClassToken totalSupply</b>:{totalSupply} {symbol}</Text>
<Text my={4}><b>ClassToken in current account</b>:</Text>
</div>
)
}
解释一下:
钩子useEffect(()=>{},[])将只被调用一次。
用window.ethereum(通过MetaMask注入到页面)创建一个Web3Provider。
在ethers.js中用addressContract、abi、provider创建一个合约实例。
调用只读函数symbol(), totalSupply(),并将结果设置为反应状态的变量,可以在页面上显示。
任务 4.3: 当账户变化时,查询当前账户的CLT余额
编辑ReadERC20.tsx:
// src/components/ReadERC20.tsx
const [balance, SetBalance] =useState<number|undefined>(undefined)
...
//call when currentAccount change
useEffect(()=>{
if(!window.ethereum) return
if(!currentAccount) return
queryTokenBalance(window)
},[currentAccount])
async function queryTokenBalance(window:any){
const provider = new ethers.providers.Web3Provider(window.ethereum)
const erc20 = new ethers.Contract(addressContract, abi, provider);
erc20.balanceOf(currentAccount)
.then((result:string)=>{
SetBalance(Number(ethers.utils.formatEther(result)))
})
.catch('error', console.error)
}
...
return (
<div>
<Text><b>ERC20 Contract</b>: {addressContract}</Text>
<Text><b>ClassToken totalSupply</b>:{totalSupply} {symbol}</Text>
<Text my={4}><b>ClassToken in current account</b>: {balance} {symbol}</Text>
</div>
)
解释一下:
当currentAccount改变时,副作用钩子函数useEffect(()=>{},[currentAccount]被调用,调用balanceOf(address)来获得余额。
当我们刷新页面时,没有当前账户,也没有显示余额。在我们连接钱包后,余额被查询到并显示在页面上。
还有更多的工作要做:
当MetaMask切换账户时,我们的Web 应用不知道,也不会改变页面的显示,因此需要监听MetaMask的账户变化事件。
当当前账户的余额发生变化时,由于当前账户没有被改变,我们的Web应用程序将不会更新。
你可以使用MetaMask将CLT发送给其他人,你会发现我们需要在页面上更新CLT的账户余额。我们将在任务6中完成这一工作。在任务5中,我们将首先为用户创建转账组件。
任务5:执行写操作(转账)
继续在Web App中与智能合约交互,现在执行一个写操作
任务5.1:添加空的TransferERC20组件
// src/component/TransferERC20.tsx
import React, { useEffect,useState } from 'react';
import { Text, Button, Input , NumberInput, NumberInputField, FormControl, FormLabel } from '@chakra-ui/react'
interface Props {
addressContract: string,
currentAccount: string | undefined
}
export default function ReadERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
const [amount,setAmount]=useState<string>('100')
const [toAddress, setToAddress]=useState<string>("")
async function transfer(event:React.FormEvent) {
event.preventDefault()
console.log("transfer clicked")
}
const handleChange = (value:string) => setAmount(value)
return (
<form onSubmit={transfer}>
<FormControl>
<FormLabel htmlFor='amount'>Amount: </FormLabel>
<NumberInput defaultValue={amount} min={10} max={1000} onChange={handleChange}>
<NumberInputField />
</NumberInput>
<FormLabel htmlFor='toaddress'>To address: </FormLabel>
<Input id="toaddress" type="text" required onChange={(e) => setToAddress(e.target.value)} my={3}/>
<Button type="submit" isDisabled={!currentAccount}>Transfer</Button>
</FormControl>
</form>
)
}
导入并添加这个组件到index.tsx:
<Box mb={0} p={4} w='100%' borderWidth="1px" borderRadius="lg">
<Heading my={4} fontSize='xl'>Transfer Classtoken</Heading>
<TransferERC20
addressContract='0x5FbDB2315678afecb367f032d93F642f64180aa3'
currentAccount={currentAccount}
/>
</Box>
任务5.2: 实现transfer()函数
在TransferERC20.tsx中实现转移函数:
// src/component/TransferERC20.tsx
import React, { useState } from 'react'
import {Button, Input , NumberInput, NumberInputField, FormControl, FormLabel } from '@chakra-ui/react'
import {ethers} from 'ethers'
import {parseEther } from 'ethers/lib/utils'
import {ERC20ABI as abi} from 'abi/ERC20ABI'
import { Contract } from "ethers"
import { TransactionResponse,TransactionReceipt } from "@ethersproject/abstract-provider"
interface Props {
addressContract: string,
currentAccount: string | undefined
}
declare let window: any;
export default function TransferERC20(props:Props){
const addressContract = props.addressContract
const currentAccount = props.currentAccount
const [amount,setAmount]=useState<string>('100')
const [toAddress, setToAddress]=useState<string>("")
async function transfer(event:React.FormEvent) {
event.preventDefault()
if(!window.ethereum) return
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
const erc20:Contract = new ethers.Contract(addressContract, abi, signer)
erc20.transfer(toAddress,parseEther(amount))
.then((tr: TransactionResponse) => {
console.log(`TransactionResponse TX hash: ${tr.hash}`)
tr.wait().then((receipt:TransactionReceipt)=>{console.log("transfer receipt",receipt)})
})
.catch((e:Error)=>console.log(e))
}
const handleChange = (value:string) => setAmount(value)
return (
<form onSubmit={transfer}>
<FormControl>
<FormLabel htmlFor='amount'>Amount: </FormLabel>
<NumberInput defaultValue={amount} min={10} max={1000} onChange={handleChange}>
<NumberInputField />
</NumberInput>
<FormLabel htmlFor='toaddress'>To address: </FormLabel>
<Input id="toaddress" type="text" required onChange={(e) => setToAddress(e.target.value)} my={3}/>
<Button type="submit" isDisabled={!currentAccount}>Transfer</Button>
</FormControl>
</form>
)
}
解释一下:
我们调用transfer(address recipient, uint256 amount) → bool,这是ERC20智能合约的状态变化函数。
正如你所看到的,转移后ClassToken的余额没有改变。我们将在任务6中解决这个问题:
任务6:监听事件:在Web 应用中与智能合约交互
我们可以通过智能合约事件的设计来更新CLT余额。对于ERC20代币智能合约,当转账在链上被确认时,会发出一个事件Transfer(address from, address to, uint256 value)(文档)。
我们可以在Node.js webapp中监听这个事件并更新页面显示。
任务6.1: 了解智能合约事件
简单解释事件:当我们调用会智能合约的状态变化函数时,有三个步骤:
第1步:链外调用。我们使用JavaScript API(ethers.js)在链外调用智能合约的状态变化函数。
第2步:链上确认。状态改变交易需要由矿工使用共识算法在链上的几个区块进行确认。所以我们不能立即得到结果。
第3步:触发事件。一旦交易被确认,就会发出一个事件。你可以通过监听事件来获得链外的结果。
任务6.2:当当前账户变化时,添加事件监听器
编辑ReadERC20.tsx:
//call when currentAccount change
useEffect(()=>{
if(!window.ethereum) return
if(!currentAccount) return
queryTokenBalance(window)
const provider = new ethers.providers.Web3Provider(window.ethereum)
const erc20 = new ethers.Contract(addressContract, abi, provider)
// listen for changes on an Ethereum address
console.log(`listening for Transfer...`)
const fromMe = erc20.filters.Transfer(currentAccount, null)
provider.on(fromMe, (from, to, amount, event) => {
console.log('Transfer|sent', { from, to, amount, event })
queryTokenBalance(window)
})
const toMe = erc20.filters.Transfer(null, currentAccount)
provider.on(toMe, (from, to, amount, event) => {
console.log('Transfer|received', { from, to, amount, event })
queryTokenBalance(window)
})
// remove listener when the component is unmounted
return () => {
provider.removeAllListeners(toMe)
provider.removeAllListeners(fromMe)
}
}, [currentAccount])
这个代码片段改编自How to Fetch and Update Data From 以太坊 with React and SWR。
解释一下:
当currentAccount改变时(useEffect),我们添加两个监听器:一个用于从currentAccount转移的事件,另一个用于转移到currentAccount。
当监听到一个事件时,查询currentAccount的token余额并更新页面。
你可以在页面上或在MetaMask中从当前账户转账,你会看到页面在事件发生时正在更新。
当完成任务6时,你已经建立了一个简单而实用的DAPP,它有智能合约和Web页面。
综上所述,DAPP有三个部分:
智能合约和区块链
Web 应用(用户界面),通过智能合约获取和设置数据
用户控制的钱包(这里是MetaMask),作为资产管理工具和用户的签名者,以及区块链的连接器。
通过这些任务,我们还了解到3种与智能合约交互的方式:
读取:从智能合约中获取数据
写:在智能合约中更新数据
监听,监听智能合约发出的事件
在本教程中,我们直接使用ethers.js来连接到区块链。作者还有一篇使用 Web3-react 库进行连接的文章,有机会在翻译。
英文原文:https://dev.to/yakult/a-tutorial-build-dapp-with-hardhat-react-and-ethersjs-1gmi
学分: 222
分类: 去中心化应用
标签:
react
ethers.js
DApp
点赞 6
收藏 11
分享
Twitter分享
微信扫码分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
你可能感兴趣的文章
关于dapp和钱包连接的真相
530 浏览
Viem React 教程:如何转账、铸币和查看链状态
827 浏览
从零搭建仿Kickstarter的众筹Dapp
603 浏览
ethers.js v6使用!
1599 浏览
去中心化DApp体验(AR 世界)
424 浏览
React的Web3modal/wagmi之Hooks使用(四)
845 浏览
相关问题
ethers.js调用合约的时候,如果最终是失败的,ethers会提前报错,直接终止上链了,怎么样强制执行
1 回答
web3.py中如何调用 需要指定地址才可以调用的方法?
2 回答
使用ethers将一个大数传进合约里发生溢出后换成string传入报错(能直接给解决办法吗?)
1 回答
求一个 RainbowKit + react-router-dom (可以是 BrowserRouter 或 HashRouter ) 的范例
1 回答
如何寻找区块链相关的工作?
3 回答
android webview 跳转Dapp的webview url,怎么做到自动授权登陆,打开url,那边可以拿到我们的钱包账号等
1 回答
1 条评论
请先 登录 后评论
张小风
0xD305...609D
关注
贡献值: 869
学分: 4156
ETH
文章目录
关于
关于我们
社区公约
学分规则
Github
伙伴们
ChainTool
为区块链开发者准备的开源工具箱
合作
广告投放
发布课程
联系我们
友情链接
关注社区
Discord
Youtube
B 站
公众号
关注不错过动态
微信群
加入技术圈子
©2024 登链社区 版权所有 |
Powered By Tipask3.5|
粤公网安备 44049102496617号
粤ICP备17140514号
粤B2-20230927
增值电信业务经营许可证
×
发送私信
请将文档链接发给晓娜,我们会尽快安排上架,感谢您的推荐!
发给:
内容:
取消
发送
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
取消
举报
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!