Browse Source

transfer sol

jpcaulfi 3 years ago
parent
commit
084ce983a1

+ 2 - 2
README.md

@@ -51,8 +51,8 @@ Regardless of what you may want to add on top of existing Solana programs, the n
 - [x] 3. Recommended program layout
 - ### [ ] Accounts
 - [x] 1. Creating a system account
-- [x] 2. Rent
-- [ ] 3. Transferring SOL
+- [ ] 2. Rent
+- [x] 3. Transferring SOL
 - [ ] 4. Transferring an account's ownership
 - [ ] 5. Destroying an account
 - ### [ ] Tokens

+ 14 - 0
accounts/transfer-sol/anchor/Anchor.toml

@@ -0,0 +1,14 @@
+[features]
+seeds = false
+[programs.localnet]
+transfer_sol = "4fQVnLWKKKYxtxgGn7Haw8v2g2Hzbu8K61JvWKvqAi7W"
+
+[registry]
+url = "https://anchor.projectserum.com"
+
+[provider]
+cluster = "localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 13 - 0
accounts/transfer-sol/anchor/Cargo.toml

@@ -0,0 +1,13 @@
+[workspace]
+members = [
+    "programs/*"
+]
+
+[profile.release]
+overflow-checks = true
+lto = "fat"
+codegen-units = 1
+[profile.release.build-override]
+opt-level = 3
+incremental = false
+codegen-units = 1

+ 14 - 0
accounts/transfer-sol/anchor/package.json

@@ -0,0 +1,14 @@
+{
+    "dependencies": {
+        "@project-serum/anchor": "^0.24.2"
+    },
+    "devDependencies": {
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "typescript": "^4.3.5"
+    }
+}

+ 19 - 0
accounts/transfer-sol/anchor/programs/transfer-sol/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "transfer-sol"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "transfer_sol"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = "0.24.2"

+ 2 - 0
accounts/transfer-sol/anchor/programs/transfer-sol/Xargo.toml

@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []

+ 40 - 0
accounts/transfer-sol/anchor/programs/transfer-sol/src/lib.rs

@@ -0,0 +1,40 @@
+use anchor_lang::prelude::*;
+use anchor_lang::system_program;
+
+declare_id!("4fQVnLWKKKYxtxgGn7Haw8v2g2Hzbu8K61JvWKvqAi7W");
+
+#[program]
+pub mod transfer_sol {
+    use super::*;
+
+    pub fn transfer_sol(ctx: Context<TransferSol>, amount: u64) -> Result<()> {
+        
+        msg!("Received request to transfer {:?} lamports from {:?} to {:?}.", 
+            amount, &ctx.accounts.payer.key(), &ctx.accounts.recipient.key());
+        msg!("  Processing transfer...");
+
+        system_program::transfer(
+            CpiContext::new(
+                ctx.accounts.system_program.to_account_info(),
+                system_program::Transfer {
+                    from: ctx.accounts.payer.to_account_info(),
+                    to: ctx.accounts.recipient.to_account_info(),
+                },
+            ),
+            amount,
+        )?;
+        
+        msg!("Transfer completed successfully.");
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct TransferSol<'info> {
+    /// CHECK: We're initializing this account via the transfer
+    #[account(mut)]
+    recipient: AccountInfo<'info>,
+    #[account(mut)]
+    payer: Signer<'info>,
+    system_program: Program<'info, System>,
+}

+ 38 - 0
accounts/transfer-sol/anchor/tests/test.ts

@@ -0,0 +1,38 @@
+import * as anchor from "@project-serum/anchor";
+import { TransferSol } from "../target/types/transfer_sol";
+
+describe("transfer-sol", () => {
+  
+  const provider = anchor.AnchorProvider.env();
+  anchor.setProvider(provider);
+  const wallet = provider.wallet as anchor.Wallet;
+  const program = anchor.workspace.TransferSol as anchor.Program<TransferSol>;
+
+  it("Transfer some SOL", async () => {
+
+    async function getBalances(payerPubkey: anchor.web3.PublicKey, recipientPubkey: anchor.web3.PublicKey, timeframe: string) {
+      let payerBalance = await provider.connection.getBalance(payerPubkey);
+      let recipientBalance = await provider.connection.getBalance(recipientPubkey);
+      console.log(`${timeframe} balances:`);
+      console.log(`   Payer: ${payerBalance}`);
+      console.log(`   Recipient: ${recipientBalance}`);
+    };
+
+    const recipientKeypair = anchor.web3.Keypair.generate();
+    const transferAmount = 1 * anchor.web3.LAMPORTS_PER_SOL;
+
+    await getBalances(wallet.publicKey, recipientKeypair.publicKey, "Beginning");
+    
+    await program.methods.transferSol(new anchor.BN(transferAmount))
+    .accounts({
+      payer: wallet.publicKey,
+      recipient: recipientKeypair.publicKey,
+      systemProgram: anchor.web3.SystemProgram.programId,
+    })
+    .signers([wallet.payer])
+    .rpc();
+
+    await getBalances(wallet.publicKey, recipientKeypair.publicKey, "Resulting");
+
+  });
+});

+ 10 - 0
accounts/transfer-sol/anchor/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true
+  }
+}

