Making a simple vestment app:
pub struct MakeVestment<'info> {
#[account(
mut,
seeds = [b"ledger", vested_tokens_mint.key().as_ref(), beneficiary.key().as_ref()],
bump
)]
pub ledger: Account<'info, Ledger>,
#[account(
init,
payer = vestor,
space = 8 + size_of::<Vestment>(),
seeds = [b"vestment", ledger.key().as_ref(), &((ledger.vestment_count + 1) as u64).to_le_bytes()],
bump
)]
pub vestment: Account<'info, Vestment>, //parses from bits to vestment struct
#[account(mut)]
pub vestor: Signer<'info>, //=AccountInfo but has to sign it too
#[account(mut)]
pub vestor_token_account: Account<'info, TokenAccount>,
#[account()]
/// CHECK: TODO
pub beneficiary: AccountInfo<'info>,
#[account(
init,
payer = vestor,
seeds = [b"vested-tokens", vestment.key().as_ref()],
bump,
token::mint = vested_tokens_mint,
token::authority = vested_tokens,
)]
pub vested_tokens: Account<'info, TokenAccount>,
pub vested_tokens_mint: Account<'info, Mint>, // mint
pub token_program: Program<'info, Token>,
pub rent: Sysvar<'info, Rent>,
///CHECK: Validated here.
#[account(address=system_program::ID)] //so its valid
pub system_program: AccountInfo<'info>, //accountInfo gives an accounts in BITS
}
pub fn make_vestment(
ctx: Context<MakeVestment>,
amount: u64,
cliff: Option<i64>,
period: i64,
num_of_periods: u32,
) -> Result<()> {
let vestment: &mut Account<Vestment> = &mut ctx.accounts.vestment;
let vestor: &Signer = &ctx.accounts.vestor;
let vesting_start_at = Clock::get().unwrap().unix_timestamp;
let ledger = &mut ctx.accounts.ledger;
ledger.vestment_count= ledger.vestment_count.checked_add(1).unwrap();
if amount <=0 {
return Err(ErrorCode::InvalidAmount.into());
}
if let Some(c) = cliff {
if c<=0 {
return Err(ErrorCode::InvalidCliff.into());
}
}
if period<=0 {
return Err(ErrorCode::InvalidPeriod.into());
}
if num_of_periods <=0 {
return Err(ErrorCode::InvalidNumberOfPeriods.into());
}
vestment.vestor = vestor.key();
vestment.vesting_start_at = vesting_start_at;
vestment.amount_vested = amount*1000000000;
vestment.amount_claimed = 0;
vestment.period_length = period;
vestment.num_of_periods = num_of_periods;
vestment.beneficiary = ctx.accounts.beneficiary.key();
vestment.last_claim_period = None;
vestment.amount_per_period = vestment.amount_vested.checked_div(vestment.num_of_periods as u64).unwrap();
vestment.is_active = true;
if let Some(c) = cliff {
vestment.cliff_end_at = vestment.vesting_start_at.checked_add(c);
vestment.vesting_end_at = vestment.cliff_end_at.unwrap()
.checked_add((num_of_periods as i64).checked_mul(period).unwrap())
.unwrap();
} else {
vestment.cliff_end_at = None;
vestment.vesting_end_at = vesting_start_at
.checked_add((num_of_periods as i64).checked_mul(period).unwrap())
.unwrap();
}
token::transfer(
CpiContext::new(
ctx.accounts.token_program.to_account_info(),
token::Transfer {
from: ctx.accounts.vestor_token_account.to_account_info(),
to: ctx.accounts.vested_tokens.to_account_info(),
authority: ctx.accounts.vestor.to_account_info(),
},
),
amount*1000000000 as u64,
)?;
Ok(())
}
The problem is at the end of this:
let ledgercina;
try {
ledgercina = await program.account.ledger.fetch(ledger.toString());
console.log(ledgercina);
} catch (error) {
const tx0 = await program.rpc.makeLedger({
accounts: {
ledger: ledger,
vestor: vestor.publicKey,
vestorTokenAccount: vestorTokenAccount,
beneficiary: beneficiary.publicKey,
vestedTokensMint: tokenMint,
tokenProgram: TOKEN_PROGRAM_ID,
rent: SYSVAR_RENT_PUBKEY,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [vestor],
});
await connection.confirmTransaction(tx0);
ledgercina = await program.account.ledger.fetch(ledger.toString());
console.log(ledgercina);
}
let ledgerVCount = ledgercina.vestmentCount;
console.log(ledgerVCount);
const [oldVestment] = await PublicKey.findProgramAddress(
[
Buffer.from("vestment"),
ledger.toBuffer(),
new anchor.BN(ledgerVCount).toBuffer("le", 8),
],
program.programId
);
console.log(oldVestment);
let oldVestmentcina;
let newVestment = oldVestment;
try {
oldVestmentcina = await program.account.vestment.fetch(oldVestment);
console.log(oldVestmentcina);
if (oldVestmentcina.isActive == true) {
console.log("A vestment is already active");
return;
}
ledgerVCount++;
[newVestment] = await PublicKey.findProgramAddress(
[
Buffer.from("vestment"),
ledger.toBuffer(),
new anchor.BN(ledgerVCount).toBuffer("le", 8),
],
program.programId
);
} catch (error) {
[newVestment] = await PublicKey.findProgramAddress(
[
Buffer.from("vestment"),
ledger.toBuffer(),
new anchor.BN(1).toBuffer("le", 8),
],
program.programId
);
}
console.log("New vestment:");
console.log(newVestment);
const [vestedTokens] = await PublicKey.findProgramAddress(
[Buffer.from("vested-tokens"), newVestment.toBuffer()],
program.programId
);
var cliff = 10;
var numberOfPeriods = 4;
var period = 5;
var amount = 10;
//var vestmentTimeinSeconds = Math.floor(Date.now() / 1000);
console.log("Sve ok do sad");
const tx3 = await program.rpc.makeVestment(
new anchor.BN(amount),
null,
new anchor.BN(period),
numberOfPeriods,
{
accounts: {
ledger: ledger,
vestment: newVestment,
vestor: vestor.publicKey,
vestorTokenAccount: vestorTokenAccount,
beneficiary: beneficiary.publicKey,
vestedTokens: vestedTokens,
vestedTokensMint: tokenMint,
tokenProgram: TOKEN_PROGRAM_ID,
rent: SYSVAR_RENT_PUBKEY,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [vestor],
}
);
When calling the makeVestment function there is a problem that is in the name of this post:
Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x1
at Connection.sendEncodedTransaction (node_modules/@solana/web3.js/src/connection.ts:4465:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Connection.sendRawTransaction (node_modules/@solana/web3.js/src/connection.ts:4424:20)
at sendAndConfirmRawTransaction (node_modules/@project-serum/anchor/src/provider.ts:284:21)
at AnchorProvider.sendAndConfirm (node_modules/@project-serum/anchor/src/provider.ts:144:14)
at Object.rpc [as makeVestment] (node_modules/@project-serum/anchor/src/program/namespace/rpc.ts:29:16)
Tokens and balance:
const tx1 = await connection.requestAirdrop(
vestor.publicKey,
LAMPORTS_PER_SOL
);
const tx2 = await connection.requestAirdrop(
beneficiary.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(tx1);
await connection.confirmTransaction(tx2);
const tokenMint = await createMint(
connection,
vestor,
vestor.publicKey,
null,
0
);
const vestorTokenAccount = await createAssociatedTokenAccount(
connection,
vestor,
tokenMint,
vestor.publicKey
);
const beneficiaryTokenAccount = await createAssociatedTokenAccount(
connection,
beneficiary,
tokenMint,
beneficiary.publicKey
);
const txMint = await mintTo(
connection,
vestor,
tokenMint,
vestorTokenAccount,
vestor,
1000
);
await connection.confirmTransaction(txMint);