当前位置: 首页 > wzjs >正文

制作个人网站的软件淘宝指数查询官网

制作个人网站的软件,淘宝指数查询官网,深圳外贸网站优化,个人网站制作软件前言: 前面我们介绍了 solana 关于 anchor 智能合约的环境搭建 配置,简单编写 发布 部署 调用 的一些落地。等等。接下来我们借着案例。详细剖析下智能合约编写。 案例 vesting 介绍: 这是一个关于 释放 spl token 的案例。老板将 token 作为…

前言:

前面我们介绍了 solana 关于 anchor 智能合约的环境搭建 配置,简单编写 发布 部署 调用 的一些落地。等等。接下来我们借着案例。详细剖析下智能合约编写。

 案例 vesting 介绍:

这是一个关于 释放 spl  token 的案例。老板将 token 作为激励 发放给员工。包含 锁定期, 受益人 开始兑换时间,结束兑换时间, 解锁账户 等等,

主要功能步骤

  1. 雇主先创建一个  以公司名称作为派生种子的账户,用于存放 待释放 SPL Token,
  2. 雇主再为 每个员工创建一个 pad 账户,记录员工待解锁 账户的信息,(token总量,锁定期限,开始兑换期限,员工接收token地址 等等, )
  3. 员工领取 token

智能合约的分析: 

