Solana上的代币扩展

  • tobs.x
  • 发布于 1天前
  • 阅读 148

本文深入探讨了Solana区块链上的Token扩展,这些扩展为SPL代币增加了额外的功能和元数据,超越了基本代币的能力。

Solana 上的 Token Extensions 是可以添加到 SPL (Solana Program Library) token 的附加功能或元数据,这增强了它们在基本 token 功能之外的功能。这些扩展提供了各种类型的特性,这些特性不是标准 token 规范的一部分。在本文中,我们将探讨 token extensions。我们将了解它是如何工作的以及它的好处。我们将看看各种扩展和用例。最后,我们将了解如何将 token extensions 添加到你的项目中。

为什么存在 Token Extensions?

在此之前,在 SPL (Solana Program Library) Token 程序上创建的 Token,它支持同质化和非同质化 token,仅提供基本功能。SPL 为所有 token 类型提供了一个统一的标准,只有基本功能,这意味着开发人员必须在 token 程序之上构建自定义程序才能获得增强的功能。这种将更改推送到智能合约级别以添加新功能的做法通常会导致程序出现多个变体或版本,从而导致缺乏统一性,增加开发成本和浪费时间。

为了解决这些常见问题,Solana Labs 开发了可以与原始 token 程序集成的 Token extensions。从 2021 年末开始的开发,从概念到完成历时近两年,其中包括经过 Trail of Bits、Ottersec 和 Zellic 等著名公司的六次审计。Token Extensions 的主要目标是使开发人员能够轻松安全地在链上构建和启动资产。

Solana 上的 Token 标准

Solana Library Program:

SPL (Solana Program Library) Tokens:它们是在 Solana 区块链上创建和管理 token 的主要标准。SPL token 作为 Solana 生态系统的基础组件被引入,它为同质化 token(如加密货币)和非同质化 token(NFT)建立了规则。SPL Token Program 是 Solana Program Library (SPL) 的一个基本组件,旨在促进在 Solana 区块链上创建、管理和交互同质化和非同质化 token。SPL token 被设计成模块化和可重用的,允许开发人员通过在现有代码库的基础上构建来创建新的 token。

技术

SPL token 是使用 Solana 的 Rust 编程语言和智能合约功能创建和管理的。

Solana 的共识机制,历史证明 (PoH),与权益证明 (PoS) 相结合,确保

高可扩展性和性能,从而使 SPL token 交易受益。

SPL Token 允许基本功能,如 Token 创建,销毁,冻结,铸币权限。

在这里,我将向你展示如何使用 Solana CLI 库轻松地为你的 token 添加功能。

要安装 Solana 命令行界面 (CLI) 并管理 Solana token,你可以按照以下步骤操作:

安装

1. 安装 Solana CLI

打开你的终端并运行以下命令以安装 Solana CLI:

sh -c "$(curl -sSfL https://release.solana.com/stable/install)"

此命令下载并安装 Solana CLI 的最新稳定版本。

2. 设置环境变量

安装完成后,你需要将 Solana CLI 添加到系统的 PATH 中。将以下行添加到你的 shell 配置文件(.bashrc、.zshrc 等):

export PATH="/home/your-username/.local/share/solana/install/active_release/bin:$PATH"

将 your-username 替换为你的实际用户名。然后,重新加载你的 shell 配置:

source ~/.bashrc  # or `source ~/.zshrc` for Zsh users

3. 验证安装

通过检查 Solana 版本来确认安装:

solana --version

这应输出已安装的 Solana CLI 的版本。

4. 创建一个新钱包

要与 Solana token 交互,你需要一个钱包。通过生成密钥对来创建一个新钱包:

solana-keygen new

按照提示保存你的密钥对。这将创建一个新钱包并保存密钥对文件。

SPL 上的 Token 特性:

1. Token 创建:现在,你可以使用 Solana CLI 创建和管理 token。要创建一个新的 SPL token,请使用:

spl-token create-token

2. 铸币:允许创建新的 token。开发人员可以在铸币过程中定义总供应量、小数位和其他属性。

要铸造新的 token,请使用:

spl-token mint <TOKEN_ADDRESS> <AMOUNT> <RECIPIENT_ACCOUNT_ADDRESS>

将 <TOKEN_ADDRESS> 替换为 token 地址,<AMOUNT> 替换为要铸造的 token 数量,<RECIPIENT_ACCOUNT_ADDRESS> 替换为接收者的 token 帐户地址。

这是一个完整的示例,说明如何创建一个 Token 并将其关联到特定地址并铸造初始供应。

## Create a new token
TOKEN_MINT=$(spl-token create-token | grep -oP '(?&lt;=Creating token ).*')

## Create a token account
TOKEN_ACCOUNT=$(spl-token create-account $TOKEN_MINT | grep -oP '(?&lt;=Creating account ).*')

## Mint tokens to the account
spl-token mint $TOKEN_MINT 1000 $TOKEN_ACCOUNT

echo "Token Mint Address: $TOKEN_MINT"
echo "Token Account Address: $TOKEN_ACCOUNT"

3. 铸币权限:

指定一个帐户或实体,该帐户或实体有权铸造新的 token。此权限可以重新分配或撤销。

spl-token authorize &lt;TOKEN_MINT_ADDRESS> --mint &lt;NEW_MINT_AUTHORITY_PUBLIC_KEY>
Set variables
MINT_ADDRESS="your_mint_address_here"
BURN_AUTHORITY_KEYPAIR_PATH="path/to/burn_authority.json"
TOKEN_ACCOUNT_ADDRESS="your_token_account_address_here"
AMOUNT_TO_BURN=100

4. 销毁:

可以通过销毁 token 将其从流通中移除,从而有效地减少总供应量。

spl-token burn &lt;TOKEN_ACCOUNT_ADDRESS> &lt;AMOUNT>

将 <TOKEN_ACCOUNT_ADDRESS> 替换为你要从中销毁 token 的 token 帐户的地址,<AMOUNT> 替换为要销毁的 token 数量。

例如

## Burn 50 tokens from User 1's token account
spl-token burn $USER1_TOKEN_ACCOUNT 50

5. 转账:

促进帐户之间 token 的转账。SPL Token Program 确保这些转账安全高效。

要确保可以转账 token,发起转账的钱包必须具有必要的权限。

所有者权限:创建 token 帐户的钱包通常具有从中转账 token 的权限。

委托权限:如果需要,你可以将转账权限委托给另一个帐户。

委托转账权限

委托权限:使用 SPL Token CLI 将转账权限委托给另一个帐户。

spl-token authorize &lt;TOKEN_ACCOUNT_ADDRESS> --transfer &lt;NEW_TRANSFER_AUTHORITY_PUBLIC_KEY>

创建 Token 帐户后,你可以将 token 转账到其他地址。

spl-token transfer &lt;TOKEN_MINT_ADDRESS> &lt;AMOUNT> &lt;RECIPIENT_TOKEN_ACCOUNT>

