Pārlūkot izejas kodu

Add interface scripts (#17)

* [wip] Add interface crate

* [wip] Add missing features

* [wip] Add wasm

* Add dev dependencies

* Update rust renderer

* Address review comments

* Update lock file

* Fix dependencies

* Switch crates version

* Remove serde feature

* Add interface scripts

* Enable CI on all branches

* Add rust toolchain option

* Fix clippy args

* Refactor rust toolchain

* Replace interface build for test

* Fix step name

* Fix test script call

* Address review comments

* Remove duplicate

* Fix rustdoc tests

* Fix lock file

* Add missing dependency

* Add missing feature dependency
Fernando Otero 1 gadu atpakaļ
vecāks
revīzija
53e46675e1

+ 18 - 9
.github/actions/setup/action.yml

@@ -10,11 +10,8 @@ inputs:
   cargo-cache-local-key:
     description: The key to cache local cargo dependencies. Skips local cargo caching if not provided.
     required: false
-  clippy:
-    description: Install Clippy if `true`. Defaults to `false`.
-    required: false
-  rustfmt:
-    description: Install Rustfmt if `true`. Defaults to `false`.
+  toolchain:
+    description: Rust toolchain to install. Comma-separated string of [`build`, `format`, `lint`, `test`].
     required: false
   solana:
     description: Install Solana if `true`. Defaults to `false`.
@@ -40,20 +37,32 @@ runs:
       shell: bash
       run: pnpm zx ./scripts/ci/set-env.mjs
 
-    - name: Install Rustfmt
-      if: ${{ inputs.rustfmt == 'true' }}
+    - name: Install Rust 'build' Toolchain
+      if: ${{ contains(inputs.toolchain, 'build') }}
+      uses: dtolnay/rust-toolchain@master
+      with:
+        toolchain: ${{ env.TOOLCHAIN_BUILD }}
+
+    - name: Install Rust 'format' Toolchain
+      if: ${{ contains(inputs.toolchain, 'format') }}
       uses: dtolnay/rust-toolchain@master
       with:
         toolchain: ${{ env.TOOLCHAIN_FORMAT }}
         components: rustfmt
 
-    - name: Install Clippy
-      if: ${{ inputs.clippy == 'true' }}
+    - name: Install Rust 'lint' Toolchain
+      if: ${{ contains(inputs.toolchain, 'lint') }}
       uses: dtolnay/rust-toolchain@master
       with:
         toolchain: ${{ env.TOOLCHAIN_LINT }}
         components: clippy
 
+    - name: Install Rust 'test' Toolchain
+      if: ${{ contains(inputs.toolchain, 'test') }}
+      uses: dtolnay/rust-toolchain@master
+      with:
+        toolchain: ${{ env.TOOLCHAIN_TEST }}
+
     - name: Install Solana
       if: ${{ inputs.solana == 'true' }}
       uses: solana-program/actions/install-solana@v1

+ 38 - 4
.github/workflows/main.yml

@@ -4,7 +4,6 @@ on:
   push:
     branches: [main]
   pull_request:
-    branches: [main]
 
 jobs:
   format_and_lint_client_js:
@@ -33,8 +32,7 @@ jobs:
       - name: Setup Environment
         uses: ./.github/actions/setup
         with:
-          clippy: true
-          rustfmt: true
+          toolchain: format, lint
 
       - name: Format Client Rust
         run: pnpm clients:rust:format
@@ -42,6 +40,42 @@ jobs:
       - name: Lint Client Rust
         run: pnpm clients:rust:lint
 
+  format_and_lint_interface:
+    name: Format & Lint Interface
+    runs-on: ubuntu-latest
+    steps:
+      - name: Git Checkout
+        uses: actions/checkout@v4
+
+      - name: Setup Environment
+        uses: ./.github/actions/setup
+        with:
+          toolchain: format, lint
+
+      - name: Format Interface
+        run: pnpm interface:format
+
+      - name: Lint Interface
+        run: pnpm interface:lint
+
+  test_interface:
+    name: Test Interface
+    runs-on: ubuntu-latest
+    needs: format_and_lint_interface
+    steps:
+      - name: Git Checkout
+        uses: actions/checkout@v4
+
+      - name: Setup Environment
+        uses: ./.github/actions/setup
+        with:
+          toolchain: test
+          cargo-cache-key: cargo-interface
+          solana: true
+
+      - name: Test Interface
+        run: pnpm interface:test
+
   generate_clients:
     name: Check Client Generation
     runs-on: ubuntu-latest
@@ -52,7 +86,7 @@ jobs:
       - name: Setup Environment
         uses: ./.github/actions/setup
         with:
-          rustfmt: true
+          toolchain: format
 
       - name: Generate Clients
         run: pnpm generate:clients

+ 181 - 66
Cargo.lock

@@ -4,13 +4,23 @@ version = 3
 
 [[package]]
 name = "ahash"
-version = "0.7.8"
+version = "0.8.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
 dependencies = [
- "getrandom 0.2.15",
+ "cfg-if",
  "once_cell",
  "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
 ]
 
 [[package]]
@@ -30,9 +40,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.90"
+version = "1.0.93"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95"
+checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
 
 [[package]]
 name = "arrayref"
@@ -46,6 +56,17 @@ version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
 
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.4.0"
@@ -127,16 +148,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee"
 dependencies = [
  "borsh-derive 0.10.4",
- "hashbrown 0.12.3",
+ "hashbrown 0.13.2",
 ]
 
 [[package]]
 name = "borsh"
-version = "1.5.1"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed"
+checksum = "f5327f6c99920069d1fe374aa743be1af0031dea9f250852cdf1ae6a0861ee24"
 dependencies = [
- "borsh-derive 1.5.1",
+ "borsh-derive 1.5.2",
  "cfg_aliases",
 ]
 
@@ -155,16 +176,15 @@ dependencies = [
 
 [[package]]
 name = "borsh-derive"
-version = "1.5.1"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b"
+checksum = "10aedd8f1a81a8aafbfde924b0e3061cd6fedd6f6bbcfc6a76e6fd426d7bfe26"
 dependencies = [
  "once_cell",
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
  "syn 2.0.87",
- "syn_derive",
 ]
 
 [[package]]
@@ -239,9 +259,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.1.30"
+version = "1.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
+checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf"
 dependencies = [
  "shlex",
 ]
@@ -305,9 +325,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
+checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
 dependencies = [
  "libc",
 ]
@@ -452,6 +472,19 @@ version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
 
+[[package]]
+name = "env_logger"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
 [[package]]
 name = "equivalent"
 version = "1.0.1"
@@ -531,15 +564,21 @@ name = "hashbrown"
 version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
 dependencies = [
  "ahash",
 ]
 
 [[package]]
 name = "hashbrown"
-version = "0.15.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
 
 [[package]]
 name = "heck"
@@ -547,12 +586,27 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "hex"
 version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
 [[package]]
 name = "iana-time-zone"
 version = "0.1.61"
@@ -616,7 +670,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
 dependencies = [
  "equivalent",
- "hashbrown 0.15.0",
+ "hashbrown 0.15.1",
  "serde",
 ]
 
@@ -662,9 +716,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.161"
+version = "0.2.162"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
 
 [[package]]
 name = "libsecp256k1"
@@ -876,29 +930,6 @@ dependencies = [
  "toml_edit",
 ]
 
-[[package]]
-name = "proc-macro-error"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
-dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
-dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
-]
-
 [[package]]
 name = "proc-macro2"
 version = "1.0.89"
@@ -1026,6 +1057,35 @@ dependencies = [
  "bitflags",
 ]
 
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
 [[package]]
 name = "rustc_version"
 version = "0.4.1"
@@ -1226,7 +1286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a5d526f3525ab22a3ada3f9a1d642664dafac00dc9208326b701a2045514eb04"
 dependencies = [
  "borsh 0.10.4",
- "borsh 1.5.1",
+ "borsh 1.5.2",
 ]
 
 [[package]]
@@ -1328,7 +1388,7 @@ version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1807bc4e9e1d25271514167d5a1e698ce5a330bce547a368242dd63b355b5faa"
 dependencies = [
- "borsh 1.5.1",
+ "borsh 1.5.2",
  "bs58",
  "bytemuck",
  "bytemuck_derive",
@@ -1347,7 +1407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfef689e06e5c7cb6206d4dc61ac77733de4f72d754e0d531393206abc27dbe4"
 dependencies = [
  "bincode",
- "borsh 1.5.1",
+ "borsh 1.5.2",
  "getrandom 0.2.15",
  "js-sys",
  "num-traits",
@@ -1369,6 +1429,17 @@ dependencies = [
  "solana-sdk-macro",
 ]
 
+[[package]]
+name = "solana-logger"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "367c5431bad14b10fbb62614b48720b746672558dba3244167ff7d251890c355"
+dependencies = [
+ "env_logger",
+ "lazy_static",
+ "log",
+]
+
 [[package]]
 name = "solana-msg"
 version = "2.1.0"
@@ -1407,7 +1478,7 @@ dependencies = [
  "bitflags",
  "blake3",
  "borsh 0.10.4",
- "borsh 1.5.1",
+ "borsh 1.5.2",
  "bs58",
  "bv",
  "bytemuck",
@@ -1486,7 +1557,7 @@ version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd089caeef26dd07bd12b7b67d45e92faddc2fc67a960f316df7ae4776a2f3d5"
 dependencies = [
- "borsh 1.5.1",
+ "borsh 1.5.2",
  "num-traits",
  "serde",
  "serde_derive",
@@ -1528,7 +1599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bea3215775fcedf200d47590c7e2ce9a3a46bc2b7d3f77d0eae9c6edf0a39aec"
 dependencies = [
  "borsh 0.10.4",
- "borsh 1.5.1",
+ "borsh 1.5.2",
  "bs58",
  "bytemuck",
  "bytemuck_derive",
@@ -1542,6 +1613,8 @@ dependencies = [
  "solana-atomic-u64",
  "solana-decode-error",
  "solana-define-syscall",
+ "solana-frozen-abi",
+ "solana-frozen-abi-macro",
  "solana-sanitize",
  "solana-sha256-hasher",
  "wasm-bindgen",
@@ -1678,17 +1751,22 @@ name = "solana-system-interface"
 version = "0.0.1"
 dependencies = [
  "anyhow",
- "borsh 1.5.1",
+ "borsh 1.5.2",
  "js-sys",
  "num-traits",
  "serde",
  "serde_derive",
+ "solana-account-info",
+ "solana-cpi",
  "solana-decode-error",
  "solana-frozen-abi",
  "solana-frozen-abi-macro",
  "solana-instruction",
+ "solana-logger",
  "solana-nonce",
  "solana-program",
+ "solana-program-entrypoint",
+ "solana-program-error",
  "solana-pubkey",
  "static_assertions",
  "strum",
@@ -1739,9 +1817,9 @@ dependencies = [
 
 [[package]]
 name = "subtle"
-version = "2.4.1"
+version = "2.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
 
 [[package]]
 name = "syn"
@@ -1766,31 +1844,28 @@ dependencies = [
 ]
 
 [[package]]
-name = "syn_derive"
-version = "0.1.8"
+name = "termcolor"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
 dependencies = [
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 2.0.87",
+ "winapi-util",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.68"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.68"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1964,6 +2039,37 @@ dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
 [[package]]
 name = "windows-core"
 version = "0.52.0"
@@ -1973,6 +2079,15 @@ dependencies = [
  "windows-targets",
 ]
 
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
 [[package]]
 name = "windows-targets"
 version = "0.52.6"
@@ -2069,6 +2184,6 @@ dependencies = [
 
 [[package]]
 name = "zeroize"
-version = "1.3.0"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"

+ 1 - 0
Cargo.toml

@@ -8,3 +8,4 @@ solana = "2.1.0"
 [workspace.metadata.toolchains]
 format = "nightly-2024-08-08"
 lint = "nightly-2024-08-08"
+test = "nightly-2024-08-08"

+ 8 - 1
interface/Cargo.toml

@@ -20,6 +20,7 @@ solana-decode-error = "^2.1"
 solana-frozen-abi = { version = "^2.1", features = ["frozen-abi"], optional = true }
 solana-frozen-abi-macro = { version = "^2.1", features = ["frozen-abi"], optional = true }
 solana-instruction = { version = "^2.1", features = ["bincode", "std"] }
+solana-logger = { version = "^2.1", optional = true }
 solana-pubkey = { version = "^2.1", default-features = false, features = ["serde"] }
 
 [target.'cfg(target_arch = "wasm32")'.dependencies]
@@ -29,8 +30,12 @@ wasm-bindgen = "0.2"
 [dev-dependencies]
 anyhow = "1.0.89"
 borsh = { version = "1.5.1", features = ["derive", "unstable__schema"] }
+solana-account-info = "^2.1"
+solana-cpi = "^2.1"
 solana-nonce = "^0.0.2"
 solana-program = { version = "^2.1", default-features = false }
+solana-program-entrypoint = "^2.1"
+solana-program-error = { version = "^2.1", features = ["borsh"] }
 static_assertions = "1.1.0"
 strum = "0.24"
 strum_macros = "0.24"
@@ -38,5 +43,7 @@ strum_macros = "0.24"
 [features]
 frozen-abi = [
     "dep:solana-frozen-abi",
-    "dep:solana-frozen-abi-macro"
+    "dep:solana-frozen-abi-macro",
+    "dep:solana-logger",
+    "solana-pubkey/frozen-abi"
 ]

+ 18 - 15
interface/src/instruction.rs

@@ -314,7 +314,7 @@ pub enum SystemInstruction {
 /// use borsh::{BorshDeserialize, BorshSerialize};
 /// use solana_account_info::{next_account_info, AccountInfo};
 /// use solana_cpi::invoke_signed;
-/// use solana_program::sysvar::Sysvar;
+/// use solana_program::sysvar::{rent::Rent, Sysvar};
 /// use solana_program_entrypoint::entrypoint;
 /// use solana_program_error::ProgramResult;
 /// use solana_pubkey::Pubkey;
@@ -351,7 +351,7 @@ pub enum SystemInstruction {
 ///     // This program will sign for it via `invoke_signed`.
 ///     assert!(!new_account_pda.is_signer);
 ///     assert!(new_account_pda.is_writable);
-///     assert!(system_program::check_id(system_account.key));
+///     assert!(program::check_id(system_account.key));
 ///
 ///     let new_account_seed = &instr.new_account_seed;
 ///     let new_account_bump_seed = instr.new_account_bump_seed;
@@ -457,7 +457,7 @@ pub fn create_account_with_seed(
 /// ```
 /// # use solana_program::example_mocks::{solana_sdk, solana_rpc_client};
 /// use solana_rpc_client::rpc_client::RpcClient;
-/// use solana_pubkey::Pubkey
+/// use solana_pubkey::Pubkey;
 /// use solana_sdk::{
 ///     signature::{Keypair, Signer},
 ///     transaction::Transaction,
@@ -527,7 +527,7 @@ pub fn create_account_with_seed(
 /// use borsh::{BorshDeserialize, BorshSerialize};
 /// use solana_account_info::{next_account_info, AccountInfo};
 /// use solana_cpi::invoke_signed;
-/// use solana_program::sysvar::Sysvar;
+/// use solana_program::sysvar::{rent::Rent, Sysvar};
 /// use solana_program_entrypoint::entrypoint;
 /// use solana_program_error::ProgramResult;
 /// use solana_pubkey::Pubkey;
@@ -564,7 +564,7 @@ pub fn create_account_with_seed(
 ///     // This program will sign for it via `invoke_signed`.
 ///     assert!(!new_account_pda.is_signer);
 ///     assert!(new_account_pda.is_writable);
-///     assert!(system_program::check_id(system_account.key));
+///     assert!(program::check_id(system_account.key));
 ///
 ///     let new_account_seed = &instr.new_account_seed;
 ///     let new_account_bump_seed = instr.new_account_bump_seed;
@@ -648,7 +648,7 @@ pub fn assign_with_seed(
 /// ```
 /// # use solana_program::example_mocks::{solana_sdk, solana_rpc_client};
 /// use solana_rpc_client::rpc_client::RpcClient;
-/// use solana_pubkey::Pubkey
+/// use solana_pubkey::Pubkey;
 /// use solana_sdk::{
 ///     signature::{Keypair, Signer},
 ///     transaction::Transaction,
@@ -715,16 +715,17 @@ pub fn assign_with_seed(
 /// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
 ///
 /// ```
-/// use borsh::{BorshDeserialize, BorshSerialize};
+/// # use borsh::{BorshDeserialize, BorshSerialize};
 /// use solana_account_info::{next_account_info, AccountInfo};
 /// use solana_cpi::invoke_signed;
-/// use solana_program::sysvar::Sysvar;
+/// use solana_program::sysvar::{rent::Rent, Sysvar};
 /// use solana_program_entrypoint::entrypoint;
 /// use solana_program_error::ProgramResult;
 /// use solana_pubkey::Pubkey;
 /// use solana_system_interface::{instruction, program};
 ///
 /// #[derive(BorshSerialize, BorshDeserialize, Debug)]
+/// # #[borsh(crate = "borsh")]
 /// pub struct CreateAccountInstruction {
 ///     /// The PDA seed used to distinguish the new account from other PDAs
 ///     pub new_account_seed: [u8; 16],
@@ -755,7 +756,7 @@ pub fn assign_with_seed(
 ///     // This program will sign for it via `invoke_signed`.
 ///     assert!(!new_account_pda.is_signer);
 ///     assert!(new_account_pda.is_writable);
-///     assert!(system_program::check_id(system_account.key));
+///     assert!(program::check_id(system_account.key));
 ///
 ///     let new_account_seed = &instr.new_account_seed;
 ///     let new_account_bump_seed = instr.new_account_bump_seed;
@@ -844,7 +845,7 @@ pub fn transfer_with_seed(
 /// ```
 /// # use solana_program::example_mocks::{solana_sdk, solana_rpc_client};
 /// use solana_rpc_client::rpc_client::RpcClient;
-/// use solana_pubkey::Pubkey
+/// use solana_pubkey::Pubkey;
 /// use solana_sdk::{
 ///     signature::{Keypair, Signer},
 ///     transaction::Transaction,
@@ -914,7 +915,7 @@ pub fn transfer_with_seed(
 /// use borsh::{BorshDeserialize, BorshSerialize};
 /// use solana_account_info::{next_account_info, AccountInfo};
 /// use solana_cpi::invoke_signed;
-/// use solana_program::sysvar::Sysvar;
+/// use solana_program::sysvar::{rent::Rent, Sysvar};
 /// use solana_program_entrypoint::entrypoint;
 /// use solana_program_error::ProgramResult;
 /// use solana_pubkey::Pubkey;
@@ -951,7 +952,7 @@ pub fn transfer_with_seed(
 ///     // This program will sign for it via `invoke_signed`.
 ///     assert!(!new_account_pda.is_signer);
 ///     assert!(new_account_pda.is_writable);
-///     assert!(system_program::check_id(system_account.key));
+///     assert!(program::check_id(system_account.key));
 ///
 ///     let new_account_seed = &instr.new_account_seed;
 ///     let new_account_bump_seed = instr.new_account_bump_seed;
@@ -1082,7 +1083,7 @@ pub fn allocate_with_seed(
 /// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
 ///
 /// ```
-/// use borsh::{BorshDeserialize, BorshSerialize};
+/// # use borsh::{BorshDeserialize, BorshSerialize};
 /// use solana_account_info::{next_account_info, next_account_infos, AccountInfo};
 /// use solana_cpi::invoke_signed;
 /// use solana_program_entrypoint::entrypoint;
@@ -1095,7 +1096,8 @@ pub fn allocate_with_seed(
 /// /// - 0: bank_pda - writable
 /// /// - 1: system_program - executable
 /// /// - *: to - writable
-/// #[derive(BorshSerialize, BorshDeserialize, Debug)]
+/// # #[derive(BorshSerialize, BorshDeserialize, Debug)]
+/// # #[borsh(crate = "borsh")]
 /// pub struct TransferLamportsToManyInstruction {
 ///     pub bank_pda_bump_seed: u8,
 ///     pub amount_list: Vec<u64>,
@@ -1359,6 +1361,7 @@ pub fn create_nonce_account(
 /// # use solana_program::example_mocks::solana_sdk;
 /// # use solana_program::example_mocks::solana_rpc_client;
 /// # use solana_program::example_mocks::solana_rpc_client_nonce_utils;
+/// # use solana_sdk::account::Account;
 /// use solana_rpc_client::rpc_client::RpcClient;
 /// use solana_pubkey::Pubkey;
 /// use solana_sdk::{
@@ -1576,7 +1579,7 @@ pub fn withdraw_nonce_account(
 ///     new_authority_pubkey: &Pubkey,
 /// ) -> Result<()> {
 ///
-///     let instr = system_instruction::authorize_nonce_account(
+///     let instr = instruction::authorize_nonce_account(
 ///         nonce_account_pubkey,
 ///         &authorized_account.pubkey(),
 ///         new_authority_pubkey,

+ 3 - 0
package.json

@@ -16,6 +16,9 @@
     "clients:rust:lint": "zx ./scripts/client/lint-rust.mjs",
     "clients:rust:publish": "zx ./scripts/client/publish-rust.mjs",
     "clients:rust:test": "zx ./scripts/client/test-rust.mjs",
+    "interface:format": "zx ./scripts/interface/format.mjs",
+    "interface:lint": "zx ./scripts/interface/lint.mjs",
+    "interface:test": "zx ./scripts/interface/test.mjs",
     "template:upgrade": "zx ./scripts/upgrade-template.mjs"
   },
   "devDependencies": {

+ 2 - 0
scripts/ci/set-env.mjs

@@ -2,5 +2,7 @@
 import { getSolanaVersion, getToolchain } from '../utils.mjs';
 
 await $`echo "SOLANA_VERSION=${getSolanaVersion()}" >> $GITHUB_ENV`;
+await $`echo "TOOLCHAIN_BUILD=${getToolchain('build')}" >> $GITHUB_ENV`;
 await $`echo "TOOLCHAIN_FORMAT=${getToolchain('format')}" >> $GITHUB_ENV`;
 await $`echo "TOOLCHAIN_LINT=${getToolchain('lint')}" >> $GITHUB_ENV`;
+await $`echo "TOOLCHAIN_TEST=${getToolchain('test')}" >> $GITHUB_ENV`;

+ 25 - 0
scripts/interface/format.mjs

@@ -0,0 +1,25 @@
+#!/usr/bin/env zx
+import 'zx/globals';
+import {
+  cliArguments,
+  getToolchainArgument,
+  partitionArguments,
+  popArgument,
+  workingDirectory,
+} from '../utils.mjs';
+
+// Configure additional arguments here, e.g.:
+// ['--arg1', '--arg2', ...cliArguments()]
+const formatArgs = cliArguments();
+
+const fix = popArgument(formatArgs, '--fix');
+const [cargoArgs, fmtArgs] = partitionArguments(formatArgs, '--');
+const toolchain = getToolchainArgument('format');
+const manifestPath = path.join(workingDirectory, 'interface', 'Cargo.toml');
+
+// Format the interface.
+if (fix) {
+  await $`cargo ${toolchain} fmt --manifest-path ${manifestPath} ${cargoArgs} -- ${fmtArgs}`;
+} else {
+  await $`cargo ${toolchain} fmt --manifest-path ${manifestPath} ${cargoArgs} -- --check ${fmtArgs}`;
+}

+ 39 - 0
scripts/interface/lint.mjs

@@ -0,0 +1,39 @@
+#!/usr/bin/env zx
+import 'zx/globals';
+import {
+  cliArguments,
+  getToolchainArgument,
+  popArgument,
+  workingDirectory,
+} from '../utils.mjs';
+
+// Configure additional arguments here, e.g.:
+// ['--arg1', '--arg2', ...cliArguments()]
+const lintArgs = ['--all-targets', '--all-features', ...cliArguments()];
+// Check whether a '--' was already used.
+if (lintArgs.indexOf('--') === -1) {
+  lintArgs.push('--');
+}
+// Add additional arguments.
+lintArgs.push(
+  '--deny=warnings',
+  '--deny=clippy::default_trait_access',
+  '--deny=clippy::arithmetic_side_effects',
+  '--deny=clippy::manual_let_else',
+  '--deny=clippy::used_underscore_binding'
+);
+
+const fix = popArgument(lintArgs, '--fix');
+// Note: need to use nightly clippy as frozen-abi proc-macro generates
+// a lot of code (frozen-abi is enabled only under nightly due to the
+// use of unstable rust feature). Likewise, frozen-abi(-macro) crates'
+// unit tests are only compiled under nightly.
+const toolchain = getToolchainArgument('lint');
+const manifestPath = path.join(workingDirectory, 'interface', 'Cargo.toml');
+
+// Lint the interface.
+if (fix) {
+  await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} --fix ${lintArgs}`;
+} else {
+  await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} ${lintArgs}`;
+}

+ 16 - 0
scripts/interface/test.mjs

@@ -0,0 +1,16 @@
+#!/usr/bin/env zx
+import 'zx/globals';
+import {
+  cliArguments,
+  getToolchainArgument,
+  workingDirectory,
+} from '../utils.mjs';
+
+// Configure additional arguments here, e.g.:
+// ['--arg1', '--arg2', ...cliArguments()]
+const buildArgs = cliArguments();
+const toolchain = getToolchainArgument('test');
+const manifestPath = path.join(workingDirectory, 'interface', 'Cargo.toml');
+
+// Test the interface.
+await $`cargo ${toolchain} test --all-features --manifest-path ${manifestPath} ${buildArgs}`;