智能合约 编写包含很多固定写法。这里就不赘述了。可以先看前面的章节内容。我们这里主要介绍下 学到的新姿势:

 

  • 雇主创建 账户
    /**
    创建 老板解锁 账户:主要就是 给 vesting_account 赋值
    **/
    pub fn create_vesting_account(ctx: Context<CreateVestingAccount>,company_name:String
    ) -> Result<()> {*ctx.accounts.vesting_account = VestingAccount {owner: ctx.accounts.signer.key(),mint: ctx.accounts.mint.key(),treasury_token_account: ctx.accounts.treasury_token_account.key(),company_name,treasury_bump: ctx.bumps.treasury_token_account,bump: ctx.bumps.treasury_token_account,};Ok(())
    }#[derive(Accounts)]
    #[instruction(company_name:String)]
    pub struct CreateVestingAccount<'info>{#[account(mut)]pub signer: Signer<'info>,#[account(init,space = 8 + VestingAccount::INIT_SPACE,payer = signer,seeds = [company_name.as_ref()],bump,)]pub vesting_account: Account<'info, VestingAccount>,pub mint:InterfaceAccount<'info, Mint>,/**1. 需要创建2. 指定 spl  mint3. 授权账户就是自己4. 支付的费用5. 生成 pda 账户种子6. pda bump**/#[account(init,token::mint = mint,token::authority = treasury_token_account,payer = signer,seeds = [b"vesting_treasury".as_ref(),company_name.as_ref()],bump,)]pub treasury_token_account:InterfaceAccount<'info,TokenAccount>,pub system_program: Program<'info, System>,pub token_program: Interface<'info, TokenInterface>,
    }/**
    解锁账户 雇主操作的账户 用于公司员工管理,存储需要解锁的 spl token1.owner 归属人 觉得谁可以更新2.spl 发放 spl mint3.用于保存 spl 账户信息,雇主 用于分配 所有要发放的 SPL4.公司名称 标识,  用于派生 PDA5.保存 分配 SPL 账户的 bump,6.保存 归属账号的 bump宏 :#[account]  用于构造数据 指定改结构体为一个 solana 账户#[derive(InitSpace)] 是对数据结构的实现, 指定我们想要使用 InitSpace,会让 anchor 自动计算 结构体大小#[max_len(50)]  字符串类型没有固定大小,这里指定为 固定大小 才能使用 InitSpace 推导出结构体大小
    **/
    #[account]
    #[derive(InitSpace)]
    pub struct VestingAccount {pub owner: Pubkey,pub mint: Pubkey,pub treasury_token_account: Pubkey,#[max_len(50)]pub company_name:String,pub treasury_bump:u8,pub bump:u8,
    }
  • 雇主为每个员工 创建账号

    /**
    创建雇员 待解锁的账号:
    结构体包含 解锁 token 的  所有信息
    **/
    pub fn create_employee_account(ctx: Context<CreateEmployeeAccount>,start_time:i64,end_time:i64,total_amount:u64,cliff_time:i64,
    ) -> Result<()> {*ctx.accounts.employee_account = EmployeeAccount {beneficiary: ctx.accounts.beneficiary.key(),start_time,end_time,total_amount,total_withdrawn:0,cliff_time,vesting_account: ctx.accounts.vesting_account.key(),bump:ctx.bumps.employee_account,};Ok(())
    }/**1.支付费用的账户2.受益人账户,领取 token 的 账户地址3.操作该账户的权限4.员工账户5.指定系统程序
    **/
    #[derive(Accounts)]
    pub struct CreateEmployeeAccount<'info>{#[account(mut)]pub owner:Signer<'info>,pub beneficiary:SystemAccount<'info>,//has_one 解锁 账户的所有者 是刺指令的签名者 owner#[account(has_one = owner,)]pub vesting_account:Account<'info, VestingAccount>,//创建员工账户#[account(init,space = 8 + EmployeeAccount::INIT_SPACE,payer = owner,seeds = [b"employee_vesting", beneficiary.key().as_ref(), vesting_account.key().as_ref()],bump,)]pub employee_account: Account<'info, EmployeeAccount>,pub system_program: Program<'info, System>,
    }/**1.受益人  接收token 的雇员 钱包 (ATA账号)2.开始兑换时间  unix 时间3.截止的兑换时间4.锁定期 员工需要等待多久才能解锁(类似期权,几年不能交易)5.解锁账户 雇主创建的放 spl token 的账户6.分配给该员工的 总 spl 数量7.记录该员工 解锁的数量,用于后期计算
    **/
    #[account]
    #[derive(InitSpace)]
    pub struct EmployeeAccount {pub beneficiary: Pubkey,pub start_time:i64,pub end_time:i64,pub cliff_time:i64,pub vesting_account: Pubkey,pub total_amount:u64,pub total_withdrawn:u64,pub bump:u8,
    }
  • 员工释放 token

    /**
    员工认领 Token,保证员工在正确的时间里 领取 token**/
    pub fn claim_tokens(ctx:Context<ClaimTokens>,company_name:String,) -> Result<()>{//获取员工账户(有老板已经创建好的)let employee_account =&mut ctx.accounts.employee_account;//获取系统时间let now = Clock::get()?.unix_timestamp;//当前时间小于 锁定期则 不能释放if now < employee_account.cliff_time {return  Err(ErrorCode::ClaimNotAvailableYet.into())}//已经开放的时间, saturating_sub 防止数组越界let time_since_start = now.saturating_sub(employee_account.start_time);//总释放时间let total_vesting_time = employee_account.end_time.saturating_sub(employee_account.start_time);if total_vesting_time == 0 {return  Err(ErrorCode::InvalidVestingPeriod.into())}//解锁数量//如果当前时间 大于 释放结束时间。那可以全部都 解锁掉let vested_amount = if now >= employee_account.end_time {employee_account.total_amount}else {//checked_mul 防止 乘法的溢出//数量*总的开放时间 / 当前已经开放的时间 = 当前开放时间可以获取的数量match employee_account.total_amount.checked_mul(time_since_start as u64) {Some(product) => product / (total_vesting_time as u64),None =>{return  Err(ErrorCode::CalculationOverflow.into())}}};//可申领金额let claimable_amount = vested_amount.saturating_sub(employee_account.total_withdrawn);if claimable_amount == 0 {return  Err(ErrorCode::NothingToClaim.into())}//从老板设立的账号中 转账 到员工let transfer_cpi_accounts = TransferChecked {from: ctx.accounts.treasury_token_account.to_account_info(),mint: ctx.accounts.mint.to_account_info(),//to: ctx.accounts.employee_account.to_account_info(),to: employee_account.to_account_info(),//已经将权限设置为自己了。所有这里是可以调用的authority: ctx.accounts.treasury_token_account.to_account_info(),};let cip_program = ctx.accounts.token_program.to_account_info();let signer_seeds:&[&[&[u8]]] = &[&[b"vesting_treasury",ctx.accounts.vesting_account.company_name.as_ref(),&[ctx.accounts.vesting_account.treasury_bump],]];let cpi_context = CpiContext::new(cip_program, transfer_cpi_accounts).with_signer(signer_seeds);let decimals = ctx.accounts.mint.decimals;token_interface::transfer_checked(cpi_context, claimable_amount, decimals)?;employee_account.total_withdrawn += claimable_amount;Ok(())
    }}

