范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

NO。7Web3世界使用Reactethers。js开发简单加密钱包

  互联网的技术日新月异,互联网不断深入人们的生活;
  web3.0将是彻底改变人们生活的互联网形式;
  web3.0使所有网上公民不再受到现有资源积累的限制;
  具有更加平等地获得财富和声誉的机会。
  web3.0会从哪里开始呢?
  本合集文章,授权转载,侵权必究。
  Web 3.0世界系列文章
  来源 : 代码与野兽
  【 Web3 系列文章 】
  NO.1 遇见Web3: 在 Web3 的世界中写下第一行 HelloWorld
  NO.2 全面系统的 Web3 学习路线,助你成为 Web3 开发专家
  NO.3 Web3世界:区块链、比特币、以太坊和智能合约
  NO.4 Remix IDE 使用与 VSCode 搭建 Solidity 开发环境
  NO.5 深入聊聊 Web3 世界中的协议和硬盘:IPFS
  NO.6 一文聊透 Solidity 语法:助你成为智能合约专家
  最近在开发一个 NFT 二创平台,其中包含了很多概念和技术。我会更新一个系列的文章来总结和沉淀在这个过程中的一些知识与思考。
  本文是对 ethers.js 进行一个全方位介绍,非常适合 web3 入门学习。 什么是 ethers.js?
  Web3 中的各类 DApp,都需要与智能合约进行交互。如果用原生 JS 来做这些事会很麻烦。这时就需要使用专属的 SDK。
  目前 JS 环境中有两个主流的库可以用来和智能合约进行交互,一个是 web3.js,另一个是 ethers.js。 ethers.js VS web3.js
  web3.js 比 ethers.js 出现的更早。但是目前 ethers.js 更受欢迎。
  主要原因有如下两点: 体积:ethers.js 体积仅有 116.5kb,web3.js 有 590.6kb。相差 5 倍左右。 设计理念:由于设计理念不同。web3.js 认为用户会在本地部署以太坊节点,私钥和网络连接状态由这个节点管理。但实际上大部分人都不会在本地部署以太坊节点。ethers.js 充分考虑了这一点,它是用 Provider 管理网络连接状态,用 Wallet 管理密钥,更加安全和灵活。而且原生支持 ENS。 ethers.js 基本使用介绍节点即服务
  由于在本地部署一个区块链节点的成本并不低,很少会有人真的部署一个节点,而是选择使用节点即服务。
  这类服务有很多,比如老牌的 Alchemy、Infura、Moralis 以及今年估值 102 亿美金的新秀 Tenderly。
  在这里我们选择 Alchemy,目前它的市场占有率是最高的。
  alchemy 的网址在这:dashboard.alchemy.com/。具体的注册登陆就不讲了。
  登陆之后我们创建一个 App。
  Chain 选择 Ethereum,Network 选择 Goerli。
  这样就成功创建了一个 App,点击后面的 view key,就可以查看 key。
  我们把它复制下来,后面会用到。
  构造合约
  在对合约进行读取或交互之前,我们首先需要构造一个合约对象。
  合约对象有三个构造参数,第一个是合约地址,是一个字符串。第二个是合约的 abi,可以是一个 JSON,第三个参数是 provider 对象,它用于管理网络连接状态。
  下面的例子中就是使用 alchemy 提供的 JSON RPC 接口作为网络连接。 const rpc = `https://eth-goerli.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_API_KEY}`; const provider = new ethers.providers.JsonRpcProvider(rpc);  const contract = new ethers.Contract(contractAddress, abi, provider)
  除了 JsonRpcProvider 以外,ethers 还有 IpcProvider、InfuraProvider、AlchemyProvider、Web3Provider 等多种 Provider。读取合约信息
  abi 中的方法会直接挂载到 contract 对象上,我们可以直接调用。
  不过需要注意,所有的操作都是异步的。(async () => {   const owner = await contract.owner();   console.log(owner); })();连接钱包
  由于和合约交互需要支付 gas 费用,所以必须有一个数字钱包。
  钱包有很多种,比如 MetaMask、Rainbow、Coinbase Wallet 等。其中 MetaMask 是最常用的一种数字钱包。
  这里主要介绍如何连接到 MetaMask。
  MetaMask 有一个浏览器插件,如果用户安装了该插件,在 window 对象下会有一个 ethereum 对象。我们可以调用 ethereum.request 方法发起请求,参数是一个对象,对象的 method 描述该次请求的操作。
  ethereum.request 方法是异步的,会返回一个数组,该数组是所有登陆钱包的账户地址字符串,第一个账户就是当前激活的账户。如果返回的数组长度为 0,则意味着没有登陆任何账户。(async ()=> {   const accounts = await ethereum.request({ method: "eth_requestAccounts" })    if(accounts.length === 0) {     throw Error("未登录任何账户")   }      const activeAccount = accounts[0]   console.log(activeAccount) })()
  我们还可以通过 ethereum.request 方法获取当前的网络状态。(async ()=> {   const chainId = await ethereum.request({ method: "eth_chainId" })   console.log(chainId) })()
  它会返回一个字符串。0x1 表示以太网主网;0x5 表示 Goerli 测试网,更多网络的 chainId 可以在这个网站查看:chainlist.org/。
  下面是使用 ethers.js 来连接 MetaMask 的代码。(async ()=> {   const provider = new ethers.providers.Web3Provider(window.ethereum)    const accounts = await provider.send("eth_requestAccounts", [])   const activeAccount = accounts[0] })()
  如果使用 MetaMask 作为 provider,那么就不需要再使用 alchemy 了。钱包
  在转账交易之前,我们需要创建一个 Wallet 实例,它的作用是对交易和消息进行签名。
  创建 Wallet 对象的方法有三种。
  通过 Wallet.createRandom 创建随机钱包
  这种方式创建的是一个单机钱包,需要连接网络。const wallet = ethers.Wallet.createRandom() wallet.connect(provider)
  通过助记词创建const wallet = new ethers.Wallet.fromMnemonic(mnenonic.phrase)
  通过私钥和 provider 创建const wallet = new ethers.Wallet(privateKey, provider)钱包信息
  我们可以在创建好的钱包上面获取很多有用的信息,比如钱包地址、助记词、私钥、交易次数等。console.log(wallet.address) console.log(await wallet.getAddress()) console.log(wallet.mnemonic) console.log(wallet.privateKey) console.log(wallet.getTransactionCount())转账
  一旦又了钱包,我们就可以向其他人发起转账交易。
  创建一个 tx 对象,它最少需要两个属性,to 和 value,分别表示接受钱包地址和转账额度。
  然后使用 wallet.sendTransaction 方法发送转账,它会返回一个 receipt 对象。这个对象有一个异步的 wait 方法,当交易上链后会返回。const tx = {   to: address,   value: ethers.utils.parseEther("0.1"), }  console.log("开始转账") const receipt = await wallet.sendTransaction(tx) await receipt.wait() console.log("完成转账")通过合约转账交易
  交易需要使用 Wallet 对象。再通过 wallet 作为合约的第三个构造参数创建 Contract 对象。
  调用合约的 transfer 方法,进行转账交易。该方法需要两个参数,转入的钱包地址字符串和转入的数量。
  transfer 会返回一个 tx 对象,该对象有一个异步的 wait 方法,会在交易完成后执行。const wallet = new ethers.Wallet(privateKey, provider)  const contract = new ethers.Contract(contractAddress, abi, wallet)  (async ()=> {   const tx = await contract.transfer(toAddress, ethers.utils.parseEther("1"))   await tx.wait() })()通过 signer 进行转账
  通常我们无法直接拿到 privateKey,但是可以通过 signer 对象间接使用 privateKey。只需要进行签名就可以进行交易。这也是最常用的交易方式。const signer = walletProvider.getSigner(); const tx = {   to,   value, }; const receipt = await signer.sendTransaction(tx); await receipt.wait();使用 React 和 ethers.js 开发加密钱包
  接下来我们开发一个最简单的加密钱包,具备最基础的转账功能和查询余额功能。创建项目
  我们首先创建一个 Next.js 项目。npx create-next-app
  需要选择 TypeScript。安装依赖安装 ethers.jsnpm i ethers安装 tailwindcssnpm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
  修改 tailwind.cinfig.js。/** @type {import("tailwindcss").Config} */ module.exports = {   content: [     "./pages/**/*.{js,ts,jsx,tsx}",     "./components/**/*.{js,ts,jsx,tsx}",   ],   theme: {     extend: {},   },   plugins: [], }
  修改 styles/globals.css。@tailwind base; @tailwind components; @tailwind utilities;安装 headless-uinpm install @headlessui/react整体架构设计
  由于业务并不复杂,我们可以将它简单划分为几个组件。使用 Context 足够应对这个场景,而不需要额外导入状态管理库来增加复杂性。
  Wallet 是根组件,内部维护了很多 state,以 Context 的方式将数据和操作注入到子组件。
  Connect 负责连接钱包和断开连接。
  Details 负责显示钱包信息,是纯展示型组件。
  Transfer 负责向其他账户进行转账。
  Loading 负责渲染加载动画,是纯展示型组件。创建上下文type IWalletCtx = {   walletProvider: any;   setWalletProvider: (walletProvider: any) => void;   msgIsOpen: boolean;   setMsgIsOpen: (msgIsOpen: boolean) => void;   msg: string;   setMsg: (msg: string) => void;   account: string;   setAccount: (account: string) => void;   networkName: string;   setNetworkName: (networkName: string) => void;   balance: string;   setBalance: (balance: string) => void;   showMessage: (message: string) => void;   refresh: boolean;   setRefresh: (refresh: boolean) => void; };  const WalletCtx = createContext({} as IWalletCtx);
  通过初始化一个对象,然后断言为 IWalletCtx 的方式,可以避免在使用 WalletCtx 时添加是否为 undefined 或 null 的判断。因为我们一定会注入数据。Loading 组件
  Loading 作为纯展示型组件,是最简单的组件。SVG 的代码是直接从 tailwindcss 文档中搬运过来的。仅仅是添加了一个 size 属性,用来展示不同大小的尺寸。function Loading({ size = "md" }: { size?: "sm" | "md" | "lg" | "xl" }) {   const sizes = {     sm: "h-3 w-3",     md: "h-5 w-5",     lg: "h-7 w-7",     xl: "h-9 w-9",   };   return (                           ); }Wallet 组件
  在 Wallet 组件中创建这些 state,并注入到 context 中。export default function Wallet() {   const [walletProvider, setWalletProvider] = useState(null);   const [msgIsOpen, setMsgIsOpen] = useState(false);   const [msg, setMsg] = useState("");   const [account, setAccount] = useState("");   const [networkName, setNetworkName] = useState("");   const [balance, setBalance] = useState("");   const [refresh, setRefresh] = useState(false);    useEffect(() => {     setWalletProvider(new ethers.providers.Web3Provider(window.ethereum));   }, []);    const showMessage = (message: string) => {     setMsg(message);     setMsgIsOpen(true);     setTimeout(() => {       setMsg("");       setMsgIsOpen(false);     }, 2000);   };    return (                      setMsgIsOpen(false)}>                                       {msg}                                                   
); }   Wallet 组件基本上没有什么逻辑,它的主要作用有三个:向 context 注入数据。创建 ethers.provider。使用 Dialog 组件作为全局消息提示。Connect 组件   在 styles/globals.css 中添加按钮样式。@layer components { .btn { @apply bg-black text-white py-2 px-4 rounded-3xl; } }   在 index.tsx 中编写逻辑。function Connect() { const { walletProvider, account, setAccount, setNetworkName, setBalance, showMessage, refresh, } = useContext(WalletCtx); const refreshBalance = useCallback(async () => { if (!walletProvider || !account) return; const balance = await walletProvider.getBalance(account); setBalance(ethers.utils.formatEther(balance)); }, [setBalance, walletProvider, account]); useEffect(() => { refreshBalance(); }, [refresh, refreshBalance]); const connectToMetamask = async () => { try { await window.ethereum.enable(); const accounts = await walletProvider.send("eth_requestAccounts", []); const network = await walletProvider.getNetwork(); const balance = await walletProvider.getBalance(accounts[0]); setAccount(accounts[0]); setNetworkName(network.name); setBalance(ethers.utils.formatEther(balance)); } catch (error) { console.log(error); showMessage("failed to connect to metamask"); } }; const disconnect = async () => { setAccount(""); }; if (!account) { return ( {walletProvider ? ( ) : ( )} ); } return (

Hello, {account}

); }   我们连接钱包后会获取 3 个重要的信息:钱包账户地址、连接的网络和余额。   分别通过 walletProvider.listAccounts()、walletProvider.getNetwork() 和 walletProvider.getBalance(accounts[0]) 来获取,需要注意它们都是异步操作。Details 组件   Details 作为纯展示型组件没有什么逻辑,主要是一些样式。function Details() { const { account, networkName, balance } = useContext(WalletCtx); if (!account) { return null; } return ( balance network: {networkName} {balance} ETH ); }   现在我们看一下 Connect 和 Details 组件一起使用的效果。   Transfer 组件   Transfer 的功能比较简单,它在 UI 上仅仅包含两个输入框和一个 send 按钮。   两个输入框分别可以输入 to 和 value,表示转账的钱包地址和转账金额。function Transfer() { const { walletProvider, account, showMessage, refresh, setRefresh } = useContext(WalletCtx); const [to, setTo] = useState(""); const [amount, setAmount] = useState(""); const [transferring, setTransferring] = useState(false); const transfer = async () => { try { const value = ethers.utils.parseEther(amount); const signer = walletProvider.getSigner(); const tx = { to, value, }; setTransferring(true); const receipt = await signer.sendTransaction(tx); await receipt.wait(); setTo(""); setAmount(""); showMessage("successfully transferred"); } catch (error) { console.log(error); showMessage("failed to transfer"); } finally { setTransferring(false); setRefresh(!refresh); } }; if (!account) { return null; } return ( Transfer {transferring ? ( transferring... ) : ( setTo(e.target.value)} type="text" placeholder="address" /> setAmount(e.target.value)} type="number" placeholder="amount" /> )} ); }   转账是通过 signer.sendTransaction 方法进行的,它会返回收据对象 receipt。   在转账时使用到了 ethers.utils.parseEther,因为 value 默认的单位是 wei,它非常小,10 的 18 次方才是一个 ehter。在 JS 中需要使用 BigInt 类型表示,并不方便操作,而我们更喜欢用 ether 来描述货币。所以这个 API 可以帮我们转换货币单位。   需要注意,在测试时需要选择 goerli 网或者其他测试网,否则会浪费 gas 费。   你至少要有两个钱包账户,这样可以从一个钱包账户转到另一个钱包账户。   下面我们来测试一下转账。   这时 MetaMask 钱包会弹出来签名界面。   点击确认后,需要等待一段时间上链,大约 1 分钟,或者更久。   转账成功后,当前账户的余额会刷新。   完成   现在一个简单的加密钱包就完成了。通过这个项目的学习,相信你已经学会了 ethers.js 常规 API 的使用。   源码链接:https://github.com/luzhenqian/web3-examples   线上地址:web3-examples.vercel.app/   web3.0 生态系统   Web 3世界非常精彩。   如果你对 Web3 感兴趣,右上角记得加个关注。   我会持续更新更多 Web3 相关的高质量文章。   #头条创作挑战赛# #web3.0#

