3

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);

1 Answer 1

3

Educated guess based on what your instruction is doing: the error is probably coming from the token::transfer. Everything else would probably be getting an Anchor error message.

0x1 is 1 in hex

You can see token errors in their source code here: https://github.com/solana-labs/solana-program-library/blob/master/token/program/src/error.rs#L13

Notice they're numbered (in comments) from 0. The second error (index 1) is here:

/// Insufficient funds for the operation requested.
#[error("Insufficient funds")]
InsufficientFunds,

So that'd be my first guess - the account you're sending from doesn't have a sufficient balance. Maybe try using the SPL token library to check the balance in your test is what you expect?

1
  • 1
    Thank you man there was a problem in the token::transfer function, you helped us a lot!
    – zazzz
    Aug 10, 2022 at 10:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.