0

I have a Rust Anchor program for swapping SPL Tokens. It has three methods: Make, refund and take. Also I have a Next.js frontend app. I want to integrate this Rust Anchor program with Next.js app. For the first time, I want to integrate make method of the program.

Here is the make.rs file.

use anchor_lang::prelude::*;

use anchor_spl::{
    associated_token::AssociatedToken,
    token_interface::{transfer_checked, Mint, TokenAccount, TokenInterface, TransferChecked},
};

use crate::Escrow;

#[derive(Accounts)]
#[instruction(seed: u64)]
pub struct Make<'info> {
    #[account(mut)]
    pub maker: Signer<'info>,
    #[account(
        mint::token_program = token_program
    )]
    pub mint_a: InterfaceAccount<'info, Mint>,
    #[account(
        mint::token_program = token_program
    )]
    pub mint_b: InterfaceAccount<'info, Mint>,
    #[account(
        mut,
        associated_token::mint = mint_a,
        associated_token::authority = maker,
        associated_token::token_program = token_program
    )]
    pub maker_ata_a: InterfaceAccount<'info, TokenAccount>,
    #[account(
        init,
        payer = maker,
        space = 8 + Escrow::INIT_SPACE,
        seeds = [b"escrow", maker.key().as_ref(), seed.to_le_bytes().as_ref()],
        bump
    )]
    pub escrow: Account<'info, Escrow>,
    #[account(
        init,
        payer = maker,
        associated_token::mint = mint_a,
        associated_token::authority = escrow,
        associated_token::token_program = token_program
    )]
    pub vault: InterfaceAccount<'info, TokenAccount>,
    pub associated_token_program: Program<'info, AssociatedToken>,
    pub token_program: Interface<'info, TokenInterface>,
    pub system_program: Program<'info, System>,
}

impl<'info> Make<'info> {
    pub fn save_escrow(&mut self, seed: u64, receive: u64, bumps: &MakeBumps) -> Result<()> {
        self.escrow.set_inner(Escrow {
            seed,
            maker: self.maker.key(),
            mint_a: self.mint_a.key(),
            mint_b: self.mint_b.key(),
            receive,
            bump: bumps.escrow,
        });
        Ok(())
    }

    pub fn deposit(&mut self, deposit: u64) -> Result<()> {
        let transfer_accounts = TransferChecked {
            from: self.maker_ata_a.to_account_info(),
            mint: self.mint_a.to_account_info(),
            to: self.vault.to_account_info(),
            authority: self.maker.to_account_info(),
        };

        let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), transfer_accounts);

        transfer_checked(cpi_ctx, deposit, self.mint_a.decimals)
    }
}

In lib.rs file make() method is implemented like that.

use anchor_lang::prelude::*;

pub mod contexts;
use contexts::*;

pub mod state;
pub use state::*;

declare_id!("avfosQBePj8eH7CSzbEenD5kCk4DEnNpg3if6dCdPrc");

#[program]
pub mod anchor_escrow {
    use super::*;

