John 2 роки тому
батько
коміт
3529ef5b48
66 змінених файлів з 2441 додано та 0 видалено
  1. 8 0
      basics/account-data/solang/.gitignore
  2. 15 0
      basics/account-data/solang/Anchor.toml
  3. 19 0
      basics/account-data/solang/package.json
  4. 37 0
      basics/account-data/solang/solidity/account-data.sol
  5. 53 0
      basics/account-data/solang/tests/account-data.ts
  6. 11 0
      basics/account-data/solang/tsconfig.json
  7. 8 0
      basics/checking-accounts/solang/.gitignore
  8. 15 0
      basics/checking-accounts/solang/Anchor.toml
  9. 19 0
      basics/checking-accounts/solang/package.json
  10. 48 0
      basics/checking-accounts/solang/solidity/checking-accounts.sol
  11. 74 0
      basics/checking-accounts/solang/tests/checking-accounts.ts
  12. 11 0
      basics/checking-accounts/solang/tsconfig.json
  13. 8 0
      basics/counter/solang/.gitignore
  14. 15 0
      basics/counter/solang/Anchor.toml
  15. 19 0
      basics/counter/solang/package.json
  16. 23 0
      basics/counter/solang/solidity/counter.sol
  17. 53 0
      basics/counter/solang/tests/counter.ts
  18. 11 0
      basics/counter/solang/tsconfig.json
  19. 8 0
      basics/cross-program-invocation/solang/.gitignore
  20. 16 0
      basics/cross-program-invocation/solang/Anchor.toml
  21. 19 0
      basics/cross-program-invocation/solang/package.json
  22. 32 0
      basics/cross-program-invocation/solang/solidity/hand.sol
  23. 30 0
      basics/cross-program-invocation/solang/solidity/lever.sol
  24. 105 0
      basics/cross-program-invocation/solang/tests/test.ts
  25. 11 0
      basics/cross-program-invocation/solang/tsconfig.json
  26. 8 0
      basics/hello-solana/solang/.gitignore
  27. 15 0
      basics/hello-solana/solang/Anchor.toml
  28. 19 0
      basics/hello-solana/solang/package.json
  29. 15 0
      basics/hello-solana/solang/solidity/hello-solana.sol
  30. 25 0
      basics/hello-solana/solang/tests/hello-solana.ts
  31. 11 0
      basics/hello-solana/solang/tsconfig.json
  32. 8 0
      basics/pda-rent-payer/solang/.gitignore
  33. 15 0
      basics/pda-rent-payer/solang/Anchor.toml
  34. 19 0
      basics/pda-rent-payer/solang/package.json
  35. 37 0
      basics/pda-rent-payer/solang/solidity/pda-rent-payer.sol
  36. 300 0
      basics/pda-rent-payer/solang/solidity/system_instruction.sol
  37. 61 0
      basics/pda-rent-payer/solang/tests/pda-rent-payer.ts
  38. 11 0
      basics/pda-rent-payer/solang/tsconfig.json
  39. 8 0
      basics/processing-instructions/solang/.gitignore
  40. 8 0
      basics/processing-instructions/solang/.prettierignore
  41. 15 0
      basics/processing-instructions/solang/Anchor.toml
  42. 19 0
      basics/processing-instructions/solang/package.json
  43. 18 0
      basics/processing-instructions/solang/solidity/processing-instructions.sol
  44. 40 0
      basics/processing-instructions/solang/tests/processing-instructions.ts
  45. 11 0
      basics/processing-instructions/solang/tsconfig.json
  46. 8 0
      basics/program-derived-addresses/solang/.gitignore
  47. 15 0
      basics/program-derived-addresses/solang/Anchor.toml
  48. 19 0
      basics/program-derived-addresses/solang/package.json
  49. 43 0
      basics/program-derived-addresses/solang/solidity/program-derived-addresses.sol
  50. 60 0
      basics/program-derived-addresses/solang/tests/program-derived-addresses.ts
  51. 11 0
      basics/program-derived-addresses/solang/tsconfig.json
  52. 8 0
      basics/rent/solang/.gitignore
  53. 15 0
      basics/rent/solang/Anchor.toml
  54. 19 0
      basics/rent/solang/package.json
  55. 21 0
      basics/rent/solang/solidity/rent.sol
  56. 300 0
      basics/rent/solang/solidity/system_instruction.sol
  57. 60 0
      basics/rent/solang/tests/rent.ts
  58. 11 0
      basics/rent/solang/tsconfig.json
  59. 8 0
      basics/transfer-sol/solang/.gitignore
  60. 8 0
      basics/transfer-sol/solang/.prettierignore
  61. 15 0
      basics/transfer-sol/solang/Anchor.toml
  62. 19 0
      basics/transfer-sol/solang/package.json
  63. 300 0
      basics/transfer-sol/solang/solidity/system_instruction.sol
  64. 30 0
      basics/transfer-sol/solang/solidity/transfer-sol.sol
  65. 129 0
      basics/transfer-sol/solang/tests/transfer-sol.ts
  66. 11 0
      basics/transfer-sol/solang/tsconfig.json

+ 8 - 0
basics/account-data/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 15 - 0
basics/account-data/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+account_data = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/account-data/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 37 - 0
basics/account-data/solang/solidity/account-data.sol

@@ -0,0 +1,37 @@
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract account_data {
+    // A private instance of the AddressInfo struct
+    // This is the data that is stored in the account
+    AddressInfo private addressInfo;
+
+    // The AddressInfo struct definition
+    struct AddressInfo {
+        string name;
+        uint8 houseNumber;
+        string street;
+        string city;
+    }
+
+    @payer(payer) // "payer" is the account that pays to create the dataAccount
+    @space(space) // "space" allocated to the account (maximum 10240 bytes, maximum space that can be reallocate when creating account in program via a CPI)
+    constructor(address payer, uint16 space, string _name, uint8 _houseNumber, string _street, string _city) {
+        // The AddressInfo instance is initialized with the data passed to the constructor
+        addressInfo = AddressInfo(_name, _houseNumber, _street, _city);
+    }
+
+    // A function to get the addressInfo data stored on the account
+    function get() public view returns (AddressInfo) {
+        return addressInfo;
+    }
+
+    // A function to get the size in bytes of the stored AddressInfo
+    function getAddressInfoSize() public view returns(uint) {
+        uint size = 0;
+        size += bytes(addressInfo.name).length;
+        size += 1; // For houseNumber, which is uint8 and takes 1 byte
+        size += bytes(addressInfo.street).length;
+        size += bytes(addressInfo.city).length;
+        return size;
+    }
+}

+ 53 - 0
basics/account-data/solang/tests/account-data.ts

@@ -0,0 +1,53 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { AccountData } from "../target/types/account_data"
+
+describe("account-data", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate a new random keypair for the data account.
+  const dataAccount = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet
+  const program = anchor.workspace.AccountData as Program<AccountData>
+
+  // Create the new account
+  // Using 10240 bytes of space, because its unclear how to correctly calculate the minimum space needed for the account
+  // Space calculation is different from regular Native/Anchor Solana programs
+  it("Is initialized!", async () => {
+    const tx = await program.methods
+      .new(
+        wallet.publicKey, // payer
+        10240, // space (10240 bytes is the maximum space allowed when allocating space through a program)
+        "Joe C", // name
+        136, // house number
+        "Mile High Dr.", // street
+        "Solana Beach" // city
+      )
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([dataAccount])
+      .rpc()
+    console.log("Your transaction signature", tx)
+  })
+
+  // Get the account data
+  it("Get AddressInfo Data", async () => {
+    const val = await program.methods
+      .get()
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .view()
+    console.log("State:", val)
+  })
+
+  // Get the account data size
+  // Testing how much space is used to store the account data
+  // However, minimum space required is greater than this
+  it("Get AddressInfo Size", async () => {
+    const size = await program.methods
+      .getAddressInfoSize()
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .view()
+    console.log("Size:", size.toNumber())
+  })
+})

+ 11 - 0
basics/account-data/solang/tsconfig.json

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

+ 8 - 0
basics/checking-accounts/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 15 - 0
basics/checking-accounts/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+checking_accounts = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/checking-accounts/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 48 - 0
basics/checking-accounts/solang/solidity/checking-accounts.sol