依赖 Cargo.toml:

[package]
name = "tokenvesting"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"[lib]
crate-type = ["cdylib", "lib"]
name = "tokenvesting"[features]
default = []
cpi = ["no-entrypoint"]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
idl-build = ["anchor-lang/idl-build","anchor-spl/idl-build"][dependencies]
#cargo add anchor-lang --features init-if-needed
anchor-lang = { version = "0.31.1", features = ["init-if-needed"] }
anchor-spl = "0.31.1"
solana-program = "2.3.0"

完整脚本: 

#![allow(clippy::result_large_err)]use anchor_lang::prelude::*;
use anchor_spl::associated_token::AssociatedToken;
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface, TransferChecked};declare_id!("JAVuBXeBZqXNtS73azhBDAoYaaAFfo4gWXoZe2e7Jf8H");/**
(智能合约 和 http 请求类似都是 无状态的)
智能合约主要功能:1.雇主先创建一个  以公司名称作为派生种子的账户,用于存放 待释放 SPL Token,2.雇主再为 每个员工创建一个 pad 庄户,记录员工带解锁庄户的信息,(token总量,锁定期限,开始兑换期限,员工接收token地址 等等, )3.员工领取 token**/
#[program]
pub mod vesting {use super::*;use anchor_spl::token_interface;/**创建 老板解锁 账户:主要就是 给 vesting_account 赋值**/pub fn create_vesting_account(ctx: Context<CreateVestingAccount>,company_name: String,) -> Result<()> {*ctx.accounts.vesting_account = VestingAccount {owner: ctx.accounts.signer.key(),mint: ctx.accounts.mint.key(),treasury_token_account: ctx.accounts.treasury_token_account.key(),company_name,treasury_bump: ctx.bumps.treasury_token_account,bump: ctx.bumps.treasury_token_account,};Ok(())}/**创建雇员 待解锁的账号:结构体包含 解锁 token 的  所有信息**/pub fn create_employee_account(ctx: Context<CreateEmployeeAccount>,start_time: i64,end_time: i64,total_amount: u64,cliff_time: i64,) -> Result<()> {*ctx.accounts.employee_account = EmployeeAccount {beneficiary: ctx.accounts.beneficiary.key(),start_time,end_time,total_amount,total_withdrawn: 0,cliff_time,vesting_account: ctx.accounts.vesting_account.key(),bump: ctx.bumps.employee_account,};Ok(())}/**员工认领 Token,保证员工在正确的时间里 领取 token**/pub fn claim_tokens(ctx: Context<ClaimTokens>, company_name: String) -> Result<()> {//获取员工账户(有老板已经创建好的)let employee_account = &mut ctx.accounts.employee_account;//获取系统时间let now = Clock::get()?.unix_timestamp;//当前时间小于 锁定期则 不能释放if now < employee_account.cliff_time {return Err(ErrorCode::ClaimNotAvailableYet.into());}//已经开放的时间, saturating_sub 防止数组越界let time_since_start = now.saturating_sub(employee_account.start_time);//总释放时间let total_vesting_time = employee_account.end_time.saturating_sub(employee_account.start_time);if total_vesting_time == 0 {return Err(ErrorCode::InvalidVestingPeriod.into());}//解锁数量//如果当前时间 大于 释放结束时间。那可以全部都 解锁掉let vested_amount = if now >= employee_account.end_time {employee_account.total_amount} else {//checked_mul 防止 乘法的溢出//数量*总的开放时间 / 当前已经开放的时间 = 当前开放时间可以获取的数量match employee_account.total_amount.checked_mul(time_since_start as u64){Some(product) => product / (total_vesting_time as u64),None => return Err(ErrorCode::CalculationOverflow.into()),}};//可申领金额let claimable_amount = vested_amount.saturating_sub(employee_account.total_withdrawn);if claimable_amount == 0 {return Err(ErrorCode::NothingToClaim.into());}//从老板设立的账号中 转账 到员工let transfer_cpi_accounts = TransferChecked {from: ctx.accounts.treasury_token_account.to_account_info(),mint: ctx.accounts.mint.to_account_info(),//to: ctx.accounts.employee_account.to_account_info(),to: employee_account.to_account_info(),//已经将权限设置为自己了。所有这里是可以调用的authority: ctx.accounts.treasury_token_account.to_account_info(),};let cip_program = ctx.accounts.token_program.to_account_info();let signer_seeds: &[&[&[u8]]] = &[&[b"vesting_treasury",ctx.accounts.vesting_account.company_name.as_ref(),&[ctx.accounts.vesting_account.treasury_bump],]];let cpi_context =CpiContext::new(cip_program, transfer_cpi_accounts).with_signer(signer_seeds);let decimals = ctx.accounts.mint.decimals;token_interface::transfer_checked(cpi_context, claimable_amount, decimals)?;employee_account.total_withdrawn += claimable_amount;Ok(())}
}/**
创建雇主账号1.signer  mut 签名者,支付手续费,应为需要支付手续费 所以需要是 mut2.指定 解锁账号 派生信息3.spl mint 地址4.存储 激励 spl 的 ATA 地址,(即将分配给 员工的 Token)5.指定使用到的系统程序 System6.指定使用到的系统程序 TokenInterface宏:#[instruction(company_name:String)] 是对数据结构的实现 (创建), 指定入参 company_name**/#[derive(Accounts)]
#[instruction(company_name:String)]
pub struct CreateVestingAccount<'info> {#[account(mut)]pub signer: Signer<'info>,#[account(init,space = 8 + VestingAccount::INIT_SPACE,payer = signer,seeds = [company_name.as_ref()],bump,)]pub vesting_account: Account<'info, VestingAccount>,pub mint: InterfaceAccount<'info, Mint>,/**1. 需要创建2. 指定 spl  mint3. 授权账户就是自己4. 支付的费用5. 生成 pda 账户种子6. pda bump**/#[account(init,token::mint = mint,token::authority = treasury_token_account,payer = signer,seeds = [b"vesting_treasury".as_ref(),company_name.as_ref()],bump,)]pub treasury_token_account: InterfaceAccount<'info, TokenAccount>,pub system_program: Program<'info, System>,pub token_program: Interface<'info, TokenInterface>,
}/**
解锁账户 雇主操作的账户 用于公司员工管理,存储需要解锁的 spl token1.owner 归属人 觉得谁可以更新2.spl 发放 spl mint3.用于保存 spl 账户信息,雇主 用于分配 所有要发放的 SPL4.公司名称 标识,  用于派生 PDA5.保存 分配 SPL 账户的 bump,6.保存 归属账号的 bump宏 :#[account]  用于构造数据 指定改结构体为一个 solana 账户#[derive(InitSpace)] 是对数据结构的实现, 指定我们想要使用 InitSpace,会让 anchor 自动计算 结构体大小#[max_len(50)]  字符串类型没有固定大小,这里指定为 固定大小 才能使用 InitSpace 推导出结构体大小
**/
#[account]
#[derive(InitSpace)]
pub struct VestingAccount {pub owner: Pubkey,pub mint: Pubkey,pub treasury_token_account: Pubkey,#[max_len(50)]pub company_name: String,pub treasury_bump: u8,pub bump: u8,
}/**1.支付费用的账户2.受益人账户,领取 token 的 账户地址3.操作该账户的权限4.员工账户5.指定系统程序
**/
#[derive(Accounts)]
pub struct CreateEmployeeAccount<'info> {#[account(mut)]pub owner: Signer<'info>,pub beneficiary: SystemAccount<'info>,//has_one 解锁 账户的所有者 是刺指令的签名者 owner#[account(has_one = owner,)]pub vesting_account: Account<'info, VestingAccount>,//创建员工账户#[account(init,space = 8 + EmployeeAccount::INIT_SPACE,payer = owner,seeds = [b"employee_vesting", beneficiary.key().as_ref(), vesting_account.key().as_ref()],bump,)]pub employee_account: Account<'info, EmployeeAccount>,pub system_program: Program<'info, System>,
}/**1.受益人  接收token 的雇员 钱包 (ATA账号)2.开始兑换时间  unix 时间3.截止的兑换时间4.锁定期 员工需要等待多久才能解锁(类似期权,几年不能交易)5.解锁账户 雇主创建的放 spl token 的账户6.分配给该员工的 总 spl 数量7.记录该员工 解锁的数量,用于后期计算
**/
#[account]
#[derive(InitSpace)]
pub struct EmployeeAccount {pub beneficiary: Pubkey,pub start_time: i64,pub end_time: i64,pub cliff_time: i64,pub vesting_account: Pubkey,pub total_amount: u64,pub total_withdrawn: u64,pub bump: u8,
}/**
员工认领 token1.交易的签名2.查找 待认领的 员工账户信息,雇主创建好的, mut 可编辑, has_one 约束验证,结构体中 EmployeeAccount 的两个字段与 当前约束值 是否一直3.查找 存放 解锁的 spl token 账户, mut 可编 has_one = treasury_token_account,has_one = mint 共同约束 vesting_account pda 账户4.spl mint 信息, 确定  vesting_account5.待 解锁的 老板庄户6.员工 待接收的 token account 账户
**/
#[derive(Accounts)]
#[instruction(company_name:String)]
pub struct ClaimTokens<'info> {#[account(mut)]pub beneficiary: Signer<'info>,#[account(mut,seeds = [b"employee_vesting",beneficiary.key().as_ref(),vesting_account.key().as_ref()],bump = employee_account.bump,has_one = beneficiary,has_one = vesting_account,)]pub employee_account: Account<'info, EmployeeAccount>,//宏  根据 传入的公司名称处理,是否存在 对应的pad#[account(mut,seeds = [company_name.as_ref()],bump = vesting_account.bump,has_one = treasury_token_account,has_one = mint,)]pub vesting_account: Account<'info, VestingAccount>,pub mint: InterfaceAccount<'info, Mint>,#[account(mut)]pub treasury_token_account: InterfaceAccount<'info, TokenAccount>,#[account(init_if_needed,payer = beneficiary,associated_token::mint = mint,associated_token::authority = beneficiary,associated_token::token_program = token_program,)]pub employee_token_account: InterfaceAccount<'info, TokenAccount>,pub token_program: Interface<'info, TokenInterface>,pub associated_token_program: Program<'info, AssociatedToken>,pub system_program: Program<'info, System>,
}#[error_code]
pub enum ErrorCode {#[msg("Claim not available yet")]ClaimNotAvailableYet,#[msg("Invalid Vesting Period")]InvalidVestingPeriod,#[msg("Calculation Overflow")]CalculationOverflow,#[msg("Nothing To Claim")]NothingToClaim,
}

