SOL合约部署调用与销毁
常见术语
- SPL: Solana Program Library
- PDAs: Program Derived Addresses
- CPI: Cross-Program Invocation
BPF is a highly efficient bytecode execution environment initially developed for network packet filtering in the Linux kernel. Solana leverages BPF as the execution environment for its smart contracts
开发环境
参考 https://solana.com/developers/guides/getstarted/setup-local-development
由于 devnet 会定时删数据滚服,然后 chain_id+=1 所以用 devnet 好处是数据少 rpc 节点负担小 延迟低
solana config set --url https://api.devnet.solana.com
然后就是 devnet 基础设施多点(explorer区块浏览器也能连localhost),主要是我可怜的笔记本内存太小了不想运行个sol全节点
Anchor framework 应该指的是 sol 的智能合约开发框架
就像eth不用remix这样web的IDE,sol也不用solana playground否则像我当初remix学solidity都是一键傻瓜部署运行结果连部署和调用的底层原理一点都不懂
创建项目
代码在 https://solana.com/developers/guides/getstarted/hello-world-in-your-browser
cargo new --lib firstsol
cd firstsol
echo -e '[toolchain]\nchannel = "1.76.0"\n' > rust-toolchain.toml
cargo add solana-program
[lib]
crate-type = ["cdylib", "lib"]
sol NFT 合约代码可以参考 https://github.com/the-web3/nft-share/blob/main/SolNft/programs/SolNft/src/lib.rs
部署合约
cargo build-bpf 默认就是 release 编译 由于 rent-exempt reserve
机制存在,智能合约so文件体积越小存储费用越低
$ solana program deploy target/deploy/firstsol.so
Program Id: 6jL67XKqEVWPBZEmMT8AuhTP4zJefpPs48BmV3JLxncR
好贵,收了我 0.14 SOL 的 GAS
$ solana program show --programs
Program Id | Slot | Authority | Balance
6jL67XKqEVWPBZEmMT8AuhTP4zJefpPs48BmV3JLxncR | 312032887 | 6YA5ZxLRNuYEg44xbkLPtgbu5dBQdEftcWS31kpyba4f | 0.1350588 SOL
Authority 列应该就是合约发布者也就是我的钱包地址, 跟ETH的POS类似 一个区块中会有多个Slot 312032887 类似于 slot_id
ts调用合约
并不能像 aptos/sui 那样用命令行工具调用(claude3.5 API会骗你说可以),用 ts/rust 调用会方便点
import {
Connection,
PublicKey,
Keypair,
Transaction,
sendAndConfirmTransaction,
TransactionInstruction
} from '@solana/web3.js';
import * as fs from 'fs';
(async () => {
const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
// Read the keypair from the file
const keypairPath = `${process.env.HOME}/.config/solana/id.json`;
const keypairData = JSON.parse(fs.readFileSync(keypairPath, 'utf8'));
const payer = Keypair.fromSecretKey(new Uint8Array(keypairData));
const programId = new PublicKey('6jL67XKqEVWPBZEmMT8AuhTP4zJefpPs48BmV3JLxncR');
// Create an instruction to call your program
const instruction = new TransactionInstruction({
keys: [{pubkey: payer.publicKey, isSigner: true, isWritable: true}],
programId,
data: Buffer.alloc(0)
});
// Create a transaction
const transaction = new Transaction().add(instruction);
// Sign and Send the transaction
const signature = await sendAndConfirmTransaction(
connection,
transaction,
[payer]
);
console.log('Transaction sent with signature:', signature);
})();
w@w:~/solana$ solana confirm -v 3nFhxCp6hvHCLFmVd3YgkpbrsS9jxBF7Jwy3MNvcSBFG25KZeeNL3xasQEK9msGh3cjy6uJMTUGR2jYX9TZmeXyR
RPC URL: https://api.devnet.solana.com
Default Signer Path: /home/w/.config/solana/id.json
Commitment: confirmed
Unknown Program (6jL67XKqEVWPBZEmMT8AuhTP4zJefpPs48BmV3JLxncR): Unknown Instruction
> Program logged: "Hello, world!"
> Program consumed: 340 of 200000 compute units
> Program returned success
或者用 solana cli
solana logs | grep "6jL67XKqEVWPBZEmMT8AuhTP4zJefpPs48BmV3JLxncR invoke" -A3
rs调用合约
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
commitment_config::CommitmentConfig,
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
signature::Signer,
transaction::Transaction,
};
fn main() {
dotenv::dotenv().unwrap();
let connection = RpcClient::new_with_commitment(
"https://api.devnet.solana.com".to_string(),
CommitmentConfig::confirmed(),
);
let payer = solana_client_example::keypair();
let program_id: Pubkey = std::env::var("program_id").unwrap().parse().unwrap();
let instruction = Instruction {
program_id,
accounts: vec![AccountMeta::new(payer.pubkey(), true)],
data: Vec::new(),
};
let transaction = Transaction::new_signed_with_payer(
&[instruction],
Some(&payer.pubkey()),
&[&payer],
connection.get_latest_blockhash().unwrap(),
);
match connection.send_and_confirm_transaction(&transaction) {
Ok(signature) => println!("Transaction sent with signature: {}", signature),
Err(err) => eprintln!("Error sending transaction: {:?}", err),
}
}
合约销毁退存储费
同一个合约项目种重复deploy的话不会创建新的program_id
solana program close