6. 帐户:

用户需要创建 token 帐户才能持有特定类型的 token。每个 token 帐户都与一个钱包地址和一个特定的 token 类型相关联。

spl-token create-account &lt;TOKEN_ADDRESS>

将 <TOKEN_ADDRESS> 替换为上一步中创建的 token 的地址。

7. 冻结权限:

允许指定的帐户冻结 token 帐户,从而阻止转账。

spl-token authorize &lt;TOKEN_MINT_ADDRESS> --freeze &lt;FREEZE_AUTHORITY>

将 <FREEZE_AUTHORITY> 替换为授权帐户的公钥。

8. 关闭权限

关闭权限允许关闭 token 帐户,并将任何剩余余额转账到指定的帐户。这对于清理未使用的帐户和恢复 SOL 很有用。

spl-token authorize &lt;TOKEN_ACCOUNT_ADDRESS> --close &lt;CLOSE_AUTHORITY_PUBLIC_KEY>

9. 关闭帐户

设置关闭权限后,你可以关闭帐户。

spl-token close &lt;TOKEN_ACCOUNT_ADDRESS> &lt;RECIPIENT_ADDRESS>

撤销和验证 SPL Token 的权限

1. 撤销铸币权限:撤销铸币权限可确保无法铸造新的 token,从而有效地限制 token 供应。

命令

spl-token authorize &lt;TOKEN_MINT_ADDRESS> --mint --disable

验证

## Verify the mint authority has been revoked
spl-token account-info $TOKEN_MINT

2. 撤销冻结权限

撤销冻结权限可防止进一步冻结或解冻 token 帐户。

命令

spl-token authorize &lt;TOKEN_MINT_ADDRESS> --freeze --disable

验证

## Verify the freeze authority has been revoked
spl-token account-info $TOKEN_MINT

3. 撤销关闭权限

撤销关闭权限可防止关闭 token 帐户,从而确保其保持打开状态。

命令

spl-token authorize &lt;TOKEN_ACCOUNT_ADDRESS> --close --disable

验证

## Verify the close authority has been revoked
spl-token account-info $USER1_TOKEN_ACCOUNT

4. 撤销转账权限

撤销转账权限可防止进一步委托转账权限,从而保护 token 帐户免受未经授权的转账。

命令

spl-token authorize &lt;TOKEN_ACCOUNT_ADDRESS> --transfer --disable

验证

## Verify the transfer authority has been revoked
spl-token account-info $USER1_TOKEN_ACCOUNT

5. 撤销铸币权限

spl-token authorize &lt;TOKEN_MINT_ADDRESS> --mint --disable

这限制了 token 的总供应量。

Token-2022

Token-2022 是 Solana 引入的升级 token 标准,旨在扩展 SPL token 的功能。它建立在 SPL 标准的基础上,通过添加高级功能来解决更复杂的使用场景。Token-2022 标准与 SPL Token 标准兼容,确保现有 token 可以在不中断的情况下采用这些新功能。

广泛的审计确保这些扩展是安全可靠的,为强大的企业解决方案铺平了道路。Token-2022 在原始 token 标准之上引入了几个新特性和改进。这些增强旨在为 token 创建者和用户提供更大的灵活性和功能。

技术

Token-2022 使用与 SPL 相同的底层区块链基础设施,但引入了新的智能合约功能来支持其高级特性。

与 Solana 的高性能区块链集成可确保 Token-2022 token 享有与 SPL token 相同的可扩展性和效率。

Token-2022 程序向 Solana 引入了 Token Extensions。

Token Extensions 的类型

有两种值得注意的 Token Extensions 类型:

1. 铸币 — 除了原始 SPL 程序之外实现。它们扩展了 token 的能力。流行的例子包括机密转账、转账费用、计息 Token、不可转账 Token 和转账Hook。

2. 帐户 — 添加到 Solana 帐户以改进与帐户相关的功能。值得注意的例子是交易备忘录和不可变的拥有者。

现在让我们看一下 Solana 上可用的两类 Token Extensions 的各种类型,我们将了解它们的功能、如何部署它们以及它们的用例。

铸币 Extensions

1. 机密转账

交易的透明性质是任何区块链的基本特性。它增强了用户对链的信任。增强安全性,并创建一个透明的数据存储。但是,有时需要隐私。机密转账允许在不披露转账金额的情况下进行交易。虽然转账的 token 以及发送者和接收者地址仍然对公众可见。交易金额只有发起人、接收者和一个可选的第三方审计员才能访问。此功能依赖于强大的密码协议。

初始化机密 Token

solana-confidential create-token
## Initialize a new confidential token
CONF_TOKEN_MINT=$(solana-confidential create-token | grep -oP '(?&lt;=Creating token ).*')
echo "Confidential Token Mint Address: $CONF_TOKEN_MINT"

生成机密密钥

solana-confidential generate-keypair

创建机密帐户

solana-confidential create-account &lt;CONF_TOKEN_MINT> &lt;CONFIDENTIAL_KEYPAIR>

铸造机密 Token

solana-confidential mint &lt;CONF_TOKEN_MINT> &lt;AMOUNT> &lt;RECIPIENT_CONF_ACCOUNT>

转账机密 Token

solana-confidential transfer &lt;CONF_TOKEN_MINT> &lt;AMOUNT> &lt;SENDER_CONF_ACCOUNT> &lt;RECIPIENT_CONF_ACCOUNT>

验证机密转账

solana-confidential account-info &lt;CONF_TOKEN_MINT> &lt;CONF_ACCOUNT>

这是一个完整的示例工作流程,用于设置、铸造、转账和验证机密 token。

## Initialize a new confidential token
CONF_TOKEN_MINT=$(solana-confidential create-token | grep -oP '(?&lt;=Creating token ).*')
echo "Confidential Token Mint Address: $CONF_TOKEN_MINT"

## Generate confidential keys for users
USER1_CONF_KEYPAIR=$(solana-confidential generate-keypair)
USER2_CONF_KEYPAIR=$(solana-confidential generate-keypair)
echo "User 1 Confidential Keypair: $USER1_CONF_KEYPAIR"
echo "User 2 Confidential Keypair: $USER2_CONF_KEYPAIR"

## Create confidential accounts for User 1 and User 2
USER1_CONF_ACCOUNT=$(solana-confidential create-account $CONF_TOKEN_MINT $USER1_CONF_KEYPAIR | grep -oP '(?&lt;=Creating account ).*')
USER2_CONF_ACCOUNT=$(solana-confidential create-account $CONF_TOKEN_MINT $USER2_CONF_KEYPAIR | grep -oP '(?&lt;=Creating account ).*')
echo "User 1 Confidential Account: $USER1_CONF_ACCOUNT"
echo "User 2 Confidential Account: $USER2_CONF_ACCOUNT"

## Mint 1000 confidential tokens to User 1
solana-confidential mint $CONF_TOKEN_MINT 1000 $USER1_CONF_ACCOUNT

