I am creating a vesting schedule on solana using anchor and rust. I wanna initialize a vesting schedule for the user. When initializing only the user needs to sign, but for some reason my test demands the signature of the vesting schedule.
Here’s my code
state.rs
//! All account states for the project exist here
use anchor_lang::prelude::*;
#[account]
//Structure of a vesting schedule
pub struct VestingScheduleState {
//user
pub user:Pubkey,
//total duration of the vesting in seconds
pub duration:u64,
//type of vesting
pub vest_type: VestType,
//SOL or SPL
pub token: TokenType,
//total amount
pub total_amount: u64,
//starting time
pub start_time: u64,
//To track how much amount has been released
pub released_amount: u64,
//address recieving the tokens
pub recipient: Pubkey,
//this is where the user will deposit their tokens when creating a new schedule
pub escrow_wallet: Pubkey,
//OPTIONAL FEATURE:
pub cliff_period: Option<u64> ,
//token mint address
pub token_mint: Option<Pubkey>,
//decimals of the SPL token
pub decimals: Option<u16>
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub enum VestType {
///type of installments
//yearly(not reccomended?)
Yearly,
//every month
Monthly,
//every two weeks
Fortnightly,
//every week
Weekly,
//every day
Daily,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub enum TokenType {
SOL,
SPL
}
account.rs
#[derive(Accounts)]
pub struct InitializeVestingSchedule<'info> {
#[account(init, payer = user, space = 8 + std::mem::size_of::<VestingScheduleState>())]
pub vesting_schedule: Account<'info, VestingScheduleState>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
instructions.rs
pub fn initialize_vesting_schedule(
ctx:Context<InitializeVestingSchedule>,
duration: u64,
vest_type: VestType,
token: TokenType,
total_amount: u64,
start_time: u64,
recipient: Pubkey,
escrow_wallet: Pubkey,
cliff_period: Option<u64>,
token_mint: Option<Pubkey>,
decimals: Option<u16>
) -> Result<()> {
let schedule = &mut ctx.accounts.vesting_schedule;
schedule.user = ctx.accounts.user.key();
schedule.duration = duration;
schedule.vest_type = vest_type;
schedule.token = token.clone();
schedule.total_amount = total_amount;
schedule.start_time = start_time;
schedule.released_amount = 0;
schedule.recipient = recipient;
schedule.escrow_wallet = escrow_wallet;
schedule.cliff_period = cliff_period;
schedule.token_mint = token_mint;
schedule.decimals = decimals;
msg!("Schedule details confirmed.");
Ok(())
}
And this is the test i wrote
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { VestingModel } from "../target/types/vesting_model";
import { assert } from "chai";
describe("vesting-model", () => {
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.VestingModel as Program<VestingModel>;
it("It initializes a vesting schedule", async () => {
const user = anchor.web3.Keypair.generate();
const escrow_wallet = anchor.web3.Keypair.generate();
// Airdrop some SOL to the user
await program.provider.connection.requestAirdrop(
user.publicKey,
10 * anchor.web3.LAMPORTS_PER_SOL
);
const [vestingSchedule] =
await anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("vesting-schedule")],
program.programId
);
try {
// Create vesting schedule
const tx = await program.methods
.createVestingSchedule(
new anchor.BN(86400 * 30), // duration
{ monthly: {} }, // vest_type
{ sol: {} }, // token
new anchor.BN(100000000), // total_amount
new anchor.BN(Date.now()), // start_time
user.publicKey, // recipient
escrow_wallet.publicKey,
null,
null,
null
)
.accounts({
vestingSchedule,
user: user.publicKey,
})
.signers([user])
.rpc();
console.log("Transaction signature:", tx);
// Assertions
} catch (err) {
console.error("Transaction error:", err);
}
});
});
Now for accounts I know systemProgram must be present, but for some reason it just gives me an error whenever i try to. So for now i’ve removed it cuz i read somewhere that Anchor can automatically add systemProgram as the account
This is the error i get
vesting-model
Transaction error: Error: Signature verification failed.
Missing signature for public key [`FDJsHJECSwzednimrEy4h9cjHMF12iPF45BdL4v98sa`].
at Transaction.serialize (/home/aizen/solana/vesting-model/node_modules/@solana/web3.js/src/transaction/legacy.ts:828:15)
at AnchorProvider.sendAndConfirm (/home/aizen/solana/vesting-model/node_modules/@coral-xyz/anchor/src/provider.ts:160:22)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at MethodsBuilder.rpc [as _rpcFn] (/home/aizen/solana/vesting-model/node_modules/@coral-xyz/anchor/src/program/namespace/rpc.ts:29:16)
✔ It initializes a vesting schedule (211ms)
1 passing (214ms)
Done in 1.55s.
I want user to be the only signer. Vesting-schedule shouldnt have to sign the transaction