@@ -0,0 +1,48 @@
+
+import "solana";
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract checking_accounts {
+
+    // The dataAccount is unused in this example, but is a required account when using Solang
+    @payer(payer) // "payer" is the account that pays to create the dataAccount
+    constructor(address payer) {}
+
+    function checkAccounts(address accountToChange, address accountToCreate) public view {
+        print("Number of Accounts Provided: {:}".format(tx.accounts.length));
+
+        // Find the accounts we are looking for and perform checks on them
+        for (uint64 i = 0; i < tx.accounts.length; i++) {
+            if (tx.accounts[i].key == accountToChange) {
+                print("Found Account To Change");
+                programOwnerCheck(tx.accounts[i]);
+            }
+            if (tx.accounts[i].key == accountToCreate) {
+                print("Found Account To Create");
+                notInitializedCheck(tx.accounts[i]);
+                signerCheck(tx.accounts[i]);
+            }
+        }
+
+        // (Create account...) (unimplemented)
+        // (Change account...) (unimplemented)
+    }
+
+    function programOwnerCheck(AccountInfo account) internal pure {
+        print("Progam Owner Check");
+        // The owner of this account should be this program
+        require(account.owner == type(checking_accounts).program_id, "Account to change does not have the correct program id.");
+    }
+
+    function notInitializedCheck(AccountInfo account) internal pure {
+        print("Check Account Not Initialized");
+        // This account should not be initialized (has no lamports)
+        require(account.lamports == 0, "The program expected the account to create to not yet be initialized.");
+    }
+
+    function signerCheck(AccountInfo account) internal pure {
+        print("Check Account Signed Transaction");
+        // This account should be a signer on the transaction
+        require(account.is_signer, "Account required to be a signer");
+    }
+}

+ 74 - 0
basics/checking-accounts/solang/tests/checking-accounts.ts

@@ -0,0 +1,74 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { CheckingAccounts } from "../target/types/checking_accounts"
+import {
+  SystemProgram,
+  Transaction,
+  sendAndConfirmTransaction,
+} from "@solana/web3.js"
+
+describe("checking-accounts", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate a new random keypair for the data account.
+  const dataAccount = anchor.web3.Keypair.generate()
+
+  // Generate a new keypair to represent the account we will change.
+  const accountToChange = anchor.web3.Keypair.generate()
+  // Generate a new keypair to represent the account we will create.
+  const accountToCreate = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet as anchor.Wallet
+  const connection = provider.connection
+
+  const program = anchor.workspace.CheckingAccounts as Program<CheckingAccounts>
+
+  it("Is initialized!", async () => {
+    // Create the new dataAccount, this is an account required by Solang even though we don't use it
+    const tx = await program.methods
+      .new(wallet.publicKey)
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([dataAccount])
+      .rpc({ skipPreflight: true })
+    console.log("Your transaction signature", tx)
+  })
+
+  it("Create an account owned by our program", async () => {
+    // Create the new account owned by our program by directly calling the system program
+    let ix = SystemProgram.createAccount({
+      fromPubkey: wallet.publicKey,
+      newAccountPubkey: accountToChange.publicKey,
+      lamports: await connection.getMinimumBalanceForRentExemption(0),
+      space: 0,
+      programId: program.programId, // Our program
+    })
+
+    await sendAndConfirmTransaction(connection, new Transaction().add(ix), [
+      wallet.payer,
+      accountToChange,
+    ])
+  })
+
+  it("Check Accounts", async () => {
+    // Invoke the checkAccounts instruction on our program, passing in the account we want to "check"
+    const tx = await program.methods
+      .checkAccounts(accountToChange.publicKey, accountToCreate.publicKey)
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .remainingAccounts([
+        {
+          pubkey: accountToChange.publicKey,
+          isWritable: true,
+          isSigner: false,
+        },
+        {
+          pubkey: accountToCreate.publicKey,
+          isWritable: true,
+          isSigner: true,
+        },
+      ])
+      .signers([accountToCreate])
+      .rpc({ skipPreflight: true })
+    console.log("Your transaction signature", tx)
+  })
+})

+ 11 - 0
basics/checking-accounts/solang/tsconfig.json

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

+ 8 - 0
basics/counter/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 15 - 0
basics/counter/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+counter = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/counter/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 23 - 0
basics/counter/solang/solidity/counter.sol

@@ -0,0 +1,23 @@
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract counter {
+    // The counter value that is stored in the account
+    uint64 private count;
+
+    // The constructor is used to create a new counter account
+    @payer(payer)  // The "payer" pays for the counter account creation
+    constructor(address payer) {
+        // Initialize the count to zero
+        count = 0;
+    }
+
+    // Increments the count by one.
+    function increment() public {
+        count += 1;
+    }
+
+    // Returns the count value
+    function get() public view returns (uint64) {
+        return count;
+    }
+}

+ 53 - 0
basics/counter/solang/tests/counter.ts

@@ -0,0 +1,53 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { Counter } from "../target/types/counter"
+import { assert } from "chai"
+
+describe("counter", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate a new random keypair for the data account.
+  const dataAccount = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet
+
+  const program = anchor.workspace.Counter as Program<Counter>
+
+  it("Is initialized!", async () => {
+    // Initialize new Counter account
+    const tx = await program.methods
+      .new(wallet.publicKey) // wallet.publicKey is the payer for the new account
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([dataAccount]) // dataAccount keypair is a required signer because we're using it to create a new account
+      .rpc()
+    console.log("Your transaction signature", tx)
+
+    // Fetch the counter value
+    const val = await program.methods
+      .get()
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .view()
+
+    assert(Number(val) === 0)
+    console.log("Count:", Number(val))
+  })
+
+  it("Increment", async () => {
+    // Increment the counter
+    const tx = await program.methods
+      .increment()
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .rpc()
+    console.log("Your transaction signature", tx)
+
+    // Fetch the counter value
+    const val = await program.methods
+      .get()
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .view()
+
+    assert(Number(val) === 1)
+    console.log("Count:", Number(val))
+  })
+})

+ 11 - 0
basics/counter/solang/tsconfig.json

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

+ 8 - 0
basics/cross-program-invocation/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 16 - 0
basics/cross-program-invocation/solang/Anchor.toml

@@ -0,0 +1,16 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+hand = "9rN5nSQBX1gcbweshWAfRE4Ccv5puJfxUJhqKZ5BEdoP"
+lever = "4wFN9As94uDgcBK9umEi6DNjRLi8gq7jaHwSw3829xq8"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/cross-program-invocation/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 32 - 0
basics/cross-program-invocation/solang/solidity/hand.sol

@@ -0,0 +1,32 @@
+
+import "solana";
+
+// Interface to the lever program.
+leverInterface constant leverProgram = leverInterface(address'4wFN9As94uDgcBK9umEi6DNjRLi8gq7jaHwSw3829xq8');
+interface leverInterface {
+    function switchPower(string name) external;
+}
+
+@program_id("9rN5nSQBX1gcbweshWAfRE4Ccv5puJfxUJhqKZ5BEdoP")
+contract hand {
+
+    // Creating a data account is required by Solang, but the account is not used in this example.
+    // We only interact with the lever program.
+    @payer(payer) // payer for the data account
+    constructor(address payer) {}
+
+    // "Pull the lever" by calling the switchPower instruction on the lever program via a Cross Program Invocation.
+    function pullLever(address dataAccount, string name) public {
+        // The account required by the switchPower instruction.
+        // This is the data account created by the lever program (not this program), which stores the state of the switch.
+        AccountMeta[1] metas = [
+            AccountMeta({pubkey: dataAccount, is_writable: true, is_signer: false})
+        ];
+
+        // The data required by the switchPower instruction.
+        string instructionData = name;
+
+        // Invoke the switchPower instruction on the lever program.
+        leverProgram.switchPower{accounts: metas}(instructionData);
+    }
+}

+ 30 - 0
basics/cross-program-invocation/solang/solidity/lever.sol