## Transfer 100 confidential tokens from User 1 to User 2
solana-confidential transfer $CONF_TOKEN_MINT 100 $USER1_CONF_ACCOUNT $USER2_CONF_ACCOUNT

## Verify User 1 and User 2's confidential token balances
solana-confidential account-info $CONF_TOKEN_MINT $USER1_CONF_ACCOUNT
solana-confidential account-info $CONF_TOKEN_MINT $USER2_CONF_ACCOUNT

用例:

工资单和商家付款:一家以 USDC 支付员工工资的公司可能希望对其员工的工资保密。

机构融资和私人融资/投资:一家贸易公司可能希望对其 OTC 交易的细节保密,以保持竞争优势。

一些已经利用这些特性的著名项目包括 Paxos 的 USDP 等稳定币和 GMO Trust 的受监管稳定币。

2. 转账Hook

转账Hook可以在 Solana 上的所有协议中强制执行,而不仅仅是一个协议。转账Hook扩展在转账 token 时调用一段自定义逻辑。想要只允许列入白名单的地址持有和转账 token 的 Token 发行者。他们可以简单地维护一个列入白名单的地址列表,并在允许转账 token 之前验证地址是否已列入白名单。在 token 级别实现此自定义逻辑消除了复杂代理层的需求,否则所有利益相关者(如钱包和 DEX/市场)都必须实现这些代理层。

通过转账Hook,所有钱包和市场都固有地提供支持。转账Hook允许开发人员在转账结算之前调用程序定义的逻辑。实现非常简单,因为开发人员只需开发和部署一个实现所需接口并执行其业务逻辑的程序。然后,开发人员配置其 token 铸币以使用新程序。

使用 Rust 创建一个新的 Solana 程序。

## Create a new directory for the project
mkdir solana-transfer-hook
cd solana-transfer-hook

## Initialize a new Rust project
cargo new --lib transfer_hook
cd transfer_hook

编辑 Cargo.toml 以包含 Solana 依赖项。

[package]
name = "transfer_hook"
version = "0.1.0"
edition = "2018"

[dependencies]
solana-program = "1.9.9"

在 src/lib.rs 中创建程序逻辑。

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    pubkey::Pubkey,
};

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    let accounts_iter = &mut accounts.iter();

    let from_account = next_account_info(accounts_iter)?;
    let to_account = next_account_info(accounts_iter)?;
    let amount = next_account_info(accounts_iter)?;
    let authority_account = next_account_info(accounts_iter)?;

    msg!("Transfer Hook: From {}, To {}, Amount: {}", from_account.key, to_account.key, amount.key);

    // Add custom logic here, e.g., logging, restricting transfers, etc.
    if from_account.owner != authority_account.key {
        msg!("Transfer not authorized by the account owner.");
        return Err(solana_program::program_error::ProgramError::IllegalOwner);
    }

    // If you want to implement a fee, you could adjust the amount here
    // For example, reduce the amount by 1% as a fee:
    // let fee = amount / 100;
    // let net_amount = amount - fee;

    Ok(())
}

部署程序

## Build the program
cargo build-bpf

## Deploy the program (replace with your actual keypair and cluster URL)
solana program deploy /path/to/your/program/target/deploy/transfer_hook.so

要在 token 转账期间调用转账Hook,你需要在 token 转账交易中调用自定义程序。

use solana_program::{
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    sysvar::{rent::Rent, Sysvar},
};
use solana_sdk::signature::Signer;

pub fn create_transfer_with_hook_instruction(
    program_id: &Pubkey,
    token_program_id: &Pubkey,
    from_pubkey: &Pubkey,
    to_pubkey: &Pubkey,
    authority_pubkey: &Pubkey,
    amount: u64,
) -> Instruction {
    let accounts = vec![\
        AccountMeta::new(*from_pubkey, false),\
        AccountMeta::new(*to_pubkey, false),\
        AccountMeta::new_readonly(*authority_pubkey, true),\
        AccountMeta::new_readonly(solana_program::system_program::id(), false),\
    ];

    let data = amount.to_le_bytes();

    Instruction {
        program_id: *program_id,
        accounts,
        data: data.to_vec(),
    }
}

以下是如何将转账Hook集成到客户端应用程序中。

use solana_client::rpc_client::RpcClient;
use solana_sdk::{
    signature::{Keypair, Signer},
    transaction::Transaction,
};

fn main() {
    let client = RpcClient::new("https://api.devnet.solana.com");

    let from_keypair = Keypair::from_base58_string("...");
    let to_pubkey = Pubkey::from_str("...").unwrap();
    let authority_pubkey = Pubkey::from_str("...").unwrap();
    let program_id = Pubkey::from_str("...").unwrap();
    let token_program_id = Pubkey::from_str("...").unwrap();

    let transfer_instruction = create_transfer_with_hook_instruction(
        &program_id,
        &token_program_id,
        &from_keypair.pubkey(),
        &to_pubkey,
        &authority_pubkey,
        100,
    );

    let mut transaction = Transaction::new_with_payer(
        &[transfer_instruction],
        Some(&from_keypair.pubkey()),
    );

    let recent_blockhash = client.get_recent_blockhash().unwrap().0;
    transaction.sign(&[&from_keypair], recent_blockhash);

    let signature = client.send_and_confirm_transaction(&transaction).unwrap();

    println!("Transaction signature: {}", signature);
}

为了确保你的转账Hook按预期工作,你应该编写测试并将其部署到像 Solana 的 Devnet 这样的测试网络。

## Run tests locally
cargo test

## Deploy and test on Devnet
solana program deploy /path/to/your/program/target/deploy/transfer_hook.so --url https://api.devnet.solana.com

用例

稳定币 — 使用转账Hook,团队可以强制对所有用户或持有超过一定阈值的金额的用户进行完整的 KYC。

RWA — RWA token 只有在满足某些条件后才能转账,例如完成 KYC、确保不违反 OFAC 列表或同意服务条款。

空投 — 为了防止大部分用户在收到 token 后立即出售 token,可以对 token 进行编程,使其仅在特定时间后才允许进行有限制的转账。转账Hook可用于限制帐户可以持有的 token 数量,并限制单笔交易中可以转账或购买的 token 数量。

结构化产品 — RWA 债务参与者 Obligate 已经在 Solana 上构建了一个用于结构化产品发行的酷炫原型。他们使用转账Hook进行合规性检查,但更重要的是,他们使用自定义快照转账Hook来跟踪票息支付。该原型展示了将发行和定价时间框架从几天缩短到几毫秒,并以完全自动化和透明的方式处理整个生命周期的能力。

3. 转账费用

此 token 扩展使开发人员可以对每次转账收取费用,从而通过特许权使用费、平台费和创建者费等方式产生收入。这些费用可以自定义路由到各个利益相关者,例如质押者或 token 持有者。在之前的 token 模型中,想要收取费用的项目通常需要冻结帐户,通过第三方处理转账费用,然后解冻帐户。但是通过扩展,项目现在可以创建自动转账费用,而无需任何额外工作。由于该扩展高度可配置,因此费用可以路由到多个接收者,每次转账都有上限,按百分比收取等等。

