Skip to content

Commit bb7a577

Browse files
committed
Add hello world to program-examples
1 parent a3b87a4 commit bb7a577

File tree

8 files changed

+186
-0
lines changed

8 files changed

+186
-0
lines changed

basics/hello-solana/move/Move.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "hello"
3+
version = "1.0.0"
4+
5+
[addresses]
6+
hello = "0xba31"
7+
276 KB
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"program_id": "DozgQiYtGbdyniV2T74xMdmjZJvYDzoRFFqw7UR5MwPK",
3+
"accounts": [
4+
{
5+
"key": "524HMdYYBy6TAn4dK5vCcjiTmT2sxV6Xoue5EXrz22Ca",
6+
"owner": "BPFLoaderUpgradeab1e11111111111111111111111",
7+
"is_signer": false,
8+
"is_writable": true,
9+
"lamports": 1000,
10+
"data": [0, 0, 0, 3]
11+
}
12+
],
13+
"instruction_data": [
14+
11, 0, 0, 0, 0, 0, 0, 0,
15+
104, 101, 108, 108, 111, 95, 95, 109, 97, 105, 110]
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"scripts": {
3+
"test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts",
4+
"build-and-test": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./tests/fixtures && pnpm test",
5+
"build": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./program/target/so",
6+
"deploy": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/deploy.ts"
7+
},
8+
"dependencies": {
9+
"@solana/web3.js": "^1.47.3"
10+
},
11+
"devDependencies": {
12+
"@types/bn.js": "^5.1.0",
13+
"@types/chai": "^4.3.1",
14+
"@types/mocha": "^9.1.1",
15+
"chai": "^4.3.4",
16+
"mocha": "^9.0.3",
17+
"solana-bankrun": "^0.3.0",
18+
"ts-mocha": "^10.0.0",
19+
"typescript": "^4.3.5"
20+
}
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module 0x10::debug {
2+
native public fun print<T>(x: &T);
3+
}
4+
5+
module hello::hello {
6+
use 0x10::debug;
7+
use 0x1::string;
8+
9+
public entry fun main() : u64 {
10+
let rv = 0;
11+
let s = string::utf8(b"Hello Solana");
12+
debug::print(&s);
13+
rv
14+
}
15+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Deploy a solana program by execing a shell.
2+
// Returns stdout when the deploy was successful.
3+
export async function deployProgramShell(programPath: string) {
4+
const util = require('util');
5+
const exec = util.promisify(require('child_process').exec);
6+
try {
7+
const { stdout, stderr } = await exec(`solana program deploy ${programPath}`);
8+
if (stderr) {
9+
return stderr;
10+
}
11+
return stdout;
12+
} catch (e) {
13+
console.error(e);
14+
return e;
15+
}
16+
}
17+
18+
export function parseProgramID(programIdLog: string) : string {
19+
// The string should of of the following form, else it is an error.
20+
// Program Id: 5K4yQ8KW2CKsBVRUw2193GMnkKBKXDm6sdXnYY1cB4Hy
21+
programIdLog = programIdLog.trim();
22+
let templateString : string = 'Program Id: 5K4yQ8KW2CKsBVRUw2193GMnkKBKXDm6sdXnYY1cB4Hy';
23+
let logLength = templateString.length;
24+
if (programIdLog.length != logLength) {
25+
console.log(`Different lenghts. Expected: ${logLength} vs. ${programIdLog.length}`);
26+
return null;
27+
}
28+
if (!programIdLog.startsWith('Program Id:')){
29+
console.log('program does not starts with.');
30+
return null;
31+
}
32+
const programId = programIdLog.substring('Program Id: '.length);
33+
return programId;
34+
}
35+
36+
async function main() {
37+
const programPath = 'bin/hello_solana_move_program.so';
38+
const programIdLog = await deployProgramShell(programPath);
39+
const programId = parseProgramID(programIdLog);
40+
if (programId) {
41+
console.log('Program deployed with', programId);
42+
return 0;
43+
}
44+
return -1;
45+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { describe, test } from 'node:test';
2+
import { assert } from 'chai';
3+
import {deployProgramShell, parseProgramID} from './deploy';
4+
5+
import {
6+
Connection,
7+
Keypair,
8+
PublicKey,
9+
sendAndConfirmTransaction,
10+
Transaction,
11+
TransactionInstruction,
12+
} from '@solana/web3.js';
13+
14+
function createKeypairFromFile(path: string): Keypair {
15+
return Keypair.fromSecretKey(
16+
Buffer.from(JSON.parse(require('fs').readFileSync(path, "utf-8")))
17+
)
18+
};
19+
20+
function getInstructionData(path: string): Buffer {
21+
// instruction_data (See: sui/external-crates/move/solana/move-mv-llvm-compiler/docs/Entrypoint.md)
22+
let j = JSON.parse(require('fs').readFileSync(path, "utf-8"));
23+
return j['instruction_data'];
24+
}
25+
26+
async function deployProgram(programPath: string) : Promise<string> {
27+
const programIdLog = await deployProgramShell(programPath);
28+
const programId = await parseProgramID(programIdLog);
29+
if (programId) {
30+
console.log('Program deployed with', programId);
31+
return programId;
32+
}
33+
console.log('Program could not be deployed');
34+
return null;
35+
}
36+
37+
describe("hello-solana", async () => {
38+
// Loading these from local files for development
39+
const connection = new Connection(`http://localhost:8899`, 'confirmed');
40+
const payer = createKeypairFromFile(require('os').homedir() + '/.config/solana/id.json');
41+
// PublicKey of the deployed program.
42+
const programPath = 'bin/hello_solana_move_program.so';
43+
const programIdStr = await deployProgram(programPath);
44+
const programId = new PublicKey(programIdStr);
45+
const instructionData = getInstructionData('bin/input.json');
46+
47+
it("Say hello!", async () => {
48+
// Set up transaction instructions first.
49+
let ix = new TransactionInstruction({
50+
keys: [
51+
{pubkey: payer.publicKey, isSigner: true, isWritable: true}
52+
],
53+
programId,
54+
data: instructionData,
55+
});
56+
57+
// Send the transaction over RPC
58+
let signature = await sendAndConfirmTransaction(
59+
connection,
60+
new Transaction().add(ix), // Add our instruction (you can add more than one)
61+
[payer]
62+
);
63+
64+
let transaction = await connection.getTransaction(signature, {commitment: "confirmed"});
65+
console.log(transaction);
66+
assert(transaction?.meta?.logMessages[0].startsWith(`Program ${programId}`));
67+
// 'Hello Solana' as bytes
68+
assert(transaction?.meta?.logMessages[1] === 'Program log: 0000000000000000000000000000000000000000000000000000000000000001::string::String { bytes: [72, 101, 108, 108, 111, 32, 83, 111, 108, 97, 110, 97], }');
69+
assert(transaction?.meta?.logMessages[2] === `Program ${programId} consumed 5331 of 200000 compute units`);
70+
assert(transaction?.meta?.logMessages[3] === `Program ${programId} success`);
71+
});
72+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"types": ["mocha", "chai"],
4+
"typeRoots": ["./node_modules/@types"],
5+
"lib": ["es2015"],
6+
"module": "commonjs",
7+
"target": "es6",
8+
"esModuleInterop": true
9+
}
10+
}

0 commit comments

Comments
 (0)