@@ -0,0 +1,30 @@
+
+@program_id("4wFN9As94uDgcBK9umEi6DNjRLi8gq7jaHwSw3829xq8")
+contract lever {
+    // Switch state
+    bool private isOn = true;
+
+    @payer(payer) // payer for the data account
+    constructor(address payer) {}
+
+    // Switch the power on or off
+    function switchPower(string name) public {
+        // Flip the switch
+        isOn = !isOn;
+
+        // Print the name of the person who pulled the switch
+        print("{:} is pulling the power switch!".format(name));
+
+        // Print the current state of the switch
+        if (isOn){
+            print("The power is now on.");
+        } else {
+            print("The power is now off!");
+        }
+    }
+
+    // Get the current state of the switch
+    function get() public view returns (bool) {
+        return isOn;
+    }
+}

+ 105 - 0
basics/cross-program-invocation/solang/tests/test.ts

@@ -0,0 +1,105 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { Lever } from "../target/types/lever"
+import { Hand } from "../target/types/hand"
+
+describe("cross-program-invocation", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate a new keypair for the data accounts for each program
+  const dataAccountLever = anchor.web3.Keypair.generate()
+  const dataAccountHand = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet
+
+  // The lever program and hand program
+  const leverProgram = anchor.workspace.Lever as Program<Lever>
+  const handProgram = anchor.workspace.Hand as Program<Hand>
+
+  it("Initialize the lever!", async () => {
+    // Initialize data account for the lever program
+    const tx = await leverProgram.methods
+      .new(wallet.publicKey)
+      .accounts({ dataAccount: dataAccountLever.publicKey })
+      .signers([dataAccountLever])
+      .rpc()
+    console.log("Your transaction signature", tx)
+
+    // Fetch the state of the data account
+    const val = await leverProgram.methods
+      .get()
+      .accounts({ dataAccount: dataAccountLever.publicKey })
+      .view()
+
+    console.log("State:", val)
+  })
+
+  it("Pull the lever!", async () => {
+    // Initialize data account for the hand program
+    // This is required by Solang, but the account is not used
+    const tx = await handProgram.methods
+      .new(wallet.publicKey)
+      .accounts({ dataAccount: dataAccountHand.publicKey })
+      .signers([dataAccountHand])
+      .rpc()
+    console.log("Your transaction signature", tx)
+
+    // Call the pullLever instruction on the hand program, which invokes the lever program via CPI
+    const tx2 = await handProgram.methods
+      .pullLever(dataAccountLever.publicKey, "Chris")
+      .accounts({ dataAccount: dataAccountHand.publicKey })
+      .remainingAccounts([
+        {
+          pubkey: dataAccountLever.publicKey, // The lever program's data account, which stores the state
+          isWritable: true,
+          isSigner: false,
+        },
+        {
+          pubkey: leverProgram.programId, // The lever program's program ID
+          isWritable: false,
+          isSigner: false,
+        },
+      ])
+      .rpc({ skipPreflight: true })
+    console.log("Your transaction signature", tx2)
+
+    // Fetch the state of the data account
+    const val = await leverProgram.methods
+      .get()
+      .accounts({ dataAccount: dataAccountLever.publicKey })
+      .view()
+
+    console.log("State:", val)
+  })
+
+  it("Pull it again!", async () => {
+    // Call the pullLever instruction on the hand program, which invokes the lever program via CPI
+    const tx = await handProgram.methods
+      .pullLever(dataAccountLever.publicKey, "Ashley")
+      .accounts({ dataAccount: dataAccountHand.publicKey })
+      .remainingAccounts([
+        {
+          pubkey: dataAccountLever.publicKey, // The lever program's data account, which stores the state
+          isWritable: true,
+          isSigner: false,
+        },
+        {
+          pubkey: leverProgram.programId, // The lever program's program ID
+          isWritable: false,
+          isSigner: false,
+        },
+      ])
+      .rpc({ skipPreflight: true })
+
+    console.log("Your transaction signature", tx)
+
+    // Fetch the state of the data account
+    const val = await leverProgram.methods
+      .get()
+      .accounts({ dataAccount: dataAccountLever.publicKey })
+      .view()
+
+    console.log("State:", val)
+  })
+})

+ 11 - 0
basics/cross-program-invocation/solang/tsconfig.json

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

+ 8 - 0
basics/hello-solana/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 15 - 0
basics/hello-solana/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+hello_solana = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/hello-solana/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 15 - 0
basics/hello-solana/solang/solidity/hello-solana.sol

@@ -0,0 +1,15 @@
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract hello_solana {
+    // The constructor is used to create a new account
+    // Here we create a new account that stores no data and only prints messages to the program logs when the constructor is called.
+    @payer(payer) // The "payer" pays for the account creation
+    constructor(address payer) {
+        // We get the program ID by calling 'type(hello_solana).program_id', where "hello_solana" is the name of the contract.
+        address programId = type(hello_solana).program_id;
+
+        // Print messages to the program logs
+        print("Hello, Solana!");
+        print("Our program's Program ID: {:}".format(programId));
+    }
+}

+ 25 - 0
basics/hello-solana/solang/tests/hello-solana.ts

@@ -0,0 +1,25 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { HelloSolana } from "../target/types/hello_solana"
+
+describe("hello-solana", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate a new random keypair for the data account.
+  const dataAccount = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet
+
+  const program = anchor.workspace.HelloSolana as Program<HelloSolana>
+
+  it("Is initialized!", async () => {
+    // Initialize a new data account
+    const tx = await program.methods
+      .new(wallet.publicKey) // wallet.publicKey is the payer for the new account
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([dataAccount]) // dataAccount keypair is a required signer because we're using it to create a new account
+      .rpc()
+    console.log("Your transaction signature", tx)
+  })
+})

+ 11 - 0
basics/hello-solana/solang/tsconfig.json

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

+ 8 - 0
basics/pda-rent-payer/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 15 - 0
basics/pda-rent-payer/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+pda_rent_payer = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/pda-rent-payer/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 37 - 0
basics/pda-rent-payer/solang/solidity/pda-rent-payer.sol

@@ -0,0 +1,37 @@
+
+import "./system_instruction.sol";
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract pda_rent_payer {
+    bool private value = true;
+
+    @payer(payer) // "payer" is the account that pays for creating the account
+    @seed("rent_vault") // hardcoded seed
+    @bump(bump) // bump seed to derive the pda
+    constructor(address payer, bytes1 bump, uint64 fundLamports) {
+        // Independently derive the PDA address from the seeds, bump, and programId
+        (address pda, bytes1 _bump) = try_find_program_address(["rent_vault"], type(pda_rent_payer).program_id);
+
+        // Verify that the bump passed to the constructor matches the bump derived from the seeds and programId
+        // This ensures that only the canonical pda address can be used to create the account (first bump that generates a valid pda address)
+        require(bump == _bump, 'INVALID_BUMP');
+
+        // Fund the pda account with additional lamports
+        SystemInstruction.transfer(
+            payer, // from
+            address(this), // to (the address of the account being created)
+            fundLamports // amount of lamports to transfer
+        );
+    }
+
+    function createNewAccount(uint64 lamports) public {
+        AccountInfo from = tx.accounts[0]; // first account must be an account owned by the program
+        AccountInfo to = tx.accounts[1]; // second account must be the intended recipient
+
+        print("From: {:}".format(from.key));
+        print("To: {:}".format(to.key));
+
+        from.lamports -= lamports;
+        to.lamports += lamports;
+    }
+}

+ 300 - 0
basics/pda-rent-payer/solang/solidity/system_instruction.sol