使用 Rust 创建一个新的 Solana 程序。

## Create a new directory for the project
mkdir solana-transfer-fee
cd solana-transfer-fee

## Initialize a new Rust project
cargo new --lib transfer_fee
cd transfer_fee

编辑 Cargo.toml 以包含 Solana 依赖项。

[package]
name = "transfer_fee"
version = "0.1.0"
edition = "2018"

[dependencies]
solana-program = "1.9.9"

在 src/lib.rs 中创建程序逻辑。

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    pubkey::Pubkey,
    program::{invoke, invoke_signed},
    system_instruction,
    program_pack::{Pack, IsInitialized},
    sysvar::{rent::Rent, Sysvar},
    program_error::ProgramError,
};

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    let accounts_iter = &mut accounts.iter();

    let from_account = next_account_info(accounts_iter)?;
    let to_account = next_account_info(accounts_iter)?;
    let authority_account = next_account_info(accounts_iter)?;
    let fee_account = next_account_info(accounts_iter)?;

    let amount = instruction_data
        .get(0..8)
        .and_then(|slice| slice.try_into().ok())
        .map(u64::from_le_bytes)
        .ok_or(ProgramError::InvalidInstructionData)?;

    // Implement fee logic (e.g., 1% fee)
    let fee = amount / 100;
    let net_amount = amount - fee;

    msg!("Transfer Hook: From {}, To {}, Net Amount: {}, Fee: {}", from_account.key, to_account.key, net_amount, fee);

    // Transfer net amount to recipient
    let ix = system_instruction::transfer(&from_account.key, &to_account.key, net_amount);
    invoke(
        &ix,
        &[\
            from_account.clone(),\
            to_account.clone(),\
            authority_account.clone(),\
        ],
    )?;

    // Transfer fee to fee collector
    let fee_ix = system_instruction::transfer(&from_account.key, &fee_account.key, fee);
    invoke(
        &fee_ix,
        &[\
            from_account.clone(),\
            fee_account.clone(),\
            authority_account.clone(),\
        ],
    )?;

    Ok(())
}

编译并将程序部署到 Solana 区块链。

## Build the program
cargo build-bpf

## Deploy the program (replace with your actual keypair and cluster URL)
solana program deploy /path/to/your/program/target/deploy/transfer_fee.so

将转账费用与 SPL Token 集成。

use solana_program::{
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    sysvar::{rent::Rent, Sysvar},
};
use solana_sdk::signature::Signer;

pub fn create_transfer_with_fee_instruction(
    program_id: &Pubkey,
    from_pubkey: &Pubkey,
    to_pubkey: &Pubkey,
    authority_pubkey: &Pubkey,
    fee_pubkey: &Pubkey,
    amount: u64,
) -> Instruction {
    let accounts = vec![\
        AccountMeta::new(*from_pubkey, true),\
        AccountMeta::new(*to_pubkey, false),\
        AccountMeta::new_readonly(*authority_pubkey, true),\
        AccountMeta::new(*fee_pubkey, false),\
    ];

    let data = amount.to_le_bytes();

    Instruction {
        program_id: *program_id,
        accounts,
        data: data.to_vec(),
    }
}

集成到客户端应用程序的示例

use solana_client::rpc_client::RpcClient;
use solana_sdk::{
    signature::{Keypair, Signer},
    transaction::Transaction,
};

fn main() {
    let client = RpcClient::new("https://api.devnet.solana.com");

    let from_keypair = Keypair::from_base58_string("...");
    let to_pubkey = Pubkey::from_str("...").unwrap();
    let authority_pubkey = Pubkey::from_str("...").unwrap();
    let fee_pubkey = Pubkey::from_str("...").unwrap();
    let program_id = Pubkey::from_str("...").unwrap();

    let transfer_instruction = create_transfer_with_fee_instruction(
        &program_id,
        &from_keypair.pubkey(),
        &to_pubkey,
        &authority_pubkey,
        &fee_pubkey,
        1000,
    );

    let mut transaction = Transaction::new_with_payer(
        &[transfer_instruction],
        Some(&from_keypair.pubkey()),
    );

    let recent_blockhash = client.get_recent_blockhash().unwrap().0;
    transaction.sign(&[&from_keypair], recent_blockhash);

    let signature = client.send_and_confirm_transaction(&transaction).unwrap();

    println!("Transaction signature: {}", signature);
}

测试转账费用

## Run tests locally
cargo test

## Deploy and test on Devnet
solana program deploy /path/to/your/program/target/deploy/transfer_fee.so --url https://api.devnet.solana.com

用例:

支付 — 此功能可以为区块链上的支付公司开辟新的商业模式。例如,他们可能会收取少量费用,类似于 Visa 的商家费用,即转账费用的 1%。此外,它还允许自动征收支付税,以确保合规性。

NFT 版税 — 转账费用使 NFT 创建者可以将版税直接嵌入到 token 中,从而使版税强制执行成为可能。

基于费用的 Token 经济学 - 例如,以太坊上的 Paxos Gold (PAXG) 采用自定义合约,对每笔 PAXG 交易收取 0.02% 的费用。由于转账费用 Token Extension,可以轻松地实现此方法。

4. 元数据

具有本机链上元数据定义和存储功能为开发人员提供了前所未有的灵活性。开发人员现在可以根据需要添加、更新和删除自定义字段,从而自定义元数据以满足其项目的独特需求。通过 token extensions,此元数据随 token 一起携带,从而确保了所有应用程序之间的可移植性,从而实现无缝互操作性。

对于标准 token 铸币 — 名称、符号和 URL 可以轻松地直接添加到铸币帐户,从而大大简化了索引器和协议与你的 token 交互的过程。通过元数据扩展,模块化元数据可以本机地合并到 token 中。

为 SPL Token 创建元数据

使用 Metaplex create_metadata 命令。此命令创建一个链接到你的 SPL token 铸币地址的元数据帐户。

metaplex create_metadata --name "Token Name" --symbol "TKN" --uri "https://example.com/metadata.json" --mint-address &lt;TOKEN_MINT_ADDRESS> --keypair &lt;PATH_TO_KEYPAIR>

更新元数据

使用 Metaplex update_metadata 命令。这允许你更改名称、符号和 URI 等属性。

metaplex update_metadata --new-name "New Token Name" --new-symbol "NTKN" --new-uri "https://example.com/new_metadata.json" --mint-address &lt;TOKEN_MINT_ADDRESS> --keypair &lt;PATH_TO_KEYPAIR>

读取元数据

使用 Metaplex get_metadata 命令。

metaplex get_metadata --mint-address &lt;TOKEN_MINT_ADDRESS>

这是一个更详细的示例,包括使用 Solana 和 Metaplex 命令创建、更新和读取元数据。