http://www.dtcms.com/wzjs/121969.html

相关文章:

  • 网站域名被注销在哪个平台做推广比较好
  • 深圳图派做的网站后台加什么赣州seo公司
  • 高创园网站建设方案怎样打百度人工客服热线
  • 做360全景的网站360广告推广平台
  • 普洱做网站的报价百度网盘客服电话人工服务
  • 深圳网站开发建设培训机构网页分析报告案例
  • 物流行业网站建设市场分析暴风seo论坛
  • 做向日葵的专业网站福州seo扣费
  • 网站建设优化规划书系统优化软件有哪些
  • 营销型网站建设哪家便宜小程序开发费用一览表
  • 爱发电怎么做网站网站seo运营
  • 网和网站的区别如何开通网站
  • 极简 网站模板国家高新技术企业查询
  • 环球旅行社网站建设规划书论文下载百度到桌面
  • 专业做制作网站新手做电商怎么起步
  • 一个ip可以做几个网站山西网络推广
  • 广州的网站建设公司佛山百度推广电话
  • 动态网站的五个组成部分什么是搜索引擎优化?
  • 网站制作与管理技术...怎么建立网站快捷方式
  • javaee网站开发视频搜索引擎优化seo专员
  • 代写代码的平台seo的基本步骤顺序正确的是
  • 网络营销方式ppt东莞百度seo哪里强
  • 本机做web打开网站无法显示网站网站推广的基本方法是
  • 组建网站建设团队软文代写兼职
  • 安徽海绵城市建设协会网站全网营销思路
  • 做矢量图的网站网址检测
  • 做淘宝要用的网站吗临沂seo优化
  • 个人备案网站可以做支付吗信阳网络推广公司
  • 印度做杂质的网站友情链接还有用吗
  • 怎么向网站添加型号查询功能seo网站优化做什么