@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: Apache-2.0
+
+// Disclaimer: This library provides a bridge for Solidity to interact with Solana's system instructions. Although it is production ready,
+// it has not been audited for security, so use it at your own risk.
+
+import 'solana';
+
+library SystemInstruction {
+    address constant systemAddress = address"11111111111111111111111111111111";
+    address constant recentBlockHashes = address"SysvarRecentB1ockHashes11111111111111111111";
+    address constant rentAddress = address"SysvarRent111111111111111111111111111111111";
+    uint64 constant state_size = 80;
+
+    enum Instruction {
+        CreateAccount,
+        Assign,
+        Transfer,
+        CreateAccountWithSeed,
+        AdvanceNounceAccount,
+        WithdrawNonceAccount,
+        InitializeNonceAccount,
+        AuthorizeNonceAccount,
+        Allocate,
+        AllocateWithSeed,
+        AssignWithSeed,
+        TransferWithSeed,
+        UpgradeNonceAccount // This is not available on Solana v1.9.15
+    }
+
+    /// Create a new account on Solana
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param to public key for the account to be created
+    /// @param lamports amount of lamports to be transfered to the new account
+    /// @param space the size in bytes that is going to be made available for the account
+    /// @param owner public key for the program that will own the account being created
+    function create_account(address from, address to, uint64 lamports, uint64 space, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: true, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.CreateAccount), lamports, space, owner);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new account on Solana using a public key derived from a seed
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param to the public key for the account to be created. The public key must match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'to' address using the seed
+    /// @param seed the string utilized to created the 'to' public key
+    /// @param lamports amount of lamports to be transfered to the new account
+    /// @param space the size in bytes that is going to be made available for the account
+    /// @param owner public key for the program that will own the account being created
+    function create_account_with_seed(address from, address to, address base, string seed, uint64 lamports, uint64 space, address owner) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+        uint32 buffer_size = 92 + seed.length;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.CreateAccountWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(uint64(seed.length), 36);
+        bincode.writeString(seed, 44);
+        uint32 offset = seed.length + 44;
+        bincode.writeUint64LE(lamports, offset);
+        offset += 8;
+        bincode.writeUint64LE(space, offset);
+        offset += 8;
+        bincode.writeAddress(owner, offset);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Assign account to a program (owner)
+    ///
+    /// @param pubkey the public key for the account whose owner is going to be reassigned
+    /// @param owner the public key for the new account owner
+    function assign(address pubkey, address owner) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: pubkey, is_signer: true, is_writable: true})
+        ];
+        bytes bincode = abi.encode(uint32(Instruction.Assign), owner);
+
+        systemAddress.call{accounts: meta}(bincode);
+    }
+
+    /// Assign account to a program (owner) based on a seed
+    ///
+    /// @param addr the public key for the account whose owner is going to be reassigned. The public key must match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'addr' key using the seed
+    /// @param seed the string utilized to created the 'addr' public key
+    /// @param owner the public key for the new program owner
+    function assign_with_seed(address addr, address base, string seed, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: addr, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+
+        uint32 buffer_size = 76 + seed.length;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.AssignWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(uint64(seed.length), 36);
+        bincode.writeString(seed, 44);
+        bincode.writeAddress(owner, 44 + seed.length);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Transfer lamports between accounts
+    ///
+    /// @param from public key for the funding account
+    /// @param to public key for the recipient account
+    /// @param lamports amount of lamports to transfer
+    function transfer(address from, address to, uint64 lamports) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: false, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.Transfer), lamports);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Transfer lamports from a derived address
+    ///
+    /// @param from_pubkey The funding account public key. It should match create_with_seed(from_base, seed, from_owner)
+    /// @param from_base the base address that derived the 'from_pubkey' key using the seed
+    /// @param seed the string utilized to create the 'from_pubkey' public key
+    /// @param from_owner owner to use to derive the funding account address
+    /// @param to_pubkey the public key for the recipient account
+    /// @param lamports amount of lamports to transfer
+    function transfer_with_seed(address from_pubkey, address from_base, string seed, address from_owner, address to_pubkey, uint64 lamports) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: from_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: from_base, is_signer: true, is_writable: false}),
+            AccountMeta({pubkey: to_pubkey, is_signer: false, is_writable: true})
+        ];
+
+        uint32 buffer_size = seed.length + 52;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.TransferWithSeed), 0);
+        bincode.writeUint64LE(lamports, 4);
+        bincode.writeUint64LE(seed.length, 12);
+        bincode.writeString(seed, 20);
+        bincode.writeAddress(from_owner, 20 + seed.length);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Allocate space in a (possibly new) account without funding
+    ///
+    /// @param pub_key account for which to allocate space
+    /// @param space number of bytes of memory to allocate
+    function allocate(address pub_key, uint64 space) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: pub_key, is_signer: true, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.Allocate), space);
+
+        systemAddress.call{accounts: meta}(bincode);
+    }
+
+    /// Allocate space for an assign an account at an address derived from a base public key and a seed
+    ///
+    /// @param addr account for which to allocate space. It should match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'addr' key using the seed
+    /// @param seed the string utilized to create the 'addr' public key
+    /// @param space number of bytes of memory to allocate
+    /// @param owner owner to use to derive the 'addr' account address
+    function allocate_with_seed(address addr, address base, string seed, uint64 space, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: addr, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = new bytes(seed.length + 84);
+        bincode.writeUint32LE(uint32(Instruction.AllocateWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(seed.length, 36);
+        bincode.writeString(seed, 44);
+        uint32 offset = 44 + seed.length;
+        bincode.writeUint64LE(space, offset);
+        offset += 8;
+        bincode.writeAddress(owner, offset);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new nonce account on Solana using a public key derived from a seed
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param nonce the public key for the account to be created. The public key must match create_with_seed(base, seed, systemAddress)
+    /// @param base the base address that derived the 'nonce' key using the seed
+    /// @param seed the string utilized to create the 'addr' public key
+    /// @param authority The entity authorized to execute nonce instructions on the account
+    /// @param lamports amount of lamports to be transfered to the new account
+    function create_nonce_account_with_seed(address from, address nonce, address base, string seed, address authority, uint64 lamports) internal view {
+        create_account_with_seed(from, nonce, base, seed, lamports, state_size, systemAddress);
+
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.InitializeNonceAccount), authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new account on Solana
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param nonce the public key for the nonce account to be created
+    /// @param authority The entity authorized to execute nonce instructions on the account
+    /// @param lamports amount of lamports to be transfered to the new account
+    function create_nonce_account(address from, address nonce, address authority, uint64 lamports) internal view {
+        create_account(from, nonce, lamports, state_size, systemAddress);
+
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.InitializeNonceAccount), authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Consumes a stored nonce, replacing it with a successor
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the publick key for the entity authorized to execute instructins on the account
+    function advance_nonce_account(address nonce_pubkey, address authorized_pubkey) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.AdvanceNounceAccount));
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Withdraw funds from a nonce account
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the public key for the entity authorized to execute instructins on the account
+    /// @param to_pubkey the recipient account
+    /// @param lamports the number of lamports to withdraw
+    function withdraw_nonce_account(address nonce_pubkey, address authorized_pubkey, address to_pubkey, uint64 lamports) internal view {
+        AccountMeta[5] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: to_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.WithdrawNonceAccount), lamports);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Change the entity authorized to execute nonce instructions on the account
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the public key for the entity authorized to execute instructins on the account
+    /// @param new_authority
+    function authorize_nonce_account(address nonce_pubkey, address authorized_pubkey, address new_authority) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.AuthorizeNonceAccount), new_authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// One-time idempotent upgrade of legacy nonce version in order to bump them out of chain domain.
+    ///
+    /// @param nonce the public key for the nonce account
+    // This is not available on Solana v1.9.15
+    function upgrade_nonce_account(address nonce) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.UpgradeNonceAccount));
+        systemAddress.call{accounts: meta}(bincode);
+    }
+}

+ 61 - 0
basics/pda-rent-payer/solang/tests/pda-rent-payer.ts