## Create metadata for the token
metaplex create_metadata \
  --name "Example Token" \
  --symbol "EXM" \
  --uri "https://example.com/metadata.json" \
  --mint-address &lt;TOKEN_MINT_ADDRESS> \
  --keypair ~/.config/solana/id.json

元数据 JSON 示例

metadata.json 文件应托管在命令中提供的 URI 中。以下是此 JSON 文件可能的样子示例:

{
  "name": "Example Token",
  "symbol": "EXM",
  "description": "An example token for demonstration purposes.",
  "image": "https://example.com/image.png",
  "attributes": [\
    {\
      "trait_type": "purpose",\
      "value": "demonstration"\
    }\
  ],
  "properties": {
    "creators": [\
      {\
        "address": "YourSolanaWalletAddress",\
        "share": 100\
      }\
    ],
    "files": [\
      {\
        "uri": "https://example.com/image.png",\
        "type": "image/png"\
      }\
    ]
  }
}

在你的应用程序中集成元数据

你还可以使用 Rust 以编程方式与你的 Solana 程序中的元数据帐户进行交互。

用于读取元数据的 Rust 示例:

use solana_client::rpc_client::RpcClient;
use solana_program::{
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    system_instruction,
};
use solana_sdk::signature::Signer;
use metaplex_token_metadata::{
    instruction::create_metadata_accounts,
    state::{Metadata, Data},
};

fn main() {
    let client = RpcClient::new("https://api.devnet.solana.com");

    let payer = Keypair::from_base58_string("...");
    let mint_address = Pubkey::from_str("...").unwrap();
    let metadata_program_id = Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap();

    let metadata_account = Pubkey::create_with_seed(
        &mint_address,
        "metadata",
        &metadata_program_id,
    ).unwrap();

    let metadata = Metadata::get_metadata_account(&client, &metadata_account).unwrap();

    println!("Metadata: {:?}", metadata);
}

用例:

艺术家 — 创作者可以动态嵌入有关其艺术作品的详细信息。

供应链 — 关键产品信息(例如产地和制造日期)可以嵌入到代表产品的 token 的元数据中。

DePIN — 像 ShadowDrive 这样的 DePIN 项目可以允许元数据 URL 指向链上数据。

5. 不可转让的 Token

为了使 token 不可交易并唯一地与钱包绑定,不可转让的扩展有助于创建通常称为“Soulbound”的锁定 token。这些是被铸造到特定地址的非同质化 token,旨在无限期地保留在原始接收者手中。这些 token 作为所有权的防篡改记录,不可撤销地链接原始铸币者和接收者。

集成不可转让逻辑

要集成不可转让逻辑,你需要确保任何 token 转账操作都涉及你的自定义程序,该程序将拒绝任何转账尝试。

以下是如何使用 Solana 客户端强制执行不可转让性的示例。

