🌞

实现一个web3-Dapp(Solana+Phantom)

现在对于 web3 的讨论就像是一个“会走路的大饼”,你说它行,会有人喷;你说它不行也会有人喷,个人的一些观点:现在web3.0的产品没有一个比对应的web2的产品多提供了用户价值的资本力量很重要 但

文链接在语雀:https://www.yuque.com/wumingshi/rkh1qq/

现在对于 web3 的讨论就像是一个“会走路的大饼”,你说它行,会有人喷;你说它不行也会有人喷,个人的一些观点:

  • 现在web3.0的产品没有一个比对应的web2的产品多提供了用户价值的
  • 资本力量很重要 但不是核心,算是助推剂;核心的我认为是项目方背景,他们有影响力,有人(投资方+韭菜)愿意参与。
  • 真实的价值目前不明显,后续会有,当时还只是解决了上链之后的资源的ownership问题
  • 从底层改变了生产关系,但是对生产力的影响现在我觉得没有,反而效率更低

尽管如此,作为一个对新技术敏感的前端鹅,怎么可以说自己不会 web3 开发呢?通过一些辅助工具可以快速部署一个web3应用。

以下内容不是 step by step 教程,目的只是体感整体的开发部署流程

写在前边

在开始开发之前,你需要明确几个概念

  • 钱包(Phantom)
  • 区块链(Solana)
  • 智能合约
  • 交易

不需要深入了解,明晰基础概念即可。目前市面上已经有很多 web3 应用,感兴趣的可以看下之前写的一点随笔

接下来,就跟随我一步步探索出一个 web3 应用。进入页面之前,你需要:

  • 体验web3应用当然需要安装一个钱包,Phantom钱包
  • 选择开发网络

  • 开发网络需要有一定的Solana币,可以看下文找到获取币的方式
  • 最后就可以进入 应用,应用的功能就是存储图片链接,每条存储记录都会被永久保存在链上。

写下我的智能合约

智能合约可以理解为就是一个服务,服务一般会运行在一个区块链上,这里选择 Solana 作为自己开发的链,原因主要在于:1)合约编写的语言不需要额外学习,例如以太坊你可能需要了解下solidity等;2)作为后起之秀,运行速度远胜于当前版本的以太坊;2)测试环境(功能同线上一模一样)找水管比较容易,实现部署到测试网络的目的。

step1: solana套件

solana提供了完善的开发套件,基于安装的CLI可以实现我们的本地开发&部署等;例如使用 solana-test-validator 直接开启本地节点,从而完成自己的本地开发过程。

整体的开发过程我们可以直接基于测试网络进行,每次交易(这里的请求)都是会消耗一些 GAS 费用的,所以没必要在线上运行自己的代码

solana config set --url localhost
solana config get

solana-test-validator

以上便可以相当于在本地环境启动了一个测试网络。可以为所欲为的部署运行自己的合约等。

step2: anchor辅助

安装:

cargo install --git https://github.com/project-serum/anchor anchor-cli --locked

anchor是用来帮助开发solana智能合约的辅助套件,可以简化一些重复没必要的流程,就像以太坊也有一个Hardhat。通过anchor隐藏合约相关的一些具体实现细节,让我们只关注在功能开发本身。

通过anchor可以直接初始一个脚手架,可谓相当贴心了。

anchor init myepicproject --javascript

初始的手脚架,默认内置了一些辅助包,连测试用例的编写方法都给你安排好了。

合约的核心代码:

use anchor_lang::prelude::*;

declare_id!("83JEudwc9cKDBfyVH......");

#[program]
pub mod myepicproject {
    use super::*;

    pub fn start_stuff_off(ctx: Context<StartStuffOff>) -> Result <()> {
        let base_account = &mut ctx.accounts.base_account;
        base_account.total_gifs = 0;
        Ok(())
    }

    pub fn add_gif(ctx: Context<AddGif>, gif_link: String) -> Result<()> {
        let base_account = &mut ctx.accounts.base_account;
        let user = &mut ctx.accounts.user;
        let item = ItemStruct {
            gif_link: gif_link.to_string(),
            user_address: *user.to_account_info().key,
        };
        base_account.gif_list.push(item);
        base_account.total_gifs += 1;
        Ok(())
    }
}

// Attach certain variables to the StartStuffOff context.
#[derive(Accounts)]
pub struct StartStuffOff<'info> {
    #[account(init, payer = user, space = 9000)]
    pub base_account: Account<'info, BaseAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program <'info, System>,
}

#[derive(Accounts)] 
pub struct AddGif<'info> {
    #[account(mut)]
    pub base_account: Account<'info, BaseAccount>,
    #[account(mut)]
    pub user:Signer<'info>,
}

#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)]
pub struct ItemStruct {
    pub gif_link: String,
    pub user_address: Pubkey
}

// Tell Solana what we want to store on this account.
#[account]
pub struct BaseAccount {
    pub total_gifs: u64,
    pub gif_list: Vec<ItemStruct>
}


以上的代码,大概看看就好,核心无非是定义一个programid用于部署更新作为唯一标识,定义数据结构以及添加一些自定义的逻辑;同时将数据可以直接定义在链上,这也是Solana一个比较好的特性,可以在链上进行一定量的存储(大小优先)。

对于以太坊则需要额外的第三方的去中心化的存储,对于去中心化存储又是一个比较大的话题了,感兴趣的可以先从IPFS开始。

step3:合约部署

切换到开发者网络,可以直接进行空投

solana config set --url devnet

solana airdrop 2 // 进行空投,一般都会成功

有了币之后,就可以开始部署我们的网络

anchor deploy

例如我部署的合约地址:https://explorer.solana.com/address/83JEudwc9cKDBfyVHgSyjwoZCEBgF8wTmM685DqNx8wM?cluster=devnet

至此我们的只能合约就完成了


前端进行交易

核心依赖

@project-serum/anchor 、 @solana/web3.js 、chrome 插件:Phantom

当安装完chrome插件:Phantom之后,会在前端window下注入solana对象,这就是我们核心利用钱包的方式。

流程解析

当我们进行添加一个图片的链接的时候,看看发生了什么:

建立链接

import { Connection, PublicKey, clusterApiUrl } from '@solana/web3.js';
import { Program, Provider, web3 } from '@project-serum/anchor';

const getProvider = () => {
    const connection = new Connection(network, opts.preflightCommitment);
    const provider = new Provider(
      connection, window.solana, opts.preflightCommitment,
    );
    return provider;
  }

初始化应用,这里progameID等信息就是我们之前部署的合约ID

...

const program = new Program(idl, programID, provider);

发起交易,即调用合约的方法,将我们的输入值进行上链

...

await program.rpc.addGif(inputValue, {
        accounts: {
          baseAccount: baseAccount.publicKey,
          user: provider.wallet.publicKey,
        },
      });



至此即完成了一个基础的web3应用

写在最后

在完成一个demo的过程,最大感触就是基于链的相关基建竟然如此完善,开发一个web3应用对于一个小白都可以快速掌握,围绕开发、部署链路的工具平台非常完善。


updatedupdated2023-10-312023-10-31