+ 8 - 0
accounts/transfer-sol/native/cicd.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# This script is for quick building & deploying of the program.
+# It also serves as a reference for the commands used for building & deploying Solana programs.
+# Run this bad boy with "bash cicd.sh" or "./cicd.sh"
+
+cargo build-bpf --manifest-path=./program/Cargo.toml --bpf-out-dir=./program/target/so
+solana program deploy ./program/target/so/program.so

+ 19 - 0
accounts/transfer-sol/native/package.json

@@ -0,0 +1,19 @@
+{
+  "scripts": {
+    "test": "yarn run ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts"
+  },
+  "dependencies": {
+    "@solana/web3.js": "^1.47.3",
+    "buffer-layout": "^1.2.2",
+    "fs": "^0.0.1-security"
+  },
+  "devDependencies": {
+    "@types/bn.js": "^5.1.0",
+    "@types/chai": "^4.3.1",
+    "@types/mocha": "^9.1.1",
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^10.0.0",
+    "typescript": "^4.3.5"
+  }
+}

+ 10 - 0
accounts/transfer-sol/native/program/Cargo.toml

@@ -0,0 +1,10 @@
+[package]
+name = "program"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+solana-program = "1.10.12"
+
+[lib]
+crate-type = ["cdylib", "lib"]

+ 48 - 0
accounts/transfer-sol/native/program/src/lib.rs

@@ -0,0 +1,48 @@
+use {
+    std::convert::TryInto,
+    solana_program::{
+        account_info::{
+            next_account_info, AccountInfo
+        },
+        entrypoint,
+        entrypoint::ProgramResult,
+        msg,
+        program::invoke,
+        program_error::ProgramError,
+        pubkey::Pubkey,
+        system_instruction,
+    },
+};
+
+
+entrypoint!(process_instruction);
+
+
+fn process_instruction(
+    _program_id: &Pubkey,
+    accounts: &[AccountInfo],
+    instruction_data: &[u8],
+) -> ProgramResult {
+
+    let accounts_iter = &mut accounts.iter();
+    let payer = next_account_info(accounts_iter)?;
+    let recipient = next_account_info(accounts_iter)?;
+
+    let amount = instruction_data
+        .get(..8)
+        .and_then(|slice| slice.try_into().ok())
+        .map(u64::from_le_bytes)
+        .ok_or(ProgramError::InvalidInstructionData)?;
+
+    msg!("Received request to transfer {:?} lamports from {:?} to {:?}.", 
+        amount, payer.key, recipient.key);
+    msg!("  Processing transfer...");
+
+    invoke(
+        &system_instruction::transfer(payer.key, recipient.key, amount),
+        &[payer.clone(), recipient.clone()],
+    )?;
+    
+    msg!("Transfer completed successfully.");
+    Ok(())
+}

+ 64 - 0
accounts/transfer-sol/native/tests/test.ts

@@ -0,0 +1,64 @@
+import {
+    Connection,
+    Keypair,
+    LAMPORTS_PER_SOL,
+    PublicKey,
+    sendAndConfirmTransaction,
+    SystemProgram,
+    Transaction,
+    TransactionInstruction,
+} from '@solana/web3.js';
+import * as buffer_layout from "buffer-layout";
+
+
+function createKeypairFromFile(path: string): Keypair {
+    return Keypair.fromSecretKey(
+        Buffer.from(JSON.parse(require('fs').readFileSync(path, "utf-8")))
+    )
+};
+
+
+describe("transfer-sol", () => {
+
+    async function getBalances(payerPubkey: PublicKey, recipientPubkey: PublicKey, timeframe: string) {
+        let payerBalance = await connection.getBalance(payerPubkey);
+        let recipientBalance = await connection.getBalance(recipientPubkey);
+        console.log(`${timeframe} balances:`);
+        console.log(`   Payer: ${payerBalance}`);
+        console.log(`   Recipient: ${recipientBalance}`);
+    };
+
+    const connection = new Connection(`http://localhost:8899`, 'confirmed');
+    const payer = createKeypairFromFile(require('os').homedir() + '/.config/solana/id.json');
+    const program = createKeypairFromFile('./program/target/so/program-keypair.json');
+  
+    it("Transfer some SOL", async () => {
+
+        let recipientKeypair = Keypair.generate();
+        let transferAmount = 1 * LAMPORTS_PER_SOL;
+
+        await getBalances(payer.publicKey, recipientKeypair.publicKey, "Beginning");
+
+        let data = Buffer.alloc(8) // 8 bytes
+        buffer_layout.ns64("value").encode(transferAmount, data);
+
+        let ix = new TransactionInstruction({
+            keys: [
+                {pubkey: payer.publicKey, isSigner: true, isWritable: true},
+                {pubkey: recipientKeypair.publicKey, isSigner: false, isWritable: true},
+                {pubkey: SystemProgram.programId, isSigner: false, isWritable: false}
+            ],
+            programId: program.publicKey,
+            data: data,
+        });
+
+        await sendAndConfirmTransaction(
+            connection, 
+            new Transaction().add(ix),
+            [payer]
+        );
+
+        await getBalances(payer.publicKey, recipientKeypair.publicKey, "Resulting");
+    });
+  });
+  

+ 10 - 0
accounts/transfer-sol/native/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true
+  }
+}