@@ -0,0 +1,61 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { PdaRentPayer } from "../target/types/pda_rent_payer"
+import { PublicKey } from "@solana/web3.js"
+
+describe("pda-rent-payer", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  const wallet = provider.wallet
+  const connection = provider.connection
+
+  const program = anchor.workspace.PdaRentPayer as Program<PdaRentPayer>
+
+  // Amount of additional lamports to fund the dataAccount with.
+  const fundLamports = 1 * anchor.web3.LAMPORTS_PER_SOL
+
+  // Derive the PDA that will be used to initialize the dataAccount.
+  const [dataAccountPDA, bump] = PublicKey.findProgramAddressSync(
+    [Buffer.from("rent_vault")],
+    program.programId
+  )
+
+  it("Initialize the Rent Vault", async () => {
+    // Add your test here.
+    const tx = await program.methods
+      .new(wallet.publicKey, [bump], new anchor.BN(fundLamports))
+      .accounts({ dataAccount: dataAccountPDA })
+      .rpc()
+    console.log("Your transaction signature", tx)
+
+    const accountInfo = await connection.getAccountInfo(dataAccountPDA)
+    console.log("AccountInfo Lamports:", accountInfo.lamports)
+  })
+
+  it("Create a new account using the Rent Vault", async () => {
+    const newAccount = anchor.web3.Keypair.generate()
+    const space = 100 // number of bytes
+
+    // Get the minimum balance for the account to be rent exempt.
+    const lamports = await connection.getMinimumBalanceForRentExemption(space)
+
+    // Invoke the createNewAccount instruction on our program
+    const tx = await program.methods
+      .createNewAccount(new anchor.BN(lamports))
+      .accounts({ dataAccount: dataAccountPDA })
+      .remainingAccounts([
+        {
+          pubkey: newAccount.publicKey, // account to create by directly transferring lamports
+          isWritable: true,
+          isSigner: false,
+        },
+      ])
+      .rpc()
+    console.log("Your transaction signature", tx)
+
+    const accountInfo = await connection.getAccountInfo(newAccount.publicKey)
+    console.log("AccountInfo Lamports:", accountInfo.lamports)
+  })
+})

+ 11 - 0
basics/pda-rent-payer/solang/tsconfig.json

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

+ 8 - 0
basics/processing-instructions/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 8 - 0
basics/processing-instructions/solang/.prettierignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+node_modules
+dist
+build
+test-ledger

+ 15 - 0
basics/processing-instructions/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+processing_instructions = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/processing-instructions/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 18 - 0
basics/processing-instructions/solang/solidity/processing-instructions.sol

@@ -0,0 +1,18 @@
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract processing_instructions {
+
+    @payer(payer) // payer for the data account, required by Solang but not used in this example
+    constructor(address payer) {}
+
+    function goToPark(string name, uint32 height) public pure {
+        // Print messages to the program logs
+        print("Welcome to the park, {:}".format(name));
+
+        if (height >5) {
+            print("You are tall enough to ride this ride. Congratulations.");
+        } else {
+            print("You are NOT tall enough to ride this ride. Sorry mate.");
+        }
+    }
+}

+ 40 - 0
basics/processing-instructions/solang/tests/processing-instructions.ts

@@ -0,0 +1,40 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { ProcessingInstructions } from "../target/types/processing_instructions"
+
+describe("processing-instructions", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate a new keypair for the data account for the program
+  const dataAccount = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet
+
+  const program = anchor.workspace
+    .ProcessingInstructions as Program<ProcessingInstructions>
+
+  it("Is initialized!", async () => {
+    // Initialize data account for the program, which is required by Solang
+    const tx = await program.methods
+      .new(wallet.publicKey)
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([dataAccount])
+      .rpc()
+    console.log("Your transaction signature", tx)
+  })
+
+  it("Go to the park!", async () => {
+    // Call the goToPark instruction on the program, providing the instruction data
+    await program.methods
+      .goToPark("Jimmy", 3)
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .rpc()
+
+    // Call the goToPark instruction on the program, providing the instruction data
+    await program.methods
+      .goToPark("Mary", 10)
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .rpc()
+  })
+})

+ 11 - 0
basics/processing-instructions/solang/tsconfig.json

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

+ 8 - 0
basics/program-derived-addresses/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 15 - 0
basics/program-derived-addresses/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+program_derived_addresses = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/program-derived-addresses/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 43 - 0
basics/program-derived-addresses/solang/solidity/program-derived-addresses.sol

@@ -0,0 +1,43 @@
+
+import "solana";
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract program_derived_addresses {
+    // A private instance of the PageVisits struct
+    // This is the data that is stored in the account
+    PageVisits private accountData;
+
+    // The PageVisits struct definition
+    struct PageVisits {
+        uint32 pageVisits;
+        bytes1 bump;
+    }
+
+    // The constructor is used to create a new account
+    // The seeds, bump, and programId are used to derive a unique and deterministic pda (program derived address) to use as the account address
+    @payer(payer) // "payer" is the account that pays for creating the account
+    @seed("page_visits") // hardcoded seed
+    @seed(abi.encode(payer)) // additional seed using the payer address
+    @bump(bump) // bump seed to derive the pda
+    constructor(address payer, bytes1 bump) {
+        // Independently derive the PDA address from the seeds, bump, and programId
+        (address pda, bytes1 _bump) = try_find_program_address(["page_visits", abi.encode(payer)], type(program_derived_addresses).program_id);
+
+        // Verify that the bump passed to the constructor matches the bump derived from the seeds and programId
+        // This ensures that only the canonical pda address can be used to create the account (first bump that generates a valid pda address)
+        require(bump == _bump, 'INVALID_BUMP');
+
+        // The PageVisits instance is initialized with pageVisits set to zero and bump set to the bump passed to the constructor
+        accountData = PageVisits(0, bump);
+    }
+
+    // Increments the pageVisits by one.
+    function incrementPageVisits() public {
+        accountData.pageVisits += 1;
+    }
+
+    // Returns the accountData (pageVisits and bump) stored on the account
+    function get() public view returns (PageVisits) {
+        return accountData;
+    }
+}

+ 60 - 0
basics/program-derived-addresses/solang/tests/program-derived-addresses.ts

@@ -0,0 +1,60 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { ProgramDerivedAddresses } from "../target/types/program_derived_addresses"
+import { PublicKey } from "@solana/web3.js"
+
+describe("program-derived-addresses", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  const wallet = provider.wallet
+
+  const program = anchor.workspace
+    .ProgramDerivedAddresses as Program<ProgramDerivedAddresses>
+
+  // Derive the PDA that will be used to initialize the dataAccount.
+  const [dataAccountPDA, bump] = PublicKey.findProgramAddressSync(
+    [Buffer.from("page_visits"), wallet.publicKey.toBuffer()],
+    program.programId
+  )
+
+  it("Is initialized!", async () => {
+    // Initialize the dataAccount using a PDA as the address.
+    // The PDA doesn't have to be passed in explicity as a signer, the program can "sign" for it.
+    // This is a feature of PDAs that allows programs to "sign" for PDA that are derived from their programId.
+    const tx = await program.methods
+      .new(
+        wallet.publicKey, // wallet.publicKey is the payer for the new account
+        [bump] // bump seed for the PDA found using findProgramAddress
+      )
+      .accounts({ dataAccount: dataAccountPDA })
+      .rpc({ skipPreflight: true })
+    console.log("Your transaction signature", tx)
+
+    // Get the current state of the dataAccount.
+    const val = await program.methods
+      .get()
+      .accounts({ dataAccount: dataAccountPDA })
+      .view()
+
+    console.log("State:", val)
+  })
+
+  it("Visit the page!", async () => {
+    // Increment the page visits counter.
+    const tx = await program.methods
+      .incrementPageVisits()
+      .accounts({ dataAccount: dataAccountPDA })
+      .rpc()
+    console.log("Your transaction signature", tx)
+
+    // Get the current state of the dataAccount.
+    const val = await program.methods
+      .get()
+      .accounts({ dataAccount: dataAccountPDA })
+      .view()
+
+    console.log("State:", val)
+  })
+})

+ 11 - 0
basics/program-derived-addresses/solang/tsconfig.json

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

+ 8 - 0
basics/rent/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 15 - 0
basics/rent/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+rent = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/rent/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 21 - 0
basics/rent/solang/solidity/rent.sol

@@ -0,0 +1,21 @@
+
+
+import "./system_instruction.sol";
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract rent {
+
+    @payer(payer) // The "payer" pays for the data account creation
+    constructor(address payer) {}
+
+    function createSystemAccount(address payer, address newAccount, uint64 lamports, uint64 space) public view {
+        SystemInstruction.create_account(
+            payer,        // lamports sent from this account (payer)
+            newAccount, // lamports sent to this account (account to be created)
+            lamports,      // lamport amount (minimum lamports required)
+            space,          // space required for the account
+            SystemInstruction.systemAddress // program owner (system program)
+        );
+    }
+
+}

+ 300 - 0
basics/rent/solang/solidity/system_instruction.sol

