Аирдроп Соланы на конкретную учетную запись
Я хотел бы отправить соль в конкретную учетную запись , чтобы мой смарт-контракт запускал якорный тест. Всякий раз, когда я запускаю свой тест, я сталкиваюсь с ошибкой
Error: Account BdFchxtKbEaWtsbuFX2nbKyZCjhz5LN8vyPukQzJQrME has insufficient funds for spend (1.30250136 SOL) + fee (0.000945 SOL) There was a problem deploying: Output { status: ExitStatus(ExitStatus(256)), stdout: "", stderr: "" }.
Ошибка не требует пояснений, но как мне отправить токены на эту конкретную учетную запись, я могу запустить
solana airdrop 5
но затем он пересылает его на другую учетную запись GgRbD2AdibdAtBrQMJJJEooco9gKt48Sd98Gn7vZQ1nJK.
Я даже пытался перевести токены с одной учетной записи на другую, используя
solana transfer BdFchxtKbEaWtsbuFX2nbKyZCjhz5LN8vyPukQzJQrME 5 --allow-unfunded-recipient
но транзакция просто зависла.
Ниже мой смарт-контракт в Rust с использованием Anchor:
use anchor_lang::prelude::*;
use anchor_lang::solana_program::system_program;
declare_id!("BNDCEb5uXCuWDxJW9BGmbfvR1JBMAKckfhYrEKW2Bv1W");
#[program]
pub mod solana_twitter {
use super::*;
pub fn send_tweet(ctx: Context<SendTweet>, topic: String, content: String) -> ProgramResult {
let tweet: &mut Account<Tweet> = &mut ctx.accounts.tweet;
let author: &Signer = &ctx.accounts.author;
let clock: Clock = Clock::get().unwrap();
if topic.chars().count() > 50 {
return Err(ErrorCode::TopicTooLong.into())
}
if content.chars().count() > 280 {
return Err(ErrorCode::ContentTooLong.into())
}
tweet.author = *author.key;
tweet.timestamp = clock.unix_timestamp;
tweet.topic = topic;
tweet.content = content;
Ok(())
}
}
#[derive(Accounts)]
pub struct SendTweet<'info> {
#[account(init, payer = author, space = Tweet::LEN)]
pub tweet: Account<'info, Tweet>,
#[account(mut)]
pub author: Signer<'info>,
#[account(address = system_program::ID)]
pub system_program: AccountInfo<'info>,
}
#[account]
pub struct Tweet {
pub author: Pubkey,
pub timestamp: i64,
pub topic: String,
pub content: String,
}
#[error]
pub enum ErrorCode {
#[msg("The provided topic should be 50 characters long maximum.")]
TopicTooLong,
#[msg("The provided content should be 280 characters long maximum.")]
ContentTooLong,
}
И ниже мой тест в Typescript:
import * as anchor from '@project-serum/anchor';
import { Program } from '@project-serum/anchor';
import { SolanaTwitter } from '../target/types/solana_twitter';
import * as assert from "assert";
import * as bs58 from "bs58";
describe('solana-twitter', () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.Provider.env());
const program = anchor.workspace.SolanaTwitter as Program<SolanaTwitter>;
it('can send a new tweet', async () => {
// Call the "SendTweet" instruction.
const tweet = anchor.web3.Keypair.generate();
await program.rpc.sendTweet('veganism', 'Hummus, am I right?', {
accounts: {
tweet: tweet.publicKey,
author: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [tweet],
});
// Fetch the account details of the created tweet.
const tweetAccount = await program.account.tweet.fetch(tweet.publicKey);
// Ensure it has the right data.
assert.equal(tweetAccount.author.toBase58(), program.provider.wallet.publicKey.toBase58());
assert.equal(tweetAccount.topic, 'veganism');
assert.equal(tweetAccount.content, 'Hummus, am I right?');
assert.ok(tweetAccount.timestamp);
});
it('can send a new tweet without a topic', async () => {
// Call the "SendTweet" instruction.
const tweet = anchor.web3.Keypair.generate();
await program.rpc.sendTweet('', 'gm', {
accounts: {
tweet: tweet.publicKey,
author: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [tweet],
});
// Fetch the account details of the created tweet.
const tweetAccount = await program.account.tweet.fetch(tweet.publicKey);
// Ensure it has the right data.
assert.equal(tweetAccount.author.toBase58(), program.provider.wallet.publicKey.toBase58());
assert.equal(tweetAccount.topic, '');
assert.equal(tweetAccount.content, 'gm');
assert.ok(tweetAccount.timestamp);
});
it('can send a new tweet from a different author', async () => {
// Generate another user and airdrop them some SOL.
const otherUser = anchor.web3.Keypair.generate();
const signature = await program.provider.connection.requestAirdrop(otherUser.publicKey, 1000000000);
await program.provider.connection.confirmTransaction(signature);
// Call the "SendTweet" instruction on behalf of this other user.
const tweet = anchor.web3.Keypair.generate();
await program.rpc.sendTweet('veganism', 'Yay Tofu!', {
accounts: {
tweet: tweet.publicKey,
author: otherUser.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [otherUser, tweet],
});
// Fetch the account details of the created tweet.
const tweetAccount = await program.account.tweet.fetch(tweet.publicKey);
// Ensure it has the right data.
assert.equal(tweetAccount.author.toBase58(), otherUser.publicKey.toBase58());
assert.equal(tweetAccount.topic, 'veganism');
assert.equal(tweetAccount.content, 'Yay Tofu!');
assert.ok(tweetAccount.timestamp);
});
it('cannot provide a topic with more than 50 characters', async () => {
try {
const tweet = anchor.web3.Keypair.generate();
const topicWith51Chars = 'x'.repeat(51);
await program.rpc.sendTweet(topicWith51Chars, 'Hummus, am I right?', {
accounts: {
tweet: tweet.publicKey,
author: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [tweet],
});
} catch (error) {
assert.equal(error.msg, 'The provided topic should be 50 characters long maximum.');
return;
}
assert.fail('The instruction should have failed with a 51-character topic.');
});
it('cannot provide a content with more than 280 characters', async () => {
try {
const tweet = anchor.web3.Keypair.generate();
const contentWith281Chars = 'x'.repeat(281);
await program.rpc.sendTweet('veganism', contentWith281Chars, {
accounts: {
tweet: tweet.publicKey,
author: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [tweet],
});
} catch (error) {
assert.equal(error.msg, 'The provided content should be 280 characters long maximum.');
return;
}
assert.fail('The instruction should have failed with a 281-character content.');
});
it('can fetch all tweets', async () => {
const tweetAccounts = await program.account.tweet.all();
assert.equal(tweetAccounts.length, 3);
});
it('can filter tweets by author', async () => {
const authorPublicKey = program.provider.wallet.publicKey
const tweetAccounts = await program.account.tweet.all([
{
memcmp: {
offset: 8, // Discriminator.
bytes: authorPublicKey.toBase58(),
}
}
]);
assert.equal(tweetAccounts.length, 2);
assert.ok(tweetAccounts.every(tweetAccount => {
return tweetAccount.account.author.toBase58() === authorPublicKey.toBase58()
}))
});
it('can filter tweets by topics', async () => {
const tweetAccounts = await program.account.tweet.all([
{
memcmp: {
offset: 8 + // Discriminator.
32 + // Author public key.
8 + // Timestamp.
4, // Topic string prefix.
bytes: bs58.encode(Buffer.from('veganism')),
}
}
]);
assert.equal(tweetAccounts.length, 2);
assert.ok(tweetAccounts.every(tweetAccount => {
return tweetAccount.account.topic === 'veganism'
}))
});
});
3 ответа
прежде всего, попробуйте убедиться, что раздел провайдера вашего anchor.toml настроен на тестовую сеть, как это
[provider]
cluster = "testnet"
wallet = "/home/yourname/.config/solana/id.json"
также используйте эту команду для установки кластера для тестовой сети
solana config set --url https://api.testnet.solana.com
проверьте активную учетную запись в вашем работающем узле solana с помощью
solana address
он должен показать открытый ключ активной учетной записи вашего работающего узла
также проверьте баланс счета с помощью
solana balance
и если у вас недостаточно sol для запуска теста или развертывания (после теста), вы можете сбросить sol, запустив
solana airdrop 1
суть в том, чтобы раздавать по 1 солу за раз (несколько раз)
теперь вы можете снова запустить тест привязки (после сборки привязки)
Для запуска тестов Anchor:
const user1KP = anchor.web3.Keypair.generate();
let token_airdrop = await provider.connection.requestAirdrop(user1KP.publicKey,
10 * LAMPORTS_PER_SOL);
const latestBlockHash = await provider.connection.getLatestBlockhash();
await provider.connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: token_airdrop,
});
Вы должны указать URL-адрес при раздаче. Я думаю макс ты можешь аирдроп 2
solana airdrop 2 2QdQZvax3uzxRWc58PR4weAX4e1AZb3c9Wfn5NtzK7Sb --url devnet
Если это зависает или дает сбой, это связано с тем, что сервер solana devnet очень часто выходит из строя. Посетите этот https://api.devnet.solana.com/
и нажмите на
What's the status of this server?
если сервер не работает, вы увидите сообщение об ошибке
если не видишь
200 Ok
сообщение