青云山生态绿色青山永泰青云山风景名胜区位于福建省福州市永泰县岭路乡与莆田市涵江区交界处,是国家级AAAA重点景区国家重点风景名胜区。青云山,因山峰平地拔起,矗立青云而得名。景区面积47平方公里,海拔三亚海上观音菩萨原身像迁移漠河北极村始末三亚海上观音原身像林海观音像。三亚海上观音菩萨原身像迁移漠河北极村始末。一许愿观音原身像1995年前后三亚宗教局申请建造供奉观音菩萨像,得到批准后,按当时的技术能力先建造一尊佛身高贵州六盘水市水城区观音山,3万多人的繁华小城如今就剩下100来人1955年,省工业厅接管水城铁厂,观音山开始进入人们的视野,观音山铁矿也成为水城铁厂的原料供应基地。水城铁厂,观音山铁矿两个项目同时开工,正当建设得如火如荼时迎来3年困难期,铁厂和游记散文游观音山记(景卫平)游观音山记作者景卫平家乡人把上观音山叫朝高山,足以看出此山的险峻高远和在人心里的位置。因观音山和秦岭第二主峰首阳山相毗邻,两山雄姿巍峨参差,其间九峰朝揖,绵延似海,林荫蔽日。风景野仙三中的那些古董都是真实存在的么在仙剑三中,有一个很有意思的搜集古董的系统,玩家在游戏历程中通过各种不同的途径收集古董,后期主角景天会有自己的古董房间放置这些珍藏品,收集齐全游戏中总共30个古董之后,还可以获得一今日原始征途新区猛龙过江火热开启,再现国战风云猛龙过江乘风破浪,新区来袭风云再起。原始征途十国新区猛龙过江今日1000已正式开启!原汁原味,还原征途经典万人同屏,热血国战荣耀!更有超多新区福利活动,助力战力飞升,成就征途王者!勇士官宣签约!库里成作家,勇士遭遇续约麻烦,威金斯恐成牺牲品头条创作挑战赛勇士队官方宣布,球队正式签下了后卫杰罗姆罗宾逊,至此勇士队大名单基本确定,勇士官方也表示,过些时候将会公布训练营成员名单。据报道,勇士为杰罗姆罗宾逊提供的是一份一年合十大元帅中,有且只有3人官至正国级,彭老总并不在其中说起十大元帅,那可是为新中国的开国元勋,他们在革命战争中的贡献非常高。从某种意义上来讲,十大元帅就是毛主席身边的左膀右臂,没有他们,就没有新中国。十大元帅中,有人擅长军事指挥,有人1947年,毛主席告别延安,为什么此后几十年,再未踏上延安土地?1947年,蒋介石调集大量兵力围攻延安,毛主席和群众不得不离开这片生活了13年的土地。临走前,毛主席鼓励大家我们要用一个延安换取整个中国。事实也如他所料,没多久,蒋介石的国民党军队9990元!五羊本田发布新款踏板NCR125,颜值动力配置都不错没有进行任何宣传预热,五羊本田突然发布了新款踏板NCR125,将目标顾客锁定在都市通勤市场。这类车友除了追求舒适省心稳定耐用经济实惠之外,对颜值审美也有一定需求,于是当看到新车具有新车售12。99万元,拉低准入门槛,欧拉好猫新增两周年轻享型文懂车帝原创曹浩懂车帝原创产品日前,我们从官方获悉,欧拉好猫莫兰迪版新增上市两周年轻享型,补贴后售价为12。99万元。新车将会成为最新入门车型,外观提供多种颜色可选,但内饰将只提供
LA记者湖人当年要威少就是因其在奇才打得好而且次轮又不值钱直播吧1月24日讯据名记此前报道,湖人送出纳恩三次轮,从奇才得到八村塁。洛杉矶知名体育媒体人ArashMarkazi随后连发数推表达了自己对于这笔交易的看法。ArashMarkazUfc284两场冠军腰带战官宣!ufc284将于2月12日澳大利亚开打。作为主场ufc明星选手亚历山大出战头条主赛升重挑战轻量级冠军马哈切夫。亚历山大,绰号大帝战绩251,50站立终结率,13降伏率,ufcp4p世界排名更新!艾伦超特鲁姆普和罗伯逊跃居第三,丁俊晖排名不变北京时间2023年1月24日,世界斯诺克巡回赛正式更新排名!奥沙利文依然凭借出色的表现稳居世界第一,塞尔比则是紧随其后。让人意外的是,减肥归来的马克艾伦一举超越了特鲁姆普和罗伯逊排历届奥运会网球男单冠军(19882021)网球运动在首届奥运会1896年就是比赛项目,但由于国际奥委会和国际网球联合会在业余球员身份问题上产生分歧,奥运会网球比赛一度中段,直到1988年汉城奥运会才恢复成为正式比赛项目,下徐云丽的努力回忆告别赛场的女排白金一代队员之四头条创作挑战赛相比魏秋月出道即巅峰,徐云丽的努力成就最后的胜利更加的肉眼可见。这位从福建女排走出来的高大副攻,在当时福建女排主帅侯春俤的精细培养下迅速成长。而且侯春俤教练把她从主攻01后!2个连锁反应诞生国米提前退出争冠,罗马最快下轮进前2本赛季,意甲争冠的悬念越来越小了,除了那不勒斯的强势之外,还因为国米和AC米兰等豪门球队不争气。特别是国米,本轮他们竟然在自己的主场,01爆冷输给了恩波利,上一次他们在意甲输给这个高清修复老照片维密超模系列(3)之美国超模大咖玛莎亨特作者鸿运18k文鸿运18k回顾流金岁月,赏析维密超模情感图片维多利亚的秘密时尚秀中文名维多利亚的秘密时尚秀外文名VictoriasSecretFashionShow维多利亚的秘密品德甲排名比分沙尔克VS莱比锡!德甲积分回放LDSPORTS沙尔克在主场有着出色的进攻能力,在近20场主场比赛中只有2场平。沙尔克在上一轮联赛中客场03法兰克福,在最近6轮联赛中取得了1胜5负。沙尔克过去10场比赛中只有三场埃梅里率维拉取得16个联赛积分同期仅次于榜首的阿森纳据WhoScored的统计,埃梅里执教阿斯顿维拉之后,率队取得16个联赛积分,同期仅次于英超榜首的阿森纳。埃梅里在11月接手球队时,他面对的是一支只差1分即陷入降级区的球队。尽管在王者统治的洛杉矶湖人队开启了新的历史25日上午7点,湖人通过官方正式介绍了新队员八村。8月24日,八村塁正式加盟湖人队。他被华盛顿奇才队夺走了3张2R选秀指名权,与肯德里克南一起加入了湖人队。在官方网站也可以看到湖人女生朋友圈对男生的小心机,看看你是否中过招?都说世界上最浪漫的事,是和你一起慢慢变老。愿得一人心,白首不相离,这是每个男生和女生的心愿。但是世界上总有些事不遂人愿,心目中的男神和女神总是高高在上,不知道怎么去接近他们,也许朋