@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: Apache-2.0
+
+// Disclaimer: This library provides a bridge for Solidity to interact with Solana's system instructions. Although it is production ready,
+// it has not been audited for security, so use it at your own risk.
+
+import 'solana';
+
+library SystemInstruction {
+    address constant systemAddress = address"11111111111111111111111111111111";
+    address constant recentBlockHashes = address"SysvarRecentB1ockHashes11111111111111111111";
+    address constant rentAddress = address"SysvarRent111111111111111111111111111111111";
+    uint64 constant state_size = 80;
+
+    enum Instruction {
+        CreateAccount,
+        Assign,
+        Transfer,
+        CreateAccountWithSeed,
+        AdvanceNounceAccount,
+        WithdrawNonceAccount,
+        InitializeNonceAccount,
+        AuthorizeNonceAccount,
+        Allocate,
+        AllocateWithSeed,
+        AssignWithSeed,
+        TransferWithSeed,
+        UpgradeNonceAccount // This is not available on Solana v1.9.15
+    }
+
+    /// Create a new account on Solana
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param to public key for the account to be created
+    /// @param lamports amount of lamports to be transfered to the new account
+    /// @param space the size in bytes that is going to be made available for the account
+    /// @param owner public key for the program that will own the account being created
+    function create_account(address from, address to, uint64 lamports, uint64 space, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: true, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.CreateAccount), lamports, space, owner);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new account on Solana using a public key derived from a seed
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param to the public key for the account to be created. The public key must match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'to' address using the seed
+    /// @param seed the string utilized to created the 'to' public key
+    /// @param lamports amount of lamports to be transfered to the new account
+    /// @param space the size in bytes that is going to be made available for the account
+    /// @param owner public key for the program that will own the account being created
+    function create_account_with_seed(address from, address to, address base, string seed, uint64 lamports, uint64 space, address owner) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+        uint32 buffer_size = 92 + seed.length;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.CreateAccountWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(uint64(seed.length), 36);
+        bincode.writeString(seed, 44);
+        uint32 offset = seed.length + 44;
+        bincode.writeUint64LE(lamports, offset);
+        offset += 8;
+        bincode.writeUint64LE(space, offset);
+        offset += 8;
+        bincode.writeAddress(owner, offset);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Assign account to a program (owner)
+    ///
+    /// @param pubkey the public key for the account whose owner is going to be reassigned
+    /// @param owner the public key for the new account owner
+    function assign(address pubkey, address owner) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: pubkey, is_signer: true, is_writable: true})
+        ];
+        bytes bincode = abi.encode(uint32(Instruction.Assign), owner);
+
+        systemAddress.call{accounts: meta}(bincode);
+    }
+
+    /// Assign account to a program (owner) based on a seed
+    ///
+    /// @param addr the public key for the account whose owner is going to be reassigned. The public key must match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'addr' key using the seed
+    /// @param seed the string utilized to created the 'addr' public key
+    /// @param owner the public key for the new program owner
+    function assign_with_seed(address addr, address base, string seed, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: addr, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+
+        uint32 buffer_size = 76 + seed.length;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.AssignWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(uint64(seed.length), 36);
+        bincode.writeString(seed, 44);
+        bincode.writeAddress(owner, 44 + seed.length);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Transfer lamports between accounts
+    ///
+    /// @param from public key for the funding account
+    /// @param to public key for the recipient account
+    /// @param lamports amount of lamports to transfer
+    function transfer(address from, address to, uint64 lamports) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: false, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.Transfer), lamports);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Transfer lamports from a derived address
+    ///
+    /// @param from_pubkey The funding account public key. It should match create_with_seed(from_base, seed, from_owner)
+    /// @param from_base the base address that derived the 'from_pubkey' key using the seed
+    /// @param seed the string utilized to create the 'from_pubkey' public key
+    /// @param from_owner owner to use to derive the funding account address
+    /// @param to_pubkey the public key for the recipient account
+    /// @param lamports amount of lamports to transfer
+    function transfer_with_seed(address from_pubkey, address from_base, string seed, address from_owner, address to_pubkey, uint64 lamports) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: from_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: from_base, is_signer: true, is_writable: false}),
+            AccountMeta({pubkey: to_pubkey, is_signer: false, is_writable: true})
+        ];
+
+        uint32 buffer_size = seed.length + 52;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.TransferWithSeed), 0);
+        bincode.writeUint64LE(lamports, 4);
+        bincode.writeUint64LE(seed.length, 12);
+        bincode.writeString(seed, 20);
+        bincode.writeAddress(from_owner, 20 + seed.length);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Allocate space in a (possibly new) account without funding
+    ///
+    /// @param pub_key account for which to allocate space
+    /// @param space number of bytes of memory to allocate
+    function allocate(address pub_key, uint64 space) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: pub_key, is_signer: true, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.Allocate), space);
+
+        systemAddress.call{accounts: meta}(bincode);
+    }
+
+    /// Allocate space for an assign an account at an address derived from a base public key and a seed
+    ///
+    /// @param addr account for which to allocate space. It should match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'addr' key using the seed
+    /// @param seed the string utilized to create the 'addr' public key
+    /// @param space number of bytes of memory to allocate
+    /// @param owner owner to use to derive the 'addr' account address
+    function allocate_with_seed(address addr, address base, string seed, uint64 space, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: addr, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = new bytes(seed.length + 84);
+        bincode.writeUint32LE(uint32(Instruction.AllocateWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(seed.length, 36);
+        bincode.writeString(seed, 44);
+        uint32 offset = 44 + seed.length;
+        bincode.writeUint64LE(space, offset);
+        offset += 8;
+        bincode.writeAddress(owner, offset);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new nonce account on Solana using a public key derived from a seed
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param nonce the public key for the account to be created. The public key must match create_with_seed(base, seed, systemAddress)
+    /// @param base the base address that derived the 'nonce' key using the seed
+    /// @param seed the string utilized to create the 'addr' public key
+    /// @param authority The entity authorized to execute nonce instructions on the account
+    /// @param lamports amount of lamports to be transfered to the new account
+    function create_nonce_account_with_seed(address from, address nonce, address base, string seed, address authority, uint64 lamports) internal view {
+        create_account_with_seed(from, nonce, base, seed, lamports, state_size, systemAddress);
+
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.InitializeNonceAccount), authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new account on Solana
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param nonce the public key for the nonce account to be created
+    /// @param authority The entity authorized to execute nonce instructions on the account
+    /// @param lamports amount of lamports to be transfered to the new account
+    function create_nonce_account(address from, address nonce, address authority, uint64 lamports) internal view {
+        create_account(from, nonce, lamports, state_size, systemAddress);
+
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.InitializeNonceAccount), authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Consumes a stored nonce, replacing it with a successor
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the publick key for the entity authorized to execute instructins on the account
+    function advance_nonce_account(address nonce_pubkey, address authorized_pubkey) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.AdvanceNounceAccount));
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Withdraw funds from a nonce account
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the public key for the entity authorized to execute instructins on the account
+    /// @param to_pubkey the recipient account
+    /// @param lamports the number of lamports to withdraw
+    function withdraw_nonce_account(address nonce_pubkey, address authorized_pubkey, address to_pubkey, uint64 lamports) internal view {
+        AccountMeta[5] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: to_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.WithdrawNonceAccount), lamports);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Change the entity authorized to execute nonce instructions on the account
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the public key for the entity authorized to execute instructins on the account
+    /// @param new_authority
+    function authorize_nonce_account(address nonce_pubkey, address authorized_pubkey, address new_authority) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.AuthorizeNonceAccount), new_authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// One-time idempotent upgrade of legacy nonce version in order to bump them out of chain domain.
+    ///
+    /// @param nonce the public key for the nonce account
+    // This is not available on Solana v1.9.15
+    function upgrade_nonce_account(address nonce) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.UpgradeNonceAccount));
+        systemAddress.call{accounts: meta}(bincode);
+    }
+}

+ 60 - 0
basics/rent/solang/tests/rent.ts

