3

I'm using anchor framework to write and deploy programs in solana blockchain. I run solana-test-validator and then use anchor deploy to deploy my simple hello-world program. It gives me the programs id.

root@localhost:~# solana program show 52icfgD6ZytaFsHhATENiXSfPouuhj3S8rjzcv8jT1gd

Program Id: 52icfgD6ZytaFsHhATENiXSfPouuhj3S8rjzcv8jT1gd
Owner: BPFLoaderUpgradeab1e11111111111111111111111
ProgramData Address: ACAthK9VGs9JjMSSsLXf8DJhVpimHiDCvSqozRFgiaCb
Authority: 11111111111111111111111111111111
Last Deployed In Slot: 0
Data Length: 183816 (0x2ce08) bytes
Balance: 1.28056344 SOL

Then I try to send SOL to ACAthK9VGs9JjMSSsLXf8DJhVpimHiDCvSqozRFgiaCb in order to invoke my hello-world program. But after checking the transaction logs, I can't find the hello-world message I printed using msg macro. How can I invoke my deployed program using solana cli?

1 Answer 1

6

Sadly you can not interact with custom programs from the CLI.

Sending sol to your program address will do nothing than adding more sol to the account. You can also close your program account to get the sol back.

But its quite easy using java script.

When you use anchor it will create you a program object. The types will be in your target folder. These you can use to call instruction on your program like so:

const txHash = await pg.program.methods.hello().rpc();
console.log(txHash);

Here is a nice web tool called solana playground where you can try it out: https://beta.solpg.io/tutorials/tiny-adventure

Here is a complete vanilla ts examples on how to interact with the tiny adventure example from playground. You can run it by using

npx ts-node yourFile.ts

First create your self a local keypair like so:

solana-keygen grind --starts-with dev:1

get some sol:

solana airdrop 1 -k devYourKaypair.json

and replace it in the following script:

import { Connection, clusterApiUrl, Keypair, PublicKey } from "@solana/web3.js";
import { IDL, TinyAdventure } from "./tiny_adventure";
import { AnchorProvider, Idl, Program, setProvider, web3 } from "@project-serum/anchor";
import * as fs from 'fs';
import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";

const programId = new PublicKey("BX66sQ2JAWM5D5xS5GcrZh1TULDdNZSXcS4LDUns2fMG")

const decodedKey = new Uint8Array(
  JSON.parse(
    fs.readFileSync("ReplaceWithYourKey.json").toString())
  );

let keyPair = Keypair.fromSecretKey(decodedKey);

// Create a placeholder wallet to set up AnchorProvider
const wallet = new NodeWallet(keyPair)
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

// Create an Anchor provider
const provider = new AnchorProvider(connection, wallet, {})

// Set the provider as the default provider
setProvider(provider)

const program = new Program(
  IDL as Idl,
  programId
) as unknown as Program<TinyAdventure>

const initializeAndMoveRight = async () => {

  const [globalLevel1GameDataAccount, bump] =
    await web3.PublicKey.findProgramAddress(
      [Buffer.from("level1", "utf8")],
      programId
    );

  let txHash;
  let gameDateAccount;
  try {
    gameDateAccount = await program.account.gameDataAccount.fetch(
      globalLevel1GameDataAccount
    );
  } catch {
    // Check if the account is already initialized, other wise initilalize it
    txHash = await program.methods
      .initialize()
      .accounts({
        newGameDataAccount: globalLevel1GameDataAccount,
        signer: keyPair.publicKey,
        systemProgram: web3.SystemProgram.programId,
      })
      .signers([keyPair])
      .rpc();

    console.log(`Use 'solana confirm -v ${txHash}' to see the logs`);
    await connection.confirmTransaction(txHash);
    console.log("A journey begins...");
    console.log("o........");
  }

  // Here you can play around now, move left and right
  txHash = await program.methods
    //.moveLeft()
    .moveRight()
    .accounts({
      gameDataAccount: globalLevel1GameDataAccount,
    })
    .signers([keyPair])
    .rpc();
  console.log(`Use 'solana confirm -v ${txHash}' to see the logs`);
  await connection.confirmTransaction(txHash);

  gameDateAccount = await program.account.gameDataAccount.fetch(
    globalLevel1GameDataAccount
  );

  console.log("Player position is:", gameDateAccount.playerPosition.toString());

  switch (gameDateAccount.playerPosition) {
    case 0:
      console.log("A journey begins...");
      console.log("o........");
      break;
    case 1:
      console.log("....o....");
      break;
    case 2:
      console.log("......o..");
      break;
    case 3:
      console.log(".........\\o/");
      break;
  }
}

initializeAndMoveRight();

And here are the types of the program that are created when you build an anchor program. Put these next to your ts file

export type TinyAdventure = {
  "version": "0.1.0",
  "name": "tiny_adventure",
  "instructions": [
    {
      "name": "initialize",
      "accounts": [
        {
          "name": "newGameDataAccount",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "signer",
          "isMut": true,
          "isSigner": true
        },
        {
          "name": "systemProgram",
          "isMut": false,
          "isSigner": false
        }
      ],
      "args": []
    },
    {
      "name": "moveLeft",
      "accounts": [
        {
          "name": "gameDataAccount",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": []
    },
    {
      "name": "moveRight",
      "accounts": [
        {
          "name": "gameDataAccount",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": []
    }
  ],
  "accounts": [
    {
      "name": "gameDataAccount",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "playerPosition",
            "type": "u8"
          }
        ]
      }
    }
  ]
};

export const IDL: TinyAdventure = {
  "version": "0.1.0",
  "name": "tiny_adventure",
  "instructions": [
    {
      "name": "initialize",
      "accounts": [
        {
          "name": "newGameDataAccount",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "signer",
          "isMut": true,
          "isSigner": true
        },
        {
          "name": "systemProgram",
          "isMut": false,
          "isSigner": false
        }
      ],
      "args": []
    },
    {
      "name": "moveLeft",
      "accounts": [
        {
          "name": "gameDataAccount",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": []
    },
    {
      "name": "moveRight",
      "accounts": [
        {
          "name": "gameDataAccount",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": []
    }
  ],
  "accounts": [
    {
      "name": "gameDataAccount",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "playerPosition",
            "type": "u8"
          }
        ]
      }
    }
  ]
};
5
  • Thanks for your answer! Can you show me a self-contained javascript code that can perform this operation? The example you provided and example in the solpg.io are both depended on other stuff (importing some modules, creating connection to cluster, etc) which I'm not aware of. I want to see a complete example. Commented Jan 10 at 13:22
  • 1
    Got you, makes sense playground can be confusing. I updated the answer and wrote you a little example for local ts file. Hope that helps
    – Jonas H.
    Commented Jan 10 at 14:35
  • Thanks you, can I use the typescript code generated by the anchor to invoke my program instructions? In fact I just want the easiest way as possible to call my to invoke my program I've written using anchor, does using that tests code make it easier to invoke my program? Commented Jan 10 at 15:18
  • When you build your anchor program it will generate your types in the target folder. So you can just replace them to yours in the ts file and interact with your program.
    – Jonas H.
    Commented Jan 10 at 15:29
  • Then all you need is probably this part if you only have a hello world: txHash = await program.methods .helloWorld() .signers([keyPair]) .rpc(); console.log(Use 'solana confirm -v ${txHash}' to see the logs); await connection.confirmTransaction(txHash);
    – Jonas H.
    Commented Jan 10 at 16:12

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.