use solana_client::rpc_client::RpcClient;
use solana_program::{
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    system_instruction,
};
use solana_sdk::signature::Signer;
use spl_token::{
    instruction::transfer,
    state```
use solana_client::rpc_client::RpcClient;
use solana_program::{
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    system_instruction,
};
use solana_sdk::signature::Signer;
use spl_token::{
    instruction::transfer,
    state::Account as TokenAccount,
};

fn main() {
    let client = RpcClient::new("https://api.devnet.solana.com");

    let from_keypair = Keypair::from_base58_string("...");
    let from_token_account = Pubkey::from_str("...").unwrap();
    let token_mint = Pubkey::from_str("...").unwrap();
    let program_id = Pubkey::from_str("...").unwrap();

    let token_account = client.get_account(&from_token_account).unwrap();
    let token_data = TokenAccount::unpack(&token_account.data).unwrap();

    // 创建应用利息的指令
    let interest_instruction = Instruction {
        program_id,
        accounts: vec![\
            AccountMeta::new(from_token_account, false),\
            AccountMeta::new(token_mint, false),\
            AccountMeta::new_readonly(solana_program::sysvar::clock::id(), false),\
        ],
        data: vec![],
    };

    let mut transaction = Transaction::new_with_payer(
        &[interest_instruction],
        Some(&from_keypair.pubkey()),
    );

    let recent_blockhash = client.get_recent_blockhash().unwrap().0;
    transaction.sign(&[&from_keypair], recent_blockhash);

    let signature = client.send_and_confirm_transaction(&transaction);
    match signature {
        Ok(sig) => println!("Transaction signature: {}", sig),
        Err(e) => println!("Transaction failed: {}", e),
    }
}

6. 测试生息代币

## 在本地运行测试
cargo test

## 在 Devnet 上部署和测试
solana program deploy /path/to/your/program/target/deploy/interest_bearing_token.so --url https://api.devnet.solana.com

用例:

固定收益 — 鉴于全球固定收益市场价值约为 130 万亿美元,因此这是一个重要的机会。 具有可变但全球利率的货币市场基金是一个很好的用例。

DAO 和质押 — 被质押的代币可以具有固有的收益,从而提高其价值主张。

负利率 — 类似于“以租代购”模式,即支付初始金额以确保对资产的临时所有权或使用权。 该价值每天下降 1%, 导致资金最终耗尽并失去对资产的访问权限。

7. 不可变的拥有者

不可变的拥有者扩展建立具有固定所有权的 Token Account,该所有权无法转移。 这种方法可以防止潜在的帐户挪用,确保经过验证的完整性和更高的安全性。

将权限设置为不可变

要使代币的权限不可变,需要在铸造所有初始代币后撤销铸币权限。 这将防止对权限的任何进一步更改。

## 撤销铸币权限
spl-token authorize-revoke &lt;TOKEN_MINT_ADDRESS> mint

验证不可变的拥有者

你可以通过尝试更改代币的权限来验证该权限是否不可变。 在撤销铸币权限后,任何更改权限的尝试都应失败。

## 尝试更改权限(应该失败)
spl-token authorize &lt;TOKEN_MINT_ADDRESS> &lt;NEW_AUTHORITY_PUBLIC_KEY> mint

用例:

具有不可变的拥有者和不可转让的代币可以用于 DAO 治理决策。 未来,随着区块链被更广泛地采用

8. 永久委托

在需要时收回或撤销代币。

建立一个指定的机构,能够销毁或转移任何数量的代币。 稳定币或中央银行数字货币 (CBDC) 等代币的开发者可以指定永久委托人,其有权在发生欺诈或犯罪活动时冻结帐户或删除代币。 它也可用于可撤销的会员资格。 Solana 代币程序一直具有“冻结”功能,此扩展现在也启用了“扣押”功能。

将委托设置为永久

要使代币的委托权限永久有效,你需要撤销铸币权限,然后设置委托权限。

## 撤销铸币权限
spl-token authorize-revoke &lt;TOKEN_MINT_ADDRESS> mint

## 将委托权限设置为永久
spl-token authorize-revoke &lt;TOKEN_MINT_ADDRESS> delegate

验证永久委托

## 尝试更改委托权限(应该失败)
spl-token authorize &lt;TOKEN_MINT_ADDRESS> &lt;NEW_DELEGATE_PUBLIC_KEY> delegate

9. 元数据指针

使代币创建者能够分配一个地址,该地址定义代币的官方元数据。

在 Solana 上分配一个定义代币官方元数据的地址涉及使用 Metaplex 代币元数据程序。 此过程允许你将元数据(例如名称、符号和 URI(指向链下数据的指针))附加到 SPL 代币。

为代币创建元数据

现在,使用 Metaplex CLI 为你的代币创建元数据。 元数据包括名称、符号和 URI 等字段。

以下是如何将元数据分配给你的代币:

## 定义元数据变量
NAME="Example Token"
SYMBOL="EXM"
URI="https://example.com/metadata.json"

## 为代币创建元数据
metaplex mint tokens create_metadata \
    --mint $TOKEN_MINT_ADDRESS \
    --name "$NAME" \
    --symbol "$SYMBOL" \
    --uri "$URI"

以下是元数据 JSON 文件 (metadata.json) 的示例。 该文件应托管在链下,并通过你提供的 URI 访问。

{
    "name": "Example Token",
    "symbol": "EXM",
    "description": "An example token with metadata",
    "image": "https://example.com/image.png",
    "attributes": [\
        {\
            "trait_type": "Category",\
            "value": "Utility"\
        }\
    ],
    "properties": {
        "files": [\
            {\
                "uri": "https://example.com/image.png",\
                "type": "image/png"\
            }\
        ],
        "creators": [\
            {\
                "address": "YourPublicKey",\
                "share": 100\
            }\
        ]
    }
}

使用 Metaplex CLI 创建元数据的详细步骤

初始化 Metaplex CLI:

metaplex config set cluster devnet

创建元数据账户:

metaplex create_candy_machine -k ~/.config/solana/id.json -p ./assets --price 1 -n "My Token Name" --symbol "SYMBOL" --spl-token $TOKEN_MINT_ADDRESS --metadata-url "https://example.com/metadata.json"

替换:

~/.config/solana/id.json 替换为你的 Solana 钱包密钥对文件的路径

./assets 替换为你的资源文件的路径。

"My Token Name" 替换为所需的代币名称。

"SYMBOL" 替换为所需的代币符号。

$TOKEN_MINT_ADDRESS 替换为代币铸币地址。

"https://example.com/metadata.json" 替换为你的元数据 JSON 文件的 URL。

验证元数据

metaplex show_candy_machine -k ~/.config/solana/id.json --id &lt;CANDY_MACHINE_ID>

10. 群组

借助 Token Extensions,代币可以与群组关联。 群组是可配置的,具有设置最大大小、初始大小、更新权限等的选项。

要在 Solana 上为 SPL 代币实施群组扩展,你需要创建一个自定义程序来扩展 SPL 代币程序的功能

创建自定义程序

创建一个新的 Rust 项目,并将必要的依赖项添加到 Cargo.toml 中:

[dependencies]
solana-program = "1.9.9"
spl-token = "3.2.0"

在 src/lib.rs 中实现群组扩展的逻辑:

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    pubkey::Pubkey,
    program_pack::{IsInitialized, Pack},
};
use spl_token::{
    error::TokenError,
    state::{Account, Mint},
};

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    // 在此处实现群组扩展逻辑
    Ok(())
}

定义群组操作

在 process_instruction 函数中实现所需的群组操作,例如在多个帐户之间转移代币或同时将代币铸造到多个帐户。

编译和部署程序

使用 Solana BPF 工具链编译程序并将其部署到 Solana 区块链。

cargo build-bpf
solana program deploy /path/to/your/program/target/deploy/your_program_name.so

调用群组扩展

调用自定义程序以一次对多个代币帐户执行群组操作。

用法示例:以下是如何使用群组扩展在多个帐户之间转移代币:

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    pubkey::Pubkey,
    program_pack::{IsInitialized, Pack},
};
use spl_token::{
    error::TokenError,
    state::{Account, Mint},
};

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    // 解析指令数据以确定群组操作
    match instruction_data[0] {
        // 示例:在多个帐户之间转移代币
        0 => {
            // 提取帐户信息
            let accounts_iter = &mut accounts.iter();
            let from_account = next_account_info(accounts_iter)?;
            let to_accounts = accounts_iter.take(10); // 限制为 10 个帐户
            let amount = instruction_data[1..9].to_owned().into();

            // 将代币从 `from_account` 转移到每个 `to_account`
            for to_account in to_accounts {
                spl_token::instruction::transfer(program_id, from_account, to_account, amount)?;
            }

            Ok(())
        }
        // 根据需要添加更多的群组操作
        _ => Err(TokenError::InvalidInstruction.into()),
    }
}

11. 群组指针

允许代币创建者指定一个群组帐户,该帐户提供有关铸币的详细信息。

创建客户端

以下是在 Rust 中调用群组转移的示例。

创建一个新的 Rust 项目:

cargo new --bin solana-group-pointer-client
cd solana-group-pointer-client
[dependencies]
solana-client = "1.9.9"
solana-program = "1.9.9"
spl-token = "3.2.0"
borsh = "0.9.1"

在 Cargo.toml 中添加依赖项

实现客户端

在 src/main.rs 中创建客户端的主要逻辑:

use borsh::{BorshSerialize};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    transaction::Transaction,
    system_instruction,
    instruction::Instruction,
};
use solana_program::system_program;

##[derive(BorshSerialize, Debug)]
pub struct GroupInstruction {
    pub operation: u8,
    pub amount: u64,
    pub group_size: u8,
}

fn main() {
    let client = RpcClient::new("https://api.devnet.solana.com");

    let payer = Keypair::from_base58_string("your-payer-private-key");
    let program_id = Pubkey::from_str("your-program-id").unwrap();
    let mint_pubkey = Pubkey::from_str("your-mint-public-key").unwrap();
    let from_account_pubkey = Pubkey::from_str("from-account-public-key").unwrap();
    let to_account_pubkeys = vec![\
        Pubkey::from_str("to-account-1-public-key").unwrap(),\
        Pubkey::from_str("to-account-2-public-key").unwrap(),\
    ];

    let group_instruction = GroupInstruction {
        operation: 0,
        amount: 100,
        group_size: to_account_pubkeys.len() as u8,
    };

    let instruction_data = group_instruction.try_to_vec().unwrap();
    let mut accounts = vec![\
        system_instruction::create_account(\
            &payer.pubkey(),\
            &from_account_pubkey,\
            1,\
            165,\
            &program_id,\
        )\
    ];

    for to_account_pubkey in &to_account_pubkeys {
        accounts.push(system_instruction::create_account(
            &payer.pubkey(),
            &to_account_pubkey,
            1,
            165,
            &program_id,
        ));
    }

    let instruction = Instruction {
        program_id,
        accounts: accounts
            .iter()
            .map(|account| solana_sdk::instruction::AccountMeta {
                pubkey: account.pubkey,
                is_signer: account.is_signer,
                is_writable: true,
            })
            .collect(),
        data: instruction_data,
    };

    let mut transaction = Transaction::new_with_payer(
        &[instruction],
        Some(&payer.pubkey()),
    );

    let recent_blockhash = client.get_recent_blockhash().unwrap().0;
    transaction.sign(&[&payer], recent_blockhash);

    let signature = client.send_and_confirm_transaction(&transaction);
    match signature {
        Ok(sig) => println!("Transaction signature: {}", sig),
        Err(e) => println!("Transaction failed: {}", e),
    }
}

Account Token Extensions

1. 转移时需要 Memo

— 强制在每次代币转账时都包含一个 memo,从而有助于法规遵从、报告和增强审计跟踪。 特别是,对于付款对帐和开票需求非常有用。
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    transaction::Transaction,
    instruction::Instruction,
};
use spl_memo::build_memo;
use spl_token::instruction::transfer;

fn main() {
    let client = RpcClient::new("https://api.devnet.solana.com");

    let payer = Keypair::from_base58_string("your-payer-private-key");
    let from_account_pubkey = Pubkey::from_str("from-account-public-key").unwrap();
    let to_account_pubkey = Pubkey::from_str("to-account-public-key").unwrap();
    let mint_pubkey = Pubkey::from_str("mint-public-key").unwrap();
    let authority_pubkey = Pubkey::from_str("authority-public-key").unwrap();

    let memo = "This is a required memo";
    let amount: u64 = 100;

    let memo_ix = build_memo(memo.as_bytes(), &[]);
    let transfer_ix = transfer(
        &spl_token::id(),
        &from_account_pubkey,
        &to_account_pubkey,
        &authority_pubkey,
        &[],
        amount,
    ).unwrap();

    let mut transaction = Transaction::new_with_payer(
        &[memo_ix, transfer_ix],
        Some(&payer.pubkey()),
    );

    let recent_blockhash = client.get_recent_blockhash().unwrap().0;
    transaction.sign(&[&payer], recent_blockhash);

    let signature = client.send_and_confirm_transaction(&transaction);
    match signature {
        Ok(sig) => println!("Transaction signature: {}", sig),
        Err(e) => println!("Transaction failed: {}", e),
    }
}

2. 默认帐户状态

— 所有新创建的 Token Account 最初都被冻结,需要用户以特定方式与项目交互才能激活(解冻)帐户/代币。

use borsh::{BorshSerialize};
use solana_client::rpc_client::RpcClient;
use solana_program::{
    pubkey::Pubkey,
    system_instruction,
    instruction::Instruction,
};
use solana_sdk::{
    signature::{Keypair, Signer},
    transaction::Transaction,
};

##[derive(BorshSerialize, Debug)]
pub struct InitAccountInstruction {
    pub initial_balance: u64,
    pub authority: Pubkey,
}

fn main() {
    let client = RpcClient::new("https://api.devnet.solana.com");

    let payer = Keypair::from_base58_string("your-payer-private-key");
    let mint_pubkey = Pubkey::from_str("mint-public-key").unwrap();
    let token_account_pubkey = Pubkey::from_str("token-account-public-key").unwrap();
    let rent_account_pubkey = Pubkey::from_str("rent-public-key").unwrap();
    let authority_pubkey = Pubkey::from_str("authority-public-key").unwrap();
    let program_id = Pubkey::from_str("your-program-id").unwrap();

    let init_instruction = InitAccountInstruction {
        initial_balance: 100,
        authority: authority_pubkey,
    };

    let instruction_data = init_instruction.try_to_vec().unwrap();
    let instruction = Instruction {
        program_id,
        accounts: vec![\
            solana_sdk::instruction::AccountMeta::new(mint_pubkey, false),\
            solana_sdk::instruction::AccountMeta::new(token_account_pubkey, false),\
            solana_sdk::instruction::AccountMeta::new_readonly(rent_account_pubkey, false),\
            solana_sdk::instruction::AccountMeta::new_readonly(authority_pubkey, true),\
        ],
        data: instruction_data,
    };

    let mut transaction = Transaction::new_with_payer(
        &[instruction],
        Some(&payer.pubkey()),
    );

    let recent_blockhash = client.get_recent_blockhash().unwrap().0;
    transaction.sign(&[&payer], recent_blockhash);

    let signature = client.send_and_confirm_transaction(&transaction);
    match signature {
        Ok(sig) => println!("Transaction signature: {}", sig),
        Err(e) => println!("Transaction failed: {}", e),
    }
}

3. CPI Guard

通过禁止跨程序调用期间的某些活动,限制其他程序与你的代币交互的方式。
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
    sysvar::{self, SysvarId},
};
use spl_token::instruction::transfer;

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    // 定义允许的 CPI 调用者
    let allowed_cpi_callers = vec![\
        Pubkey::from_str("AllowedProgram1PublicKey").unwrap(),\
        Pubkey::from_str("AllowedProgram2PublicKey").unwrap(),\
    ];

3     // 检查调用者是否为允许的程序
    let caller_program_id = sysvar::instructions::load_instruction_at_checked(0, accounts)?
        .program_id;

    if !allowed_cpi_callers.contains(&caller_program_id) {
        msg!("Unauthorized CPI caller: {:?}", caller_program_id);
        return Err(ProgramError::IllegalOwner);
    }

    // 继续进行指令处理(例如,代币转账)
    let accounts_iter = &mut accounts.iter();
    let from_account = next_account_info(accounts_iter)?;
    let to_account = next_account_info(accounts_iter)?;
    let authority_account = next_account_info(accounts_iter)?;

    let amount = instruction_data
        .get(0..8)
        .and_then(|slice| slice.try_into().ok())
        .map(u64::from_le_bytes)
        .ok_or(ProgramError::InvalidInstructionData)?;

    msg!("Transferring {} tokens", amount);

    transfer(
        &spl_token::id(),
        from_account.key,
        to_account.key,
        authority_account.key,
        &[],
        amount,
    )?;

    Ok(())
}

4. 重新分配

允许在创建帐户后激活某些扩展。 “重新分配”功能允许所有者重新分配其 Token Account 空间以适应其他扩展。
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
    system_instruction,
    sysvar::{rent::Rent, Sysvar},
    program::invoke_signed,
    program_pack::Pack,
};

entrypoint!(process_instruction);

##[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct ReallocateInstruction {
    pub new_size: u64,
}

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    let instruction = ReallocateInstruction::try_from_slice(instruction_data)
        .map_err(|_| ProgramError::InvalidInstructionData)?;

    let accounts_iter = &mut accounts.iter();
    let account_to_resize = next_account_info(accounts_iter)?;
    let payer_account = next_account_info(accounts_iter)?;
    let system_program_account = next_account_info(accounts_iter)?;

    // 确保要调整的帐户由程序拥有
    if account_to_resize.owner != program_id {
        msg!("Account being resized is not owned by the program");
        return Err(ProgramError::IllegalOwner);
    }

    let rent = Rent::get()?;
    let current_lamports = account_to_resize.lamports();
    let new_size = instruction.new_size as usize;

    // 计算新的租金豁免金额
    let required_lamports = rent.minimum_balance(new_size);
    let additional_lamports = required_lamports.saturating_sub(current_lamports);

    // 重新分配帐户
    account_to_resize.realloc(new_size, false)?;

    // 如果需要,转移额外的 lamports
    if additional_lamports > 0 {
        invoke_signed(
            &system_instruction::transfer(
                payer_account.key,
                account_to_resize.key,
                additional_lamports,
            ),
            &[\
                payer_account.clone(),\
                account_to_resize.clone(),\
                system_program_account.clone(),\
            ],
            &[],
        )?;
    }

    msg!("Account reallocated to new size: {}", new_size);

    Ok(())
}

Solana 叙事的 Token Extensions 用例。

凭借如此广泛的可用代币扩展,用例列表非常广泛且不断增长。 让我们看几个例子,看看你的团队如何利用。

游戏

不可转让的 Token Extension 可用于创建唯一的代币,以 UUID 形式标识玩家。 这些代币还可用于构建不可转让的、特定于每个人的游戏中个人资料卡。 转移Hook可用于确保每个收到代币的人都是真正的玩家,而不是机器人。 二级市场上的每次交易都可以收取转让费,以帮助资助游戏的进一步开发。 如果玩家违反规则,可能会被冻结。 游戏中货币的保密转移可以确保这些交易的隐私,允许玩家购买、出售或交易资产,而无需向他人透露交易金额。

DAO

具有不可变的拥有者和不可转让的代币可以用于 DAO 治理决策。 随着区块链被更广泛地采用,需要在透明治理的情况下,链上可能会发生现实世界的决策活动。 对于资金,可以使用保密转移来对资助金额保密。 普通大众将知道谁资助了 DAO,但不知道花费的金额。

DeFi

代表现实世界资产 (RWA) 的代币可以组合扩展来创建赚取利息、需要有关其来源的元数据并需要通过转移限制进行 KYC 的代币。 DeFi 项目可以使用转让费来实施基于费用的代币经济学和收入分成。

稳定币

Token extensions 允许稳定币开发者在 Solana 上构建完全合规的稳定币。 通过使用转移Hook,团队可以在所有用户或持有超过一定数量的用户上强制执行完整的 KYC。 团队可以使用永久委托(建立一个定义的机构,可以燃烧或转移任何数量的代币)来冻结帐户或在发生欺诈或犯罪活动时从帐户中删除代币。

支付

由于其高性能、可扩展性和低成本,Solana 是支付解决方案的领先区块链。 事实上,Visa 在最近的深入研究中表示,“Solana 独特的技术优势,包括高吞吐量、低成本和高弹性,创造了一个可扩展的区块链平台,为支付提供了引人注目的价值主张。” 创建支付解决方案的开发人员可以使用扩展来强制执行可接受的实践,并帮助他们的产品走向主流,例如在支付中包含自动税,同时仍然对支付金额保密。 通过添加所需的 memo,团队可以确保转移得到记录、跟踪和审计,从而简化付款对帐。

在 Solana 上使用 Token Extensions 的替代方案

在不使用命令行界面 (CLI) 的情况下添加 token extensions 通常涉及通过替代方法(例如使用 SDK、库或自定义脚本)与区块链进行交互。

以下是添加 token extensions 的其他一些方法:

  1. Web 界面:开发 Web 界面或应用程序,这些界面或应用程序通过 Solana 节点提供的 API 与区块链进行交互。 这些界面可以提供用户友好的方式来执行与代币相关的操作,而无需依赖 CLI。
  2. SDK 集成:将 Solana SDK 集成到你现有的应用程序中,以编程方式与区块链进行交互。 SDK 通常提供创建、管理和与代币交互的方法和函数,从而更容易将 token extensions 纳入你的项目中。
  3. 自定义脚本:编写自定义脚本或应用程序,使用 RPC(远程过程调用)调用与 Solana 区块链进行交互。 这些脚本可以自动执行与代币相关的任务,并灵活地管理 token extensions。
  4. 第三方工具和服务:探索通过图形用户界面或 API 提供代币管理功能的第三方工具和服务。 这些平台可能会提供超出 CLI 可用范围的其他功能和集成。
  5. 智能合约:在 Solana 上开发智能合约,以扩展代币功能,使其超出标准功能。 智能合约可以向代币引入自定义逻辑和行为,从而实现更高级的功能,例如质押、治理或自动交易。
  6. 区块链浏览器:利用支持代币管理功能的区块链浏览器。 一些区块链浏览器提供基于 Web 的界面,用于与 Solana 区块链上的代币进行交互,允许用户查看代币余额、转移代币以及执行其他操作,而无需使用 CLI。
  7. 钱包集成:将 token extensions 集成到加密货币钱包或钱包应用程序中。 然后,用户可以直接通过钱包界面管理他们的代币,从而无需手动 CLI 命令。

通过利用这些替代方法,你无需仅仅依赖 CLI 即可将 token extensions 添加到 Solana 区块链,从而为代币管理提供更多的可访问性和灵活性。

Solana 区块链的最佳实践

在 Solana 上处理代币时,你需要遵守特定于 Solana 区块链的最佳实践。

以下是一些指南:

1. 使用 Solana 代币标准:Solana 有自己的代币标准,如 SPL(Solana 程序库)代币。 利用这些标准进行代币创建,因为它们提供了一个定义良好且安全的框架。

2. 安全密钥生成:安全生成加密密钥,用于代币发行和管理。 使用已建立的库并遵循密钥生成的最佳实践,以防止密钥泄露。

3. 程序代码审计:如果你要部署自定义代币程序,请确保进行彻底的代码审查和审计,以识别和缓解任何安全漏洞。

4. 程序完整性验证:在部署之前验证代币程序的完整性,以确保它没有被篡改或泄露。

5. 智能合约安全性:如果使用智能合约,请遵循智能合约安全性的最佳实践,以防止常见的漏洞,如重入攻击或溢出漏洞。

6. 安全钱包管理:实施安全钱包管理实践,包括使用硬件钱包或安全存储解决方案来保护与代币发行和管理相关的私钥。

7. 监控代币活动:定期监控 Solana 区块链上的代币活动,以检测任何可疑行为或未经授权的交易。

8. 代币元数据安全性:确保代币元数据(如符号、名称和小数位数)已准确配置并安全管理,以防止虚假陈述或操纵。

9. 网络安全:参与安全且维护良好的网络基础设施,以最大限度地降低网络攻击或中断的风险。

通过遵循这些最佳实践,你可以在 Solana 区块链上以安全可靠的方式创建和执行代币,从而确保你的资产和交易的安全。

  • 原文链接: medium.com/@tobs.x/token...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
tobs.x
tobs.x
https://medium.com/@tobs.x