    pub fn make(ctx: Context<Make>, seed: u64, deposit: u64, receive: u64) -> Result<()> {
        ctx.accounts.deposit(deposit)?;
        ctx.accounts.save_escrow(seed, receive, &ctx.bumps)
    }
...

In frontend part, I tried to implement integrating this method like that:

import Modal from '@/components/Common/Modal'
import { modalStore } from '@/hooks/useStore';
import getFormattedDateTime from '@/hooks/useCurrentDate'
import React, { useState, useEffect } from 'react'
import redstone from "redstone-api";
//import { createListing } from '@/services/ApiService';
import { AnchorWallet, useWallet } from '@solana/wallet-adapter-react';
import idl from "@/target/idl/anchor_escrow.json";
import { AnchorEscrow } from '@/target/types/anchor_escrow';
import * as anchor from "@coral-xyz/anchor";
import { clusterApiUrl, Connection, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
import { randomBytes } from 'crypto';
import { getAssociatedTokenAddress, getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";



const CreateListing = () => {
  const modalKey = 'createListing';
  const { toggleModal } = modalStore();

  const [solToUSD, setSolToUSD] = useState(0.0);
  const [solToETH, setSolToETH] = useState(0.0);
  const wallet = useWallet();
  const [amount, setAmount] = useState(0);
  const [mintAddress, setMintAddress] = useState("");

  const fetchSolToUSD = async () => {
    const price = await redstone.getPrice("SOL");
    setSolToUSD(price.value);
  }

  const fetchSolToETH = async () => {
    const solPrice = await redstone.getPrice("SOL");
    const ethPrice = await redstone.getPrice("ETH");

    const solToEth = solPrice.value / ethPrice.value;

    setSolToETH(solToEth);
  }

  const handleClose = () => {
    toggleModal(modalKey);
  }

  const handleMake = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const idlJson = idl as anchor.Idl;
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
    const provider = new anchor.AnchorProvider(connection, wallet as AnchorWallet);
    const program = new anchor.Program<AnchorEscrow>(JSON.parse(JSON.stringify(idlJson)), provider);
    const tokenProgram = TOKEN_2022_PROGRAM_ID;

    if (!wallet?.publicKey) {
      throw new Error("Wallet public key is null");
    }

    const seed = new anchor.BN(randomBytes(8));
    const maker = wallet.publicKey;
    const mintA = new PublicKey(mintAddress);
    const mintB = new PublicKey(mintAddress);
    const escrow = PublicKey.findProgramAddressSync(
      [Buffer.from("escrow"), maker.toBuffer(), seed],
      program.programId
    )[0];

    const makerAtaA = await getAssociatedTokenAddress(
      mintA,
      maker
    );
    const vault = getAssociatedTokenAddressSync(mintA, escrow, true);

    try {
      const tx = await program.methods
            .make(seed, new anchor.BN(amount * LAMPORTS_PER_SOL), new anchor.BN(amount * LAMPORTS_PER_SOL))
            .accounts(
              {
                maker, 
                mintA, 
                mintB,
                makerAtaA: makerAtaA,
                vault,
                tokenProgram: tokenProgram
              }    
            )
            .rpc();
      console.log(tx);
    }
    catch (err) {
      console.error(err);
    }
  }

  useEffect(() => {
    fetchSolToUSD();
    fetchSolToETH();
  }, [])

  return (
    <Modal>
      <div className="w-[577px] flex-col rounded-3xl bg-zinc-100 p-10 text-lg text-black">
        <div className="rounded-2xl bg-neutral-800 px-5 py-2 text-white">
          <div className="flex flex-row justify-between">
            <div className="">{solToUSD !== 0.0 ? `1 SOL = ${solToUSD.toFixed(3)} USD` : 'Loading...'}</div>
            <div>{getFormattedDateTime()}</div>
          </div>
          <div className="flex flex-row justify-between">
            <div>{solToETH !== 0.0 ? `1 SOL = ${solToETH.toFixed(3)} ETH` : 'Loading...'}</div>
            <div>{getFormattedDateTime()}</div>
          </div>
        </div>
        <div className="mt-8 grid grid-cols-2">
          <div className="rounded-bl-3xl rounded-tl-3xl border border-blue-600 bg-blue-600 py-1 text-center text-white">
            Buy SOL
          </div>
          <div className="rounded-br-3xl rounded-tr-3xl border-2 border-blue-600 bg-white py-1 text-center text-blue-600">
            Sell SOL
          </div>
        </div>
        <form onSubmit={handleMake} className="flex flex-col">
          <select
            className="mt-8 rounded-3xl border border-zinc-300 bg-white text-neutral-500"
            name="paymentMethod"
            defaultValue={'DEFAULT'}
          >
            <option hidden disabled value="DEFAULT">
              Payment Method
            </option>
            <option value="creditCard">Credit Card</option>
            <option value="bankCard">Bank Card</option>
            <option value="paypal">Paypal</option>
            <option value="applePay">Apple Pay</option>
          </select>
          <select
            className="mt-8 rounded-3xl border border-zinc-300 bg-white text-neutral-500"
            name="country"
            defaultValue={'DEFAULT'}
          >
            <option hidden disabled value="DEFAULT">
              Country
            </option>
            <option value="tr">Turkey</option>
            <option value="us">United States</option>
            <option value="uk">United Kindom</option>
            <option value="de">Germany</option>
          </select>
          <select
            className="mt-8 rounded-3xl border border-zinc-300 bg-white text-neutral-500"
            name="country"
            defaultValue={'DEFAULT'}
            onChange={(e) => setMintAddress(e.target.value)}
          >
            <option hidden disabled value="DEFAULT">
              Token
            </option>
            <option id='USDC' value="Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr">USDC</option>
            <option id='TET' value="HY6uvCfBQhKANRxBcYLBK7aUva8mT7mLP2SjrLLmipza">Tether</option>
          </select>
          <input
            className="mt-8 rounded-3xl border border-zinc-300 bg-white text-neutral-500"
            type="text"
            placeholder="Wallet Address"
            value={String(wallet.publicKey)}
            readOnly
          />
          <div className="relative mt-8">
            <input
              className="w-full rounded-full border-zinc-300 bg-white text-neutral-500 px-5 py-3 backdrop-blur-sm"
              placeholder="Amount"
              type="number"
              onChange={(e) => setAmount(Number(e.target.value))}
            />
            <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
              <span className="rounded-full bg-green-400 px-4 py-1 font-bold text-black">
                SOL
              </span>
            </div>
          </div>
          <label className="text-sm opacity-30 ml-8 mt-2">Minimum: 10 SOL</label>
          <div className="relative mt-5">
            <input
              className="w-full rounded-full border-zinc-300 bg-white text-neutral-500 px-5 py-3 backdrop-blur-sm"
              placeholder="Price"
            />
            <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
              <span className="rounded-full bg-green-400 px-4 py-1 font-bold text-black">
                USD
              </span>
            </div>
          </div>
          <label className="text-sm opacity-30 ml-8 mt-2">Minimum: 10 USD</label>
          {/*<div className="mt-7 ml-4 flex flex-row gap-5">
            <div className="flexCenter group rounded-[10px]">
              <input
                type="checkbox"
                className="h-6 w-6 cursor-pointer appearance-none rounded-[10px] bg-teal-400 text-teal-400 focus:ring-teal-100"
              />
            </div>
            <span className="text-lg font-medium text-neutral-500">
              Will the offer be accepted automatically?
            </span>
          </div>*/}
          <div className="flex justify-center text-white gap-4 mt-7">
            <button type="reset" onClick={handleClose} className="p-2 w-56 rounded-full bg-gray-600">Cancel</button>
            <button type="submit" className="p-2 w-56 rounded-full bg-blue-600">Save Listing</button>
          </div>
        </form>
      </div>
    </Modal>
  )
}

export default CreateListing

However, when I submit the form, I got the error from console:

transactionLogs
: 
Array(11)
0
: 
"Program ComputeBudget111111111111111111111111111111 invoke [1]"
1
: 
"Program ComputeBudget111111111111111111111111111111 success"
2
: 
"Program ComputeBudget111111111111111111111111111111 invoke [1]"
3
: 
"Program ComputeBudget111111111111111111111111111111 success"
4
: 
"Program avfosQBePj8eH7CSzbEenD5kCk4DEnNpg3if6dCdPrc invoke [1]"
5
: 
"Program log: Instruction: Make"
6
: 
"Program 11111111111111111111111111111111 invoke [2]"
7
: 
"Program 11111111111111111111111111111111 success"
8
: 
"Instruction references an unknown account FeBFCyJ26WxmN61bnXB2CyxFaUV2PzGwvqerCJcT5sC4"
9
: 
"Program avfosQBePj8eH7CSzbEenD5kCk4DEnNpg3if6dCdPrc consumed 20882 of 199700 compute units"
10
: 
"Program avfosQBePj8eH7CSzbEenD5kCk4DEnNpg3if6dCdPrc failed: An account required by the instruction is missing"

Could you please help me to solve this problem?

0

Your Answer

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