solanasolana-web3jsanchor-solana

Set the feePayer as the one who pays for the creation of an account - Anchor Solana


in any solana transaction there is a predefined feePayer who will pay for the transaction fee.

In my mind, this feePayer, would pay also for the creation of an account, instead, if not specified, in the same transaction, you can have a wallet that pays for the transaction fee and a wallet that pays for the creation of an account.

I have the following code:

#[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,
}

When I call the function SendTweet a Tweet account is created and the author of the tweet pays both for the transaction fee and the transfer of lamports for the rent exempt account creation (that is the tweet itself).

Now, in my front end code, to generate the transaction I added a new wallet and set it as feePayer. In this case, everything works, but the feePayer only pay the transaction fee and the author pay for the account creation. How can I set the feePayer also as the ones that pays for creating the account, leaving the first wallet as the author of the tweet?

I tried the following

#[derive(Accounts)]
pub struct SendTweet<'info> {
    #[account(init, payer = fee_payer, space = Tweet::LEN)]
    pub tweet: Account<'info, Tweet>,
    #[account()]
    pub author: Signer<'info>,
    #[account(mut)]
    pub payer: Signer<'info>,
    #[account(address = system_program::ID)]
    pub system_program: AccountInfo<'info>,
}

But it just says to me that does not found the fee_payer in the scope.


Solution

  • You're very close! In the first part, you have the author specified as the payer:

    #[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>,
    }
    

    And in the second, you try to specify a separate payer:

    #[derive(Accounts)]
    pub struct SendTweet<'info> {
        #[account(init, payer = fee_payer, space = Tweet::LEN)]
        pub tweet: Account<'info, Tweet>,
        #[account()]
        pub author: Signer<'info>,
        #[account(mut)]
        pub payer: Signer<'info>,
        #[account(address = system_program::ID)]
        pub system_program: AccountInfo<'info>,
    }
    

    However, you've specified fee_payer instead of payer, which is the wrong variable name, so you just need to change this to:

    #[derive(Accounts)]
    pub struct SendTweet<'info> {
        #[account(init, payer = fee_payer, space = Tweet::LEN)]
        pub tweet: Account<'info, Tweet>,
        #[account()]
        pub author: Signer<'info>,
        #[account(mut)]
        pub fee_payer: Signer<'info>,
        #[account(address = system_program::ID)]
        pub system_program: AccountInfo<'info>,
    }