@@ -0,0 +1,60 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { Rent } from "../target/types/rent"
+
+describe("rent", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate a new keypair for the data account for the program
+  const dataAccount = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet
+  const connection = provider.connection
+
+  const program = anchor.workspace.Rent as Program<Rent>
+
+  it("Is initialized!", async () => {
+    // Initialize data account for the program, which is required by Solang
+    const tx = await program.methods
+      .new(wallet.publicKey)
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([dataAccount])
+      .rpc()
+    console.log("Your transaction signature", tx)
+  })
+
+  it("Create new account", async () => {
+    // Generate a new keypair for the new account
+    const newAccount = anchor.web3.Keypair.generate()
+    // Number of bytes of space to allocate for the account
+    const space = 100
+    // Get the minimum balance required for the account for the given space
+    const lamports = await connection.getMinimumBalanceForRentExemption(space)
+
+    // Create a new account via a Cross Program Invocation to the system program
+    const tx = await program.methods
+      .createSystemAccount(
+        wallet.publicKey, // payer
+        newAccount.publicKey, // new account
+        new anchor.BN(lamports), // lamports
+        new anchor.BN(space) // space
+      )
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([newAccount]) // new account keypair required as signer
+      .remainingAccounts([
+        {
+          pubkey: wallet.publicKey,
+          isWritable: true,
+          isSigner: true,
+        },
+        {
+          pubkey: newAccount.publicKey, // new account
+          isWritable: true,
+          isSigner: true,
+        },
+      ])
+      .rpc()
+    console.log("Your transaction signature", tx)
+  })
+})

+ 11 - 0
basics/rent/solang/tsconfig.json

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

+ 8 - 0
basics/transfer-sol/solang/.gitignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger
+.yarn

+ 8 - 0
basics/transfer-sol/solang/.prettierignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+node_modules
+dist
+build
+test-ledger

+ 15 - 0
basics/transfer-sol/solang/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+transfer_sol = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 19 - 0
basics/transfer-sol/solang/package.json

@@ -0,0 +1,19 @@
+{
+    "scripts": {
+        "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
+        "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
+    },
+    "dependencies": {
+        "@coral-xyz/anchor": "^0.28.0"
+    },
+    "devDependencies": {
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "typescript": "^4.3.5",
+        "prettier": "^2.6.2"
+    }
+}

+ 300 - 0
basics/transfer-sol/solang/solidity/system_instruction.sol

@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: Apache-2.0
+
+// Disclaimer: This library provides a bridge for Solidity to interact with Solana's system instructions. Although it is production ready,
+// it has not been audited for security, so use it at your own risk.
+
+import 'solana';
+
+library SystemInstruction {
+    address constant systemAddress = address"11111111111111111111111111111111";
+    address constant recentBlockHashes = address"SysvarRecentB1ockHashes11111111111111111111";
+    address constant rentAddress = address"SysvarRent111111111111111111111111111111111";
+    uint64 constant state_size = 80;
+
+    enum Instruction {
+        CreateAccount,
+        Assign,
+        Transfer,
+        CreateAccountWithSeed,
+        AdvanceNounceAccount,
+        WithdrawNonceAccount,
+        InitializeNonceAccount,
+        AuthorizeNonceAccount,
+        Allocate,
+        AllocateWithSeed,
+        AssignWithSeed,
+        TransferWithSeed,
+        UpgradeNonceAccount // This is not available on Solana v1.9.15
+    }
+
+    /// Create a new account on Solana
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param to public key for the account to be created
+    /// @param lamports amount of lamports to be transfered to the new account
+    /// @param space the size in bytes that is going to be made available for the account
+    /// @param owner public key for the program that will own the account being created
+    function create_account(address from, address to, uint64 lamports, uint64 space, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: true, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.CreateAccount), lamports, space, owner);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new account on Solana using a public key derived from a seed
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param to the public key for the account to be created. The public key must match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'to' address using the seed
+    /// @param seed the string utilized to created the 'to' public key
+    /// @param lamports amount of lamports to be transfered to the new account
+    /// @param space the size in bytes that is going to be made available for the account
+    /// @param owner public key for the program that will own the account being created
+    function create_account_with_seed(address from, address to, address base, string seed, uint64 lamports, uint64 space, address owner) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+        uint32 buffer_size = 92 + seed.length;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.CreateAccountWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(uint64(seed.length), 36);
+        bincode.writeString(seed, 44);
+        uint32 offset = seed.length + 44;
+        bincode.writeUint64LE(lamports, offset);
+        offset += 8;
+        bincode.writeUint64LE(space, offset);
+        offset += 8;
+        bincode.writeAddress(owner, offset);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Assign account to a program (owner)
+    ///
+    /// @param pubkey the public key for the account whose owner is going to be reassigned
+    /// @param owner the public key for the new account owner
+    function assign(address pubkey, address owner) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: pubkey, is_signer: true, is_writable: true})
+        ];
+        bytes bincode = abi.encode(uint32(Instruction.Assign), owner);
+
+        systemAddress.call{accounts: meta}(bincode);
+    }
+
+    /// Assign account to a program (owner) based on a seed
+    ///
+    /// @param addr the public key for the account whose owner is going to be reassigned. The public key must match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'addr' key using the seed
+    /// @param seed the string utilized to created the 'addr' public key
+    /// @param owner the public key for the new program owner
+    function assign_with_seed(address addr, address base, string seed, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: addr, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+
+        uint32 buffer_size = 76 + seed.length;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.AssignWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(uint64(seed.length), 36);
+        bincode.writeString(seed, 44);
+        bincode.writeAddress(owner, 44 + seed.length);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Transfer lamports between accounts
+    ///
+    /// @param from public key for the funding account
+    /// @param to public key for the recipient account
+    /// @param lamports amount of lamports to transfer
+    function transfer(address from, address to, uint64 lamports) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: from, is_signer: true, is_writable: true}),
+            AccountMeta({pubkey: to, is_signer: false, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.Transfer), lamports);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Transfer lamports from a derived address
+    ///
+    /// @param from_pubkey The funding account public key. It should match create_with_seed(from_base, seed, from_owner)
+    /// @param from_base the base address that derived the 'from_pubkey' key using the seed
+    /// @param seed the string utilized to create the 'from_pubkey' public key
+    /// @param from_owner owner to use to derive the funding account address
+    /// @param to_pubkey the public key for the recipient account
+    /// @param lamports amount of lamports to transfer
+    function transfer_with_seed(address from_pubkey, address from_base, string seed, address from_owner, address to_pubkey, uint64 lamports) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: from_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: from_base, is_signer: true, is_writable: false}),
+            AccountMeta({pubkey: to_pubkey, is_signer: false, is_writable: true})
+        ];
+
+        uint32 buffer_size = seed.length + 52;
+        bytes bincode = new bytes(buffer_size);
+        bincode.writeUint32LE(uint32(Instruction.TransferWithSeed), 0);
+        bincode.writeUint64LE(lamports, 4);
+        bincode.writeUint64LE(seed.length, 12);
+        bincode.writeString(seed, 20);
+        bincode.writeAddress(from_owner, 20 + seed.length);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Allocate space in a (possibly new) account without funding
+    ///
+    /// @param pub_key account for which to allocate space
+    /// @param space number of bytes of memory to allocate
+    function allocate(address pub_key, uint64 space) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: pub_key, is_signer: true, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.Allocate), space);
+
+        systemAddress.call{accounts: meta}(bincode);
+    }
+
+    /// Allocate space for an assign an account at an address derived from a base public key and a seed
+    ///
+    /// @param addr account for which to allocate space. It should match create_with_seed(base, seed, owner)
+    /// @param base the base address that derived the 'addr' key using the seed
+    /// @param seed the string utilized to create the 'addr' public key
+    /// @param space number of bytes of memory to allocate
+    /// @param owner owner to use to derive the 'addr' account address
+    function allocate_with_seed(address addr, address base, string seed, uint64 space, address owner) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: addr, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: base, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = new bytes(seed.length + 84);
+        bincode.writeUint32LE(uint32(Instruction.AllocateWithSeed), 0);
+        bincode.writeAddress(base, 4);
+        bincode.writeUint64LE(seed.length, 36);
+        bincode.writeString(seed, 44);
+        uint32 offset = 44 + seed.length;
+        bincode.writeUint64LE(space, offset);
+        offset += 8;
+        bincode.writeAddress(owner, offset);
+
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new nonce account on Solana using a public key derived from a seed
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param nonce the public key for the account to be created. The public key must match create_with_seed(base, seed, systemAddress)
+    /// @param base the base address that derived the 'nonce' key using the seed
+    /// @param seed the string utilized to create the 'addr' public key
+    /// @param authority The entity authorized to execute nonce instructions on the account
+    /// @param lamports amount of lamports to be transfered to the new account
+    function create_nonce_account_with_seed(address from, address nonce, address base, string seed, address authority, uint64 lamports) internal view {
+        create_account_with_seed(from, nonce, base, seed, lamports, state_size, systemAddress);
+
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.InitializeNonceAccount), authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Create a new account on Solana
+    ///
+    /// @param from public key for the account from which to transfer lamports to the new account
+    /// @param nonce the public key for the nonce account to be created
+    /// @param authority The entity authorized to execute nonce instructions on the account
+    /// @param lamports amount of lamports to be transfered to the new account
+    function create_nonce_account(address from, address nonce, address authority, uint64 lamports) internal view {
+        create_account(from, nonce, lamports, state_size, systemAddress);
+
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.InitializeNonceAccount), authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Consumes a stored nonce, replacing it with a successor
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the publick key for the entity authorized to execute instructins on the account
+    function advance_nonce_account(address nonce_pubkey, address authorized_pubkey) internal view {
+        AccountMeta[3] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.AdvanceNounceAccount));
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Withdraw funds from a nonce account
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the public key for the entity authorized to execute instructins on the account
+    /// @param to_pubkey the recipient account
+    /// @param lamports the number of lamports to withdraw
+    function withdraw_nonce_account(address nonce_pubkey, address authorized_pubkey, address to_pubkey, uint64 lamports) internal view {
+        AccountMeta[5] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: to_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: recentBlockHashes, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: rentAddress, is_signer: false, is_writable: false}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.WithdrawNonceAccount), lamports);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// Change the entity authorized to execute nonce instructions on the account
+    ///
+    /// @param nonce_pubkey the public key for the nonce account
+    /// @param authorized_pubkey the public key for the entity authorized to execute instructins on the account
+    /// @param new_authority
+    function authorize_nonce_account(address nonce_pubkey, address authorized_pubkey, address new_authority) internal view {
+        AccountMeta[2] metas = [
+            AccountMeta({pubkey: nonce_pubkey, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: authorized_pubkey, is_signer: true, is_writable: false})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.AuthorizeNonceAccount), new_authority);
+        systemAddress.call{accounts: metas}(bincode);
+    }
+
+    /// One-time idempotent upgrade of legacy nonce version in order to bump them out of chain domain.
+    ///
+    /// @param nonce the public key for the nonce account
+    // This is not available on Solana v1.9.15
+    function upgrade_nonce_account(address nonce) internal view {
+        AccountMeta[1] meta = [
+            AccountMeta({pubkey: nonce, is_signer: false, is_writable: true})
+        ];
+
+        bytes bincode = abi.encode(uint32(Instruction.UpgradeNonceAccount));
+        systemAddress.call{accounts: meta}(bincode);
+    }
+}

+ 30 - 0
basics/transfer-sol/solang/solidity/transfer-sol.sol

@@ -0,0 +1,30 @@
+
+import "./system_instruction.sol";
+
+@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")
+contract transfer_sol {
+
+    @payer(payer) // payer to create new data account
+    constructor(address payer) {
+        // No data is stored in the account in this example
+    }
+
+    // Transfer SOL from one account to another using CPI (Cross Program Invocation) to the System program
+    function transferSolWithCpi(address from, address to, uint64 lamports) public view {
+        // CPI to transfer SOL using "system_instruction" library
+        SystemInstruction.transfer(from, to, lamports);
+    }
+
+    // Transfer SOL from program owned account to another address by directly modifying the account data lamports
+    // This approach only works for accounts owned by the program itself (ex. the dataAccount created in the constructor)
+    function transferSolWithProgram(uint64 lamports) public {
+        AccountInfo from = tx.accounts[0]; // first account must be an account owned by the program
+        AccountInfo to = tx.accounts[1]; // second account must be the intended recipient
+
+        print("From: {:}".format(from.key));
+        print("To: {:}".format(to.key));
+
+        from.lamports -= lamports;
+        to.lamports += lamports;
+    }
+}

+ 129 - 0
basics/transfer-sol/solang/tests/transfer-sol.ts

@@ -0,0 +1,129 @@
+import * as anchor from "@coral-xyz/anchor"
+import { Program } from "@coral-xyz/anchor"
+import { TransferSol } from "../target/types/transfer_sol"
+import { PublicKey } from "@solana/web3.js"
+
+describe("transfer-sol", () => {
+  // Configure the client to use the local cluster.
+  const provider = anchor.AnchorProvider.env()
+  anchor.setProvider(provider)
+
+  // Generate new keypair to use as data account
+  const dataAccount = anchor.web3.Keypair.generate()
+  const wallet = provider.wallet
+  const connection = provider.connection
+
+  const program = anchor.workspace.TransferSol as Program<TransferSol>
+
+  // Amount to transfer in lamports
+  const transferAmount = 1 * anchor.web3.LAMPORTS_PER_SOL // 1 SOL
+
+  it("Is initialized!", async () => {
+    // Create the new data account
+    // The dataAccount is required by Solang even though it is not use in the transfer instruction
+    const tx = await program.methods
+      .new(wallet.publicKey) // payer
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .signers([dataAccount])
+      .rpc()
+    console.log("Your transaction signature", tx)
+  })
+
+  it("Transfer SOL using CPI to the system program", async () => {
+    // Generate new keypair to use as recipient for the transfer
+    const recipient = anchor.web3.Keypair.generate() // test1 recipient
+
+    await getBalances(wallet.publicKey, recipient.publicKey, "Beginning")
+
+    const tx = await program.methods
+      .transferSolWithCpi(
+        wallet.publicKey, // sender
+        recipient.publicKey, // recipient
+        new anchor.BN(transferAmount) // amount in lamports
+      )
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .remainingAccounts([
+        {
+          pubkey: wallet.publicKey, // sender
+          isWritable: true,
+          isSigner: true,
+        },
+        {
+          pubkey: recipient.publicKey, // recipient
+          isWritable: true,
+          isSigner: false,
+        },
+      ])
+      .rpc()
+
+    await getBalances(wallet.publicKey, recipient.publicKey, "Resulting")
+
+    console.log("Your transaction signature", tx)
+  })
+
+  it("Transfer SOL to program owned account", async () => {
+    await getBalances(wallet.publicKey, dataAccount.publicKey, "Beginning")
+
+    const tx = await program.methods
+      .transferSolWithCpi(
+        wallet.publicKey, // sender
+        dataAccount.publicKey, // recipient
+        new anchor.BN(transferAmount) // amount in lamports
+      )
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .remainingAccounts([
+        {
+          pubkey: wallet.publicKey, // sender
+          isWritable: true,
+          isSigner: true,
+        },
+        {
+          pubkey: dataAccount.publicKey, // recipient
+          isWritable: true,
+          isSigner: false,
+        },
+      ])
+      .rpc()
+
+    await getBalances(wallet.publicKey, dataAccount.publicKey, "Resulting")
+
+    console.log("Your transaction signature", tx)
+  })
+
+  it("Transfer SOL from program owned account", async () => {
+    await getBalances(dataAccount.publicKey, wallet.publicKey, "Beginning")
+
+    const tx = await program.methods
+      .transferSolWithProgram(
+        new anchor.BN(transferAmount) // amount in lamports
+      )
+      .accounts({ dataAccount: dataAccount.publicKey })
+      .remainingAccounts([
+        {
+          pubkey: wallet.publicKey, // recipient
+          isWritable: true,
+          isSigner: true,
+        },
+      ])
+      .rpc()
+
+    await getBalances(dataAccount.publicKey, wallet.publicKey, "Resulting")
+
+    console.log("Your transaction signature", tx)
+  })
+
+  // Helper function to get balances and log them to the console
+  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 / anchor.web3.LAMPORTS_PER_SOL}`) // convert lamports to SOL
+    console.log(
+      `   Recipient: ${recipientBalance / anchor.web3.LAMPORTS_PER_SOL}` // convert lamports to SOL
+    )
+  }
+})

+ 11 - 0
basics/transfer-sol/solang/tsconfig.json

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