Преглед изворни кода

Merge branch 'master' into armani/versioning

Armani Ferrante пре 3 година
родитељ
комит
2dd6caa2e5
74 измењених фајлова са 761 додато и 47 уклоњено
  1. 6 0
      .github/workflows/tests.yaml
  2. 6 0
      CHANGELOG.md
  3. 15 7
      README.md
  4. 6 0
      avm/src/lib.rs
  5. 19 1
      cli/src/config.rs
  6. 6 1
      cli/src/lib.rs
  7. 10 12
      cli/src/template.rs
  8. 6 0
      lang/src/error.rs
  9. 1 1
      lang/syn/Cargo.toml
  10. 3 0
      lang/syn/src/codegen/program/entry.rs
  11. 4 0
      lang/syn/src/idl/file.rs
  12. 4 0
      lang/syn/src/idl/mod.rs
  13. 51 1
      lang/syn/src/parser/context.rs
  14. 1 1
      tests/auction-house
  15. 3 0
      tests/cashiers-check/Anchor.toml
  16. 3 0
      tests/cfo/Anchor.toml
  17. 1 1
      tests/cfo/deps/stake
  18. 1 1
      tests/cfo/deps/swap
  19. 3 0
      tests/chat/Anchor.toml
  20. 3 0
      tests/custom-coder/Anchor.toml
  21. 9 0
      tests/declare-id/Anchor.toml
  22. 4 0
      tests/declare-id/Cargo.toml
  23. 19 0
      tests/declare-id/package.json
  24. 16 0
      tests/declare-id/programs/declare-id/Cargo.toml
  25. 2 0
      tests/declare-id/programs/declare-id/Xargo.toml
  26. 18 0
      tests/declare-id/programs/declare-id/src/lib.rs
  27. 17 0
      tests/declare-id/tests/declare-id.js
  28. 3 0
      tests/errors/Anchor.toml
  29. 3 0
      tests/escrow/Anchor.toml
  30. 12 0
      tests/floats/Anchor.toml
  31. 4 0
      tests/floats/Cargo.toml
  32. 12 0
      tests/floats/migrations/deploy.ts
  33. 19 0
      tests/floats/package.json
  34. 19 0
      tests/floats/programs/floats/Cargo.toml
  35. 2 0
      tests/floats/programs/floats/Xargo.toml
  36. 51 0
      tests/floats/programs/floats/src/lib.rs
  37. 67 0
      tests/floats/tests/floats.ts
  38. 10 0
      tests/floats/tsconfig.json
  39. 3 0
      tests/ido-pool/Anchor.toml
  40. 3 0
      tests/interface/Anchor.toml
  41. 2 2
      tests/interface/programs/counter-auth/src/lib.rs
  42. 2 2
      tests/interface/tests/interface.js
  43. 3 0
      tests/lockup/Anchor.toml
  44. 49 0
      tests/misc/programs/misc/src/context.rs
  45. 1 0
      tests/misc/programs/misc2/src/lib.rs
  46. 3 0
      tests/multisig/Anchor.toml
  47. 3 1
      tests/package.json
  48. 1 0
      tests/pda-derivation/Anchor.toml
  49. 3 0
      tests/pyth/Anchor.toml
  50. 6 0
      tests/safety-checks/.gitignore
  51. 13 0
      tests/safety-checks/Anchor.toml
  52. 4 0
      tests/safety-checks/Cargo.toml
  53. 12 0
      tests/safety-checks/migrations/deploy.ts
  54. 19 0
      tests/safety-checks/programs/account-info/Cargo.toml
  55. 2 0
      tests/safety-checks/programs/account-info/Xargo.toml
  56. 16 0
      tests/safety-checks/programs/account-info/src/lib.rs
  57. 19 0
      tests/safety-checks/programs/unchecked-account/Cargo.toml
  58. 2 0
      tests/safety-checks/programs/unchecked-account/Xargo.toml
  59. 16 0
      tests/safety-checks/programs/unchecked-account/src/lib.rs
  60. 27 0
      tests/safety-checks/test.sh
  61. 16 0
      tests/safety-checks/tests/safety-checks.ts
  62. 10 0
      tests/safety-checks/tsconfig.json
  63. 3 0
      tests/spl/token-proxy/Anchor.toml
  64. 3 0
      tests/swap/Anchor.toml
  65. 46 5
      tests/yarn.lock
  66. 3 0
      tests/zero-copy/Anchor.toml
  67. 1 1
      ts/package.json
  68. 6 0
      ts/src/coder/borsh/idl.ts
  69. 4 0
      ts/src/coder/common.ts
  70. 10 1
      ts/src/error.ts
  71. 2 0
      ts/src/idl.ts
  72. 1 1
      ts/src/program/namespace/types.ts
  73. 4 4
      ts/src/spl/token.ts
  74. 4 4
      ts/yarn.lock

+ 6 - 0
.github/workflows/tests.yaml

@@ -262,6 +262,8 @@ jobs:
             path: tests/events
           - cmd: cd tests/cashiers-check && anchor test
             path: tests/cashiers-check
+          - cmd: cd tests/declare-id && anchor test
+            path: tests/declare-id
           - cmd: cd tests/typescript && anchor test
             path: tests/typescript
           - cmd: cd tests/zero-copy && anchor test && cd programs/zero-copy && cargo test-bpf
@@ -274,6 +276,10 @@ jobs:
             path: tests/cfo
           - cmd: cd tests/auction-house && yarn && anchor test
             path: tests/auction-house
+          - cmd: cd tests/floats && yarn && anchor test
+            path: tests/floats
+          - cmd: cd tests/safety-checks && ./test.sh
+            path: tests/safety-checks
     steps:
       - uses: actions/checkout@v2
       - uses: ./.github/actions/setup/

+ 6 - 0
CHANGELOG.md

@@ -11,6 +11,11 @@ incremented for features.
 
 ## [Unreleased]
 
+### Features
+
+* lang: add check that declared id == program id ([#1451](https://github.com/project-serum/anchor/pull/1451))
+* ts: Added float types support ([#1425](https://github.com/project-serum/anchor/pull/1425)).
+
 ### Fixes
 
 * ts: Allow nullable types for `Option<T>` mapped types ([#1428](https://github.com/project-serum/anchor/pull/1428)).
@@ -21,6 +26,7 @@ incremented for features.
 * lang, client, ts: 8 byte account discriminator has been replaced with a versioned account header. This is a state breaking change. If you have existing Anchor programs, previously deployed, one can continue to use the old 8 byte account discriminator by using the `deprecated-layout` feature flag ([#1415](https://github.com/project-serum/anchor/pull/1415)).
 * lang: The `AccountLoader` and `Loader`'s `load_init` method has been removed. Instead, use `load_mut` ([#1415](https://github.com/project-serum/anchor/pull/1415)).
 * lang: All error-related code is now in the error module ([#1426](https://github.com/project-serum/anchor/pull/1426)).
+* lang: Require doc comments when using AccountInfo or UncheckedAccount types ([#1452](https://github.com/project-serum/anchor/pull/1452)).
 * ts: `BorshAccountsCoder.accountDiscriminator` method has been replaced with `BorshAccountHeader.discriminator` ([#1415](https://github.com/project-serum/anchor/pull/1415)).
 
 ## [0.21.0] - 2022-02-07

+ 15 - 7
README.md

@@ -10,7 +10,7 @@
   <p>
     <a href="https://github.com/project-serum/anchor/actions"><img alt="Build Status" src="https://github.com/project-serum/anchor/actions/workflows/tests.yaml/badge.svg" /></a>
     <a href="https://project-serum.github.io/anchor/"><img alt="Tutorials" src="https://img.shields.io/badge/docs-tutorials-blueviolet" /></a>
-    <a href="https://discord.com/channels/889577356681945098"><img alt="Discord Chat" src="https://img.shields.io/discord/889577356681945098?color=blueviolet" /></a>
+    <a href="https://discord.gg/PDeRXyVURd"><img alt="Discord Chat" src="https://img.shields.io/discord/889577356681945098?color=blueviolet" /></a>
     <a href="https://opensource.org/licenses/Apache-2.0"><img alt="License" src="https://img.shields.io/github/license/project-serum/anchor?color=blueviolet" /></a>
   </p>
 </div>
@@ -97,6 +97,14 @@ pub struct Counter {
 For more, see the [examples](https://github.com/project-serum/anchor/tree/master/examples)
 and [tests](https://github.com/project-serum/anchor/tree/master/tests) directories.
 
+## License
+
+Anchor is licensed under [Apache 2.0](./LICENSE).
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Anchor by you, as defined in the Apache-2.0 license, shall be
+licensed as above, without any additional terms or conditions.
+
 ## Contribution
 
 Thank you for your interest in contributing to Anchor! All contributions are welcome no
@@ -113,10 +121,10 @@ For simple documentation changes, feel free to just open a pull request.
 If you're considering larger changes or self motivated features, please file an issue
 and engage with the maintainers in [Discord](https://discord.gg/sxy4zxBckh).
 
-## License
-
-Anchor is licensed under [Apache 2.0](./LICENSE).
+### Thanks ❤️
 
-Unless you explicitly state otherwise, any contribution intentionally submitted
-for inclusion in Anchor by you, as defined in the Apache-2.0 license, shall be
-licensed as above, without any additional terms or conditions.
+<div align="center">
+  <a href="https://github.com/project-serum/anchor/graphs/contributors">
+    <img src="https://contrib.rocks/image?repo=project-serum/anchor" width="100%" />
+  </a>
+</div>

+ 6 - 0
avm/src/lib.rs

@@ -261,6 +261,9 @@ mod tests {
         let mut current_version_file =
             fs::File::create(current_version_file_path().as_path()).unwrap();
         current_version_file.write_all("0.18.2".as_bytes()).unwrap();
+        // Sync the file to disk before the read in current_version() to
+        // mitigate the read not seeing the written version bytes.
+        current_version_file.sync_all().unwrap();
         assert!(current_version().unwrap() == Version::parse("0.18.2").unwrap());
     }
 
@@ -278,6 +281,9 @@ mod tests {
         let mut current_version_file =
             fs::File::create(current_version_file_path().as_path()).unwrap();
         current_version_file.write_all("0.18.2".as_bytes()).unwrap();
+        // Sync the file to disk before the read in current_version() to
+        // mitigate the read not seeing the written version bytes.
+        current_version_file.sync_all().unwrap();
         // Create a fake binary for anchor-0.18.2 in the bin directory
         fs::File::create(version_binary_path(&version)).unwrap();
         uninstall_version(&version).unwrap();

+ 19 - 1
cli/src/config.rs

@@ -166,6 +166,7 @@ impl WithPath<Config> {
                 path.join("src/lib.rs"),
                 version,
                 self.features.seeds,
+                false,
             )?;
             r.push(Program {
                 lib_name,
@@ -256,9 +257,26 @@ pub struct Config {
     pub test: Option<Test>,
 }
 
-#[derive(Default, Clone, Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
 pub struct FeaturesConfig {
+    #[serde(default)]
     pub seeds: bool,
+    #[serde(default = "default_safety_checks")]
+    pub safety_checks: bool,
+}
+
+impl Default for FeaturesConfig {
+    fn default() -> Self {
+        Self {
+            seeds: false,
+            // Anchor safety checks on by default
+            safety_checks: true,
+        }
+    }
+}
+
+fn default_safety_checks() -> bool {
+    true
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize)]

+ 6 - 1
cli/src/lib.rs

@@ -1388,7 +1388,12 @@ fn extract_idl(cfg: &WithPath<Config>, file: &str) -> Result<Option<Idl>> {
     let manifest_from_path = std::env::current_dir()?.join(PathBuf::from(&*file).parent().unwrap());
     let cargo = Manifest::discover_from_path(manifest_from_path)?
         .ok_or_else(|| anyhow!("Cargo.toml not found"))?;
-    anchor_syn::idl::file::parse(&*file, cargo.version(), cfg.features.seeds)
+    anchor_syn::idl::file::parse(
+        &*file,
+        cargo.version(),
+        cfg.features.seeds,
+        cfg.features.safety_checks,
+    )
 }
 
 fn idl(cfg_override: &ConfigOverride, subcmd: IdlCommand) -> Result<()> {

+ 10 - 12
cli/src/template.rs

@@ -141,7 +141,7 @@ module.exports = async function (provider) {
   anchor.setProvider(provider);
 
   // Add your deploy script here.
-}
+};
 "#
 }
 
@@ -157,7 +157,7 @@ module.exports = async function (provider) {
   anchor.setProvider(provider);
 
   // Add your deploy script here.
-}
+};
 "#
 }
 
@@ -191,14 +191,13 @@ pub struct Initialize {{}}
 
 pub fn mocha(name: &str) -> String {
     format!(
-        r#"const anchor = require('@project-serum/anchor');
-
-describe('{}', () => {{
+        r#"const anchor = require("@project-serum/anchor");
 
+describe("{}", () => {{
   // Configure the client to use the local cluster.
   anchor.setProvider(anchor.Provider.env());
 
-  it('Is initialized!', async () => {{
+  it("Is initialized!", async () => {{
     // Add your test here.
     const program = anchor.workspace.{};
     const tx = await program.rpc.initialize();
@@ -248,18 +247,17 @@ pub fn ts_package_json() -> String {
 
 pub fn ts_mocha(name: &str) -> String {
     format!(
-        r#"import * as anchor from '@project-serum/anchor';
-import {{ Program }} from '@project-serum/anchor';
-import {{ {} }} from '../target/types/{}';
-
-describe('{}', () => {{
+        r#"import * as anchor from "@project-serum/anchor";
+import {{ Program }} from "@project-serum/anchor";
+import {{ {} }} from "../target/types/{}";
 
+describe("{}", () => {{
   // Configure the client to use the local cluster.
   anchor.setProvider(anchor.Provider.env());
 
   const program = anchor.workspace.{} as Program<{}>;
 
-  it('Is initialized!', async () => {{
+  it("Is initialized!", async () => {{
     // Add your test here.
     const tx = await program.rpc.initialize({{}});
     console.log("Your transaction signature", tx);

+ 6 - 0
lang/src/error.rs

@@ -10,6 +10,7 @@ pub const ERROR_CODE_OFFSET: u32 = 6000;
 /// - &gt;= 2000 constraint error codes
 /// - &gt;= 3000 account error codes
 /// - = 4000 state error code
+/// - &gt;= 4100 misc error codes
 /// - = 5000 deprecated error code
 ///
 /// The starting point for user-defined errors is defined
@@ -154,6 +155,11 @@ pub enum ErrorCode {
     #[msg("The given state account does not have the correct address")]
     StateInvalidAddress = 4000,
 
+    // Miscellaneous
+    /// 4100 - The declared program id does not match actual program id
+    #[msg("The declared program id does not match the actual program id")]
+    DeclaredProgramIdMismatch = 4100,
+
     // Deprecated
     /// 5000 - The API being used is deprecated and should no longer be used
     #[msg("The API being used is deprecated and should no longer be used")]

+ 1 - 1
lang/syn/Cargo.toml

@@ -17,7 +17,7 @@ seeds = []
 
 [dependencies]
 arrayref = "0.3.6"
-proc-macro2 = "1.0"
+proc-macro2 = { version = "1.0", features=["span-locations"]}
 proc-macro2-diagnostics = "0.9"
 quote = "1.0"
 syn = { version = "1.0.60", features = ["full", "extra-traits", "parsing"] }

+ 3 - 0
lang/syn/src/codegen/program/entry.rs

@@ -56,6 +56,9 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
             {
                 msg!("anchor-debug is active");
             }
+            if *program_id != ID {
+                return Err(anchor_lang::error::ErrorCode::DeclaredProgramIdMismatch.into());
+            }
             if data.len() < 8 {
                 return #fallback_maybe
             }

+ 4 - 0
lang/syn/src/idl/file.rs

@@ -18,8 +18,12 @@ pub fn parse(
     filename: impl AsRef<Path>,
     version: String,
     seeds_feature: bool,
+    safety_checks: bool,
 ) -> Result<Option<Idl>> {
     let ctx = CrateContext::parse(filename)?;
+    if safety_checks {
+        ctx.safety_checks()?;
+    }
 
     let program_mod = match parse_program_mod(&ctx) {
         None => return Ok(None),

+ 4 - 0
lang/syn/src/idl/mod.rs

@@ -178,8 +178,10 @@ pub enum IdlType {
     I16,
     U32,
     I32,
+    F32,
     U64,
     I64,
+    F64,
     U128,
     I128,
     Bytes,
@@ -217,8 +219,10 @@ impl std::str::FromStr for IdlType {
             "i16" => IdlType::I16,
             "u32" => IdlType::U32,
             "i32" => IdlType::I32,
+            "f32" => IdlType::F32,
             "u64" => IdlType::U64,
             "i64" => IdlType::I64,
+            "f64" => IdlType::F64,
             "u128" => IdlType::U128,
             "i128" => IdlType::I128,
             "Vec<u8>" => IdlType::Bytes,

+ 51 - 1
lang/syn/src/parser/context.rs

@@ -1,6 +1,6 @@
+use anyhow::anyhow;
 use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
-
 use syn::parse::{Error as ParseError, Result as ParseResult};
 
 /// Crate parse context
@@ -40,6 +40,41 @@ impl CrateContext {
             modules: ParsedModule::parse_recursive(root.as_ref())?,
         })
     }
+
+    // Perform Anchor safety checks on the parsed create
+    pub fn safety_checks(&self) -> Result<(), anyhow::Error> {
+        // Check all structs for unsafe field types, i.e. AccountInfo and UncheckedAccount.
+        for (_, ctx) in self.modules.iter() {
+            for unsafe_field in ctx.unsafe_struct_fields() {
+                // Check if unsafe field type has been documented with a /// SAFETY: doc string.
+                let is_documented = unsafe_field.attrs.iter().any(|attr| {
+                    attr.tokens.clone().into_iter().any(|token| match token {
+                        // Check for doc comments containing CHECK
+                        proc_macro2::TokenTree::Literal(s) => s.to_string().contains("CHECK"),
+                        _ => false,
+                    })
+                });
+                if !is_documented {
+                    let ident = unsafe_field.ident.as_ref().unwrap();
+                    let span = ident.span();
+                    // Error if undocumented.
+                    return Err(anyhow!(
+                        r#"
+        {}:{}:{}
+        Struct field "{}" is unsafe, but is not documented.
+        Please add a `/// CHECK:` doc comment explaining why no checks through types are necessary.
+        See https://book.anchor-lang.com/chapter_3/the_accounts_struct.html#safety-checks for more information.
+                    "#,
+                        ctx.file.canonicalize().unwrap().display(),
+                        span.start().line,
+                        span.start().column,
+                        ident.to_string()
+                    ));
+                };
+            }
+        }
+        Ok(())
+    }
 }
 
 /// Module parse context
@@ -181,6 +216,21 @@ impl ParsedModule {
         })
     }
 
+    fn unsafe_struct_fields(&self) -> impl Iterator<Item = &syn::Field> {
+        self.structs()
+            .flat_map(|s| &s.fields)
+            .filter(|f| match &f.ty {
+                syn::Type::Path(syn::TypePath {
+                    path: syn::Path { segments, .. },
+                    ..
+                }) => {
+                    segments.len() == 1 && segments[0].ident == "UncheckedAccount"
+                        || segments[0].ident == "AccountInfo"
+                }
+                _ => false,
+            })
+    }
+
     fn enums(&self) -> impl Iterator<Item = &syn::ItemEnum> {
         self.items.iter().filter_map(|i| match i {
             syn::Item::Enum(item) => Some(item),

+ 1 - 1
tests/auction-house

@@ -1 +1 @@
-Subproject commit 2bfe49bdac2333d0e413a1e452c0ab7b502266fa
+Subproject commit 2b1b1e04986106715ab53794bcb63d3641673f64

+ 3 - 0
tests/cashiers-check/Anchor.toml

@@ -7,3 +7,6 @@ cashiers_check = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 3 - 0
tests/cfo/Anchor.toml

@@ -41,3 +41,6 @@ program = "./deps/stake/target/deploy/registry.so"
 [[test.genesis]]
 address = "6ebQNeTPZ1j7k3TtkCCtEPRvG7GQsucQrZ7sSEDQi9Ks"
 program = "./deps/stake/target/deploy/lockup.so"
+
+[features]
+safety_checks = false

+ 1 - 1
tests/cfo/deps/stake

@@ -1 +1 @@
-Subproject commit f04b2aaf8817dac4c8d89e75eaaa0c099dfbf166
+Subproject commit 990eaa7944c6682838fdaa6c14cc07ed680007f0

+ 1 - 1
tests/cfo/deps/swap

@@ -1 +1 @@
-Subproject commit b3021f1444280a372721133bb2e5acca2d271283
+Subproject commit 96e3b1e2a53a95ef56e6ec2da68348ffd6a5c091

+ 3 - 0
tests/chat/Anchor.toml

@@ -7,3 +7,6 @@ chat = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 3 - 0
tests/custom-coder/Anchor.toml

@@ -11,3 +11,6 @@ wallet = "~/.config/solana/id.json"
 
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+
+[features]
+safety_checks = false

+ 9 - 0
tests/declare-id/Anchor.toml

@@ -0,0 +1,9 @@
+[provider]
+cluster = "localnet"
+wallet = "~/.config/solana/id.json"
+
+[programs.localnet]
+declare_id = "FJcF5c8HncdfAgjPjTH49GAEypkJCG2ZADh2xhduNi5B"
+
+[scripts]
+test = "yarn run mocha -t 1000000 tests/"

+ 4 - 0
tests/declare-id/Cargo.toml

@@ -0,0 +1,4 @@
+[workspace]
+members = [
+    "programs/*"
+]

+ 19 - 0
tests/declare-id/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "declare-id",
+  "version": "0.21.0",
+  "license": "(MIT OR Apache-2.0)",
+  "homepage": "https://github.com/project-serum/anchor#readme",
+  "bugs": {
+    "url": "https://github.com/project-serum/anchor/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/project-serum/anchor.git"
+  },
+  "engines": {
+    "node": ">=11"
+  },
+  "scripts": {
+    "test": "anchor test"
+  }
+}

+ 16 - 0
tests/declare-id/programs/declare-id/Cargo.toml

@@ -0,0 +1,16 @@
+[package]
+name = "declare-id"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "declare_id"
+
+[features]
+no-entrypoint = []
+cpi = ["no-entrypoint"]
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }

+ 2 - 0
tests/declare-id/programs/declare-id/Xargo.toml

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

+ 18 - 0
tests/declare-id/programs/declare-id/src/lib.rs

@@ -0,0 +1,18 @@
+use anchor_lang::prelude::*;
+
+// Intentionally different program id than the one defined in Anchor.toml.
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+
+#[program]
+mod declare_id {
+    use super::*;
+
+    pub fn initialize(_ctx: Context<Initialize>) -> ProgramResult {
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Initialize {
+}

+ 17 - 0
tests/declare-id/tests/declare-id.js

@@ -0,0 +1,17 @@
+const anchor = require("@project-serum/anchor");
+const splToken = require("@solana/spl-token");
+const assert = require("assert");
+
+describe("declare_id", () => {
+  anchor.setProvider(anchor.Provider.local());
+  const program = anchor.workspace.DeclareId;
+
+  it("throws error!", async () => {
+    try {
+      await program.rpc.initialize();
+      assert.ok(false);
+    } catch (err) {
+      assert.equal(err.code, 4100);
+    }
+  });
+});

+ 3 - 0
tests/errors/Anchor.toml

@@ -7,3 +7,6 @@ errors = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 3 - 0
tests/escrow/Anchor.toml

@@ -7,3 +7,6 @@ escrow = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run ts-mocha -t 1000000 tests/*.ts"
+
+[features]
+safety_checks = false

+ 12 - 0
tests/floats/Anchor.toml

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

+ 4 - 0
tests/floats/Cargo.toml

@@ -0,0 +1,4 @@
+[workspace]
+members = [
+    "programs/*"
+]

+ 12 - 0
tests/floats/migrations/deploy.ts

@@ -0,0 +1,12 @@
+// Migrations are an early feature. Currently, they're nothing more than this
+// single deploy script that's invoked from the CLI, injecting a provider
+// configured from the workspace's Anchor.toml.
+
+const anchor = require("@project-serum/anchor");
+
+module.exports = async function (provider) {
+  // Configure client to use the provider.
+  anchor.setProvider(provider);
+
+  // Add your deploy script here.
+};

+ 19 - 0
tests/floats/package.json

@@ -0,0 +1,19 @@
+{
+    "name": "floats",
+    "version": "0.21.0",
+    "license": "(MIT OR Apache-2.0)",
+    "homepage": "https://github.com/project-serum/anchor#readme",
+    "bugs": {
+      "url": "https://github.com/project-serum/anchor/issues"
+    },
+    "repository": {
+      "type": "git",
+      "url": "https://github.com/project-serum/anchor.git"
+    },
+    "engines": {
+      "node": ">=11"
+    },
+    "scripts": {
+      "test": "anchor test"
+    }
+  }

+ 19 - 0
tests/floats/programs/floats/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "floats"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "floats"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }

+ 2 - 0
tests/floats/programs/floats/Xargo.toml

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

+ 51 - 0
tests/floats/programs/floats/src/lib.rs

@@ -0,0 +1,51 @@
+use anchor_lang::prelude::*;
+
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+#[program]
+pub mod floats {
+    use super::*;
+
+    pub fn create(ctx: Context<Create>, data_f32: f32, data_f64: f64) -> ProgramResult {
+        let account = &mut ctx.accounts.account;
+        let authority = &mut ctx.accounts.authority;
+
+        account.data_f32 = data_f32;
+        account.data_f64 = data_f64;
+        account.authority = authority.key();
+
+        Ok(())
+    }
+
+    pub fn update(ctx: Context<Update>, data_f32: f32, data_f64: f64) -> ProgramResult {
+        let account = &mut ctx.accounts.account;
+
+        account.data_f32 = data_f32;
+        account.data_f64 = data_f64;
+
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Create<'info> {
+    #[account(init, payer = authority, space = 8 + 8 + 4 + 32)]
+    pub account: Account<'info, FloatDataAccount>,
+    #[account(mut)]
+    pub authority: Signer<'info>,
+    pub system_program: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct Update<'info> {
+    #[account(mut, has_one = authority)]
+    pub account: Account<'info, FloatDataAccount>,
+    pub authority: Signer<'info>,
+}
+
+#[account]
+pub struct FloatDataAccount {
+    pub data_f64: f64,
+    pub data_f32: f32,
+    pub authority: Pubkey,
+}

+ 67 - 0
tests/floats/tests/floats.ts

@@ -0,0 +1,67 @@
+import * as anchor from "@project-serum/anchor";
+import { Program, getProvider } from "@project-serum/anchor";
+import { Keypair, SystemProgram } from "@solana/web3.js";
+import { Floats } from "../target/types/floats";
+import assert from "assert";
+
+describe("floats", () => {
+  // Configure the client to use the local cluster.
+  anchor.setProvider(anchor.Provider.env());
+
+  const program = anchor.workspace.Floats as Program<Floats>;
+
+  it("Creates an account with float data", async () => {
+    const accountKeypair = Keypair.generate();
+
+    await program.methods
+      .create(1.0, 2.0)
+      .accounts({
+        account: accountKeypair.publicKey,
+        authority: getProvider().wallet.publicKey,
+        systemProgram: SystemProgram.programId,
+      })
+      .signers([accountKeypair])
+      .rpc();
+
+    const account = await program.account.floatDataAccount.fetch(
+      accountKeypair.publicKey
+    );
+
+    assert.strictEqual(account.dataF32, 1.0);
+    assert.strictEqual(account.dataF64, 2.0);
+  });
+
+  it("Updates an account with float data", async () => {
+    const accountKeypair = Keypair.generate();
+    const authorityPublicKey = getProvider().wallet.publicKey;
+
+    await program.methods
+      .create(1.0, 2.0)
+      .accounts({
+        account: accountKeypair.publicKey,
+        authority: authorityPublicKey,
+        systemProgram: SystemProgram.programId,
+      })
+      .signers([accountKeypair])
+      .rpc();
+
+    let account = await program.account.floatDataAccount.fetch(
+      accountKeypair.publicKey
+    );
+
+    await program.methods
+      .update(3.0, 4.0)
+      .accounts({
+        account: accountKeypair.publicKey,
+        authority: authorityPublicKey,
+      })
+      .rpc();
+
+    account = await program.account.floatDataAccount.fetch(
+      accountKeypair.publicKey
+    );
+
+    assert.strictEqual(account.dataF32, 3.0);
+    assert.strictEqual(account.dataF64, 4.0);
+  });
+});

+ 10 - 0
tests/floats/tsconfig.json

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

+ 3 - 0
tests/ido-pool/Anchor.toml

@@ -7,3 +7,6 @@ ido_pool = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 3 - 0
tests/interface/Anchor.toml

@@ -8,3 +8,6 @@ counter_auth = "Aws2XRVHjNqCUbMmaU245ojT2DBJFYX58KVo2YySEeeP"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 2 - 2
tests/interface/programs/counter-auth/src/lib.rs

@@ -19,11 +19,11 @@ pub mod counter_auth {
         fn is_authorized(_ctx: Context<Empty>, current: u64, new: u64) -> ProgramResult {
             if current % 2 == 0 {
                 if new % 2 == 0 {
-                    return Err(ProgramError::Custom(50)); // Arbitrary error code.
+                    return Err(ProgramError::Custom(15000)); // Arbitrary error code.
                 }
             } else {
                 if new % 2 == 1 {
-                    return Err(ProgramError::Custom(60)); // Arbitrary error code.
+                    return Err(ProgramError::Custom(16000)); // Arbitrary error code.
                 }
             }
             Ok(())

+ 2 - 2
tests/interface/tests/interface.js

@@ -25,7 +25,7 @@ describe("interface", () => {
         });
       },
       (err) => {
-        if (err.toString().split("custom program error: 0x32").length !== 2) {
+        if (err.toString().split("custom program error: 0x3a98").length !== 2) {
           return false;
         }
         return true;
@@ -33,7 +33,7 @@ describe("interface", () => {
     );
   });
 
-  it("Shold succeed to go from even to odd", async () => {
+  it("Should succeed to go from even to odd", async () => {
     await counter.state.rpc.setCount(new anchor.BN(3), {
       accounts: {
         authProgram: counterAuth.programId,

+ 3 - 0
tests/lockup/Anchor.toml

@@ -8,3 +8,6 @@ registry = "HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 49 - 0
tests/misc/programs/misc/src/context.rs

@@ -28,6 +28,7 @@ pub struct TestTokenSeedsInit<'info> {
     )]
     pub my_pda: Account<'info, TokenAccount>,
     #[account(mut)]
+    /// CHECK:
     pub authority: AccountInfo<'info>,
     pub system_program: Program<'info, System>,
     pub rent: Sysvar<'info, Rent>,
@@ -60,6 +61,7 @@ pub struct TestValidateAssociatedToken<'info> {
     )]
     pub token: Account<'info, TokenAccount>,
     pub mint: Account<'info, Mint>,
+    /// CHECK:
     pub wallet: AccountInfo<'info>,
 }
 
@@ -70,7 +72,9 @@ pub struct TestInstructionConstraint<'info> {
         seeds = [b"my-seed", my_account.key.as_ref()],
         bump = nonce,
     )]
+    /// CHECK:
     pub my_pda: AccountInfo<'info>,
+    /// CHECK:
     pub my_account: AccountInfo<'info>,
 }
 
@@ -86,6 +90,7 @@ pub struct TestPdaInit<'info> {
     pub my_pda: Account<'info, DataU16>,
     #[account(mut)]
     pub my_payer: Signer<'info>,
+    /// CHECK:
     pub foo: AccountInfo<'info>,
     pub system_program: Program<'info, System>,
 }
@@ -112,6 +117,7 @@ pub struct TestPdaMutZeroCopy<'info> {
         bump = my_pda.load()?.bump,
     )]
     pub my_pda: Loader<'info, DataZeroCopy>,
+    /// CHECK:
     pub my_payer: AccountInfo<'info>,
 }
 
@@ -135,29 +141,35 @@ pub struct InitializeSkipRentExempt<'info> {
 
 #[derive(Accounts)]
 pub struct InitializeNoRentExempt<'info> {
+    /// CHECK:
     pub data: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]
 pub struct TestOwner<'info> {
     #[account(owner = *misc.key)]
+    /// CHECK:
     pub data: AccountInfo<'info>,
+    /// CHECK:
     pub misc: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]
 pub struct TestExecutable<'info> {
     #[account(executable)]
+    /// CHECK:
     pub program: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]
 pub struct TestStateCpi<'info> {
     #[account(signer)]
+    /// CHECK:
     pub authority: AccountInfo<'info>,
     #[account(mut, state = misc2_program)]
     pub cpi_state: CpiState<'info, Misc2State>,
     #[account(executable)]
+    /// CHECK:
     pub misc2_program: AccountInfo<'info>,
 }
 
@@ -165,6 +177,7 @@ pub struct TestStateCpi<'info> {
 pub struct TestClose<'info> {
     #[account(mut, close = sol_dest)]
     pub data: Account<'info, Data>,
+    /// CHECK:
     sol_dest: AccountInfo<'info>,
 }
 
@@ -259,6 +272,7 @@ pub struct TestInitWithEmptySeeds<'info> {
 #[derive(Accounts)]
 pub struct TestEmptySeedsConstraint<'info> {
     #[account(seeds = [], bump)]
+    /// CHECK:
     pub pda: AccountInfo<'info>,
 }
 
@@ -283,10 +297,12 @@ pub struct TestInitIfNeeded<'info> {
 #[derive(Accounts)]
 pub struct TestInitIfNeededChecksOwner<'info> {
     #[account(init_if_needed, payer = payer, space = 100, owner = *owner.key, seeds = [b"hello"], bump)]
+    /// CHECK:
     pub data: UncheckedAccount<'info>,
     #[account(mut)]
     pub payer: Signer<'info>,
     pub system_program: Program<'info, System>,
+    /// CHECK:
     pub owner: AccountInfo<'info>,
 }
 
@@ -294,6 +310,7 @@ pub struct TestInitIfNeededChecksOwner<'info> {
 #[instruction(seed_data: String)]
 pub struct TestInitIfNeededChecksSeeds<'info> {
     #[account(init_if_needed, payer = payer, space = 100, seeds = [seed_data.as_bytes()], bump)]
+    /// CHECK:
     pub data: UncheckedAccount<'info>,
     #[account(mut)]
     pub payer: Signer<'info>,
@@ -310,7 +327,9 @@ pub struct TestInitMintIfNeeded<'info> {
     pub rent: Sysvar<'info, Rent>,
     pub system_program: Program<'info, System>,
     pub token_program: Program<'info, Token>,
+    /// CHECK:
     pub mint_authority: AccountInfo<'info>,
+    /// CHECK:
     pub freeze_authority: AccountInfo<'info>,
 }
 
@@ -324,6 +343,7 @@ pub struct TestInitTokenIfNeeded<'info> {
     pub rent: Sysvar<'info, Rent>,
     pub system_program: Program<'info, System>,
     pub token_program: Program<'info, Token>,
+    /// CHECK:
     pub authority: AccountInfo<'info>,
 }
 
@@ -343,6 +363,7 @@ pub struct TestInitAssociatedTokenIfNeeded<'info> {
     pub system_program: Program<'info, System>,
     pub token_program: Program<'info, Token>,
     pub associated_token_program: Program<'info, AssociatedToken>,
+    /// CHECK:
     pub authority: AccountInfo<'info>,
 }
 
@@ -360,18 +381,21 @@ pub struct TestConstArraySize<'info> {
 
 #[derive(Accounts)]
 pub struct NoRentExempt<'info> {
+    /// CHECK:
     pub data: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]
 pub struct EnforceRentExempt<'info> {
     #[account(rent_exempt = enforce)]
+    /// CHECK:
     pub data: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]
 pub struct InitDecreaseLamports<'info> {
     #[account(init, payer = user, space = 1000)]
+    /// CHECK:
     pub data: AccountInfo<'info>,
     #[account(mut)]
     pub user: Signer<'info>,
@@ -381,6 +405,7 @@ pub struct InitDecreaseLamports<'info> {
 #[derive(Accounts)]
 pub struct InitIfNeededChecksRentExemption<'info> {
     #[account(init_if_needed, payer = user, space = 1000)]
+    /// CHECK:
     pub data: AccountInfo<'info>,
     #[account(mut)]
     pub user: Signer<'info>,
@@ -393,9 +418,11 @@ pub struct TestProgramIdConstraint<'info> {
     // not a real associated token account
     // just deriving like this for testing purposes
     #[account(seeds = [b"seed"], bump = bump, seeds::program = anchor_spl::associated_token::ID)]
+    /// CHECK:
     first: AccountInfo<'info>,
 
     #[account(seeds = [b"seed"], bump = second_bump, seeds::program = crate::ID)]
+    /// CHECK:
     second: AccountInfo<'info>,
 }
 
@@ -404,8 +431,30 @@ pub struct TestProgramIdConstraintUsingFindPda<'info> {
     // not a real associated token account
     // just deriving like this for testing purposes
     #[account(seeds = [b"seed"], bump, seeds::program = anchor_spl::associated_token::ID)]
+    /// CHECK:
     first: AccountInfo<'info>,
 
     #[account(seeds = [b"seed"], bump, seeds::program = crate::ID)]
+    /// CHECK:
     second: AccountInfo<'info>,
 }
+
+#[derive(Accounts)]
+pub struct TestUnsafeFieldSafetyErrors<'info> {
+    #[doc = "test"]
+    /// CHECK:
+    pub data: UncheckedAccount<'info>,
+    #[account(mut)]
+    /// CHECK:
+    pub data_two: UncheckedAccount<'info>,
+    #[account(
+        seeds = [b"my-seed", signer.key.as_ref()],
+        bump
+    )]
+    /// CHECK:
+    pub data_three: UncheckedAccount<'info>,
+    /// CHECK:
+    pub data_four: UncheckedAccount<'info>,
+    pub signer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+}

+ 1 - 0
tests/misc/programs/misc2/src/lib.rs

@@ -33,5 +33,6 @@ pub mod misc2 {
 #[derive(Accounts)]
 pub struct Auth<'info> {
     #[account(signer)]
+    /// CHECK:
     pub authority: AccountInfo<'info>,
 }

+ 3 - 0
tests/multisig/Anchor.toml

@@ -7,3 +7,6 @@ multisig = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 3 - 1
tests/package.json

@@ -14,6 +14,7 @@
     "errors",
     "escrow",
     "events",
+    "floats",
     "ido-pool",
     "interface",
     "lockup",
@@ -28,7 +29,8 @@
     "sysvars",
     "tictactoe",
     "typescript",
-    "zero-copy"
+    "zero-copy",
+    "declare-id"
   ],
   "dependencies": {
     "@project-serum/anchor": "^0.21.0",

+ 1 - 0
tests/pda-derivation/Anchor.toml

@@ -1,5 +1,6 @@
 [features]
 seeds = true
+safety_checks = false
 
 [provider]
 cluster = "localnet"

+ 3 - 0
tests/pyth/Anchor.toml

@@ -7,3 +7,6 @@ pyth = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+
+[features]
+safety_checks = false

+ 6 - 0
tests/safety-checks/.gitignore

@@ -0,0 +1,6 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules

+ 13 - 0
tests/safety-checks/Anchor.toml

@@ -0,0 +1,13 @@
+[programs.localnet]
+unchecked_account = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
+account_info = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
+
+[registry]
+url = "https://anchor.projectserum.com"
+
+[provider]
+cluster = "localnet"
+wallet = "/home/armaniferrante/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 4 - 0
tests/safety-checks/Cargo.toml

@@ -0,0 +1,4 @@
+[workspace]
+members = [
+    "programs/*"
+]

+ 12 - 0
tests/safety-checks/migrations/deploy.ts

@@ -0,0 +1,12 @@
+// Migrations are an early feature. Currently, they're nothing more than this
+// single deploy script that's invoked from the CLI, injecting a provider
+// configured from the workspace's Anchor.toml.
+
+const anchor = require("@project-serum/anchor");
+
+module.exports = async function (provider) {
+  // Configure client to use the provider.
+  anchor.setProvider(provider);
+
+  // Add your deploy script here.
+};

+ 19 - 0
tests/safety-checks/programs/account-info/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "account-info"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "account_info"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = "0.21.0"

+ 2 - 0
tests/safety-checks/programs/account-info/Xargo.toml

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

+ 16 - 0
tests/safety-checks/programs/account-info/src/lib.rs

@@ -0,0 +1,16 @@
+use anchor_lang::prelude::*;
+
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+#[program]
+pub mod account_info {
+    use super::*;
+    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Initialize<'info> {
+    unchecked: AccountInfo<'info>,
+}

+ 19 - 0
tests/safety-checks/programs/unchecked-account/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "unchecked-account"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "safety_checks"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }

+ 2 - 0
tests/safety-checks/programs/unchecked-account/Xargo.toml

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

+ 16 - 0
tests/safety-checks/programs/unchecked-account/src/lib.rs

@@ -0,0 +1,16 @@
+use anchor_lang::prelude::*;
+
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+#[program]
+pub mod unchecked_account {
+    use super::*;
+    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Initialize<'info> {
+    unchecked: UncheckedAccount<'info>,
+}

+ 27 - 0
tests/safety-checks/test.sh

@@ -0,0 +1,27 @@
+#!/bin/bash
+
+echo "Building programs"
+
+#
+# Build the UncheckedAccount variant.
+#
+pushd programs/unchecked-account/
+anchor build
+if [ $? -eq 0 ]; then
+   echo "Error: expected failure"
+   exit 1
+fi
+popd
+
+#
+# Build the AccountInfo variant.
+#
+pushd programs/account-info/
+anchor build
+if [ $? -eq 0 ]; then
+   echo "Error: expected failure"
+   exit 1
+fi
+popd
+
+echo "Success. All builds failed."

+ 16 - 0
tests/safety-checks/tests/safety-checks.ts

@@ -0,0 +1,16 @@
+import * as anchor from "@project-serum/anchor";
+import { Program } from "@project-serum/anchor";
+import { SafetyChecks } from "../target/types/safety_checks";
+
+describe("safety-checks", () => {
+  // Configure the client to use the local cluster.
+  anchor.setProvider(anchor.Provider.env());
+
+  const program = anchor.workspace.SafetyChecks as Program<SafetyChecks>;
+
+  it("Is initialized!", async () => {
+    // Add your test here.
+    const tx = await program.rpc.initialize({});
+    console.log("Your transaction signature", tx);
+  });
+});

+ 10 - 0
tests/safety-checks/tsconfig.json

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

+ 3 - 0
tests/spl/token-proxy/Anchor.toml

@@ -7,3 +7,6 @@ token_proxy = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 3 - 0
tests/swap/Anchor.toml

@@ -11,3 +11,6 @@ program = "./deps/serum-dex/dex/target/deploy/serum_dex.so"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
+
+[features]
+safety_checks = false

+ 46 - 5
tests/yarn.lock

@@ -50,18 +50,19 @@
     snake-case "^3.0.4"
     toml "^3.0.0"
 
-"@project-serum/anchor@^0.20.0":
-  version "0.20.0"
-  resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.20.0.tgz#547f5c0ff7e66809fa7118b2e3abd8087b5ec519"
-  integrity sha512-p1KOiqGBIbNsopMrSVoPwgxR1iPffsdjMNCOysahTPL9whX2CLX9HQCdopHjYaGl7+SdHRuXml6Wahk/wUmC8g==
+"@project-serum/anchor@^0.21.0":
+  version "0.21.0"
+  resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.21.0.tgz#ad5fb33744991ec1900cdb2fd22707c908b12b5f"
+  integrity sha512-flRuW/F+iC8mitNokx82LOXyND7Dyk6n5UUPJpQv/+NfySFrNFlzuQZaBZJ4CG5g9s8HS/uaaIz1nVkDR8V/QA==
   dependencies:
-    "@project-serum/borsh" "^0.2.2"
+    "@project-serum/borsh" "^0.2.4"
     "@solana/web3.js" "^1.17.0"
     base64-js "^1.5.1"
     bn.js "^5.1.2"
     bs58 "^4.0.1"
     buffer-layout "^1.2.2"
     camelcase "^5.3.1"
+    cross-fetch "^3.1.5"
     crypto-hash "^1.3.0"
     eventemitter3 "^4.0.7"
     find "^0.3.0"
@@ -78,6 +79,14 @@
     bn.js "^5.1.2"
     buffer-layout "^1.2.0"
 
+"@project-serum/borsh@^0.2.4":
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/@project-serum/borsh/-/borsh-0.2.5.tgz#6059287aa624ecebbfc0edd35e4c28ff987d8663"
+  integrity sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q==
+  dependencies:
+    bn.js "^5.1.2"
+    buffer-layout "^1.2.0"
+
 "@project-serum/common@^0.0.1-beta.3":
   version "0.0.1-beta.3"
   resolved "https://registry.yarnpkg.com/@project-serum/common/-/common-0.0.1-beta.3.tgz#53586eaff9d9fd7e8938b1e12080c935b8b6ad07"
@@ -455,6 +464,13 @@ cross-fetch@^3.1.4:
   dependencies:
     node-fetch "2.6.1"
 
+cross-fetch@^3.1.5:
+  version "3.1.5"
+  resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
+  integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
+  dependencies:
+    node-fetch "2.6.7"
+
 crypto-hash@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247"
@@ -906,6 +922,13 @@ node-fetch@2.6.1:
   resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
   integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
 
+node-fetch@2.6.7:
+  version "2.6.7"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
+  integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
+  dependencies:
+    whatwg-url "^5.0.0"
+
 node-gyp-build@^4.2.0, node-gyp-build@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
@@ -1127,6 +1150,11 @@ toml@^3.0.0:
   resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
   integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==
 
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+  integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
+
 traverse-chain@~0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
@@ -1202,6 +1230,19 @@ uuid@^8.3.0:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
   integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
 
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+  integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
+
+whatwg-url@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+  integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
 which@2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"

+ 3 - 0
tests/zero-copy/Anchor.toml

@@ -11,3 +11,6 @@ test = "yarn run mocha -t 1000000 tests/"
 [programs.localnet]
 zero_cpi = "ErjUjtqKE5AGWUsjseSJCVLtddM6rhaMbDqmhzraF9h6"
 zero_copy = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
+
+[features]
+safety_checks = false

+ 1 - 1
ts/package.json

@@ -33,7 +33,7 @@
     "test": "jest tests --detectOpenHandles"
   },
   "dependencies": {
-    "@project-serum/borsh": "^0.2.4",
+    "@project-serum/borsh": "^0.2.5",
     "@solana/web3.js": "^1.17.0",
     "base64-js": "^1.5.1",
     "bn.js": "^5.1.2",

+ 6 - 0
ts/src/coder/borsh/idl.ts

@@ -33,12 +33,18 @@ export class IdlCoder {
       case "i32": {
         return borsh.i32(fieldName);
       }
+      case "f32": {
+        return borsh.f32(fieldName);
+      }
       case "u64": {
         return borsh.u64(fieldName);
       }
       case "i64": {
         return borsh.i64(fieldName);
       }
+      case "f64": {
+        return borsh.f64(fieldName);
+      }
       case "u128": {
         return borsh.u128(fieldName);
       }

+ 4 - 0
ts/src/coder/common.ts

@@ -46,10 +46,14 @@ function typeSize(idl: Idl, ty: IdlType): number {
       return 4;
     case "i32":
       return 4;
+    case "f32":
+      return 4;
     case "u64":
       return 8;
     case "i64":
       return 8;
+    case "f64":
+      return 8;
     case "u128":
       return 16;
     case "i128":

+ 10 - 1
ts/src/error.ts

@@ -102,6 +102,9 @@ const LangErrorCode = {
   // State.
   StateInvalidAddress: 4000,
 
+  // Miscellaneous
+  DeclaredProgramIdMismatch: 4100,
+
   // Used for APIs that shouldn't be used anymore.
   Deprecated: 5000,
 };
@@ -219,7 +222,13 @@ const LangErrorMessage = new Map([
     "The given state account does not have the correct address",
   ],
 
-  // Misc.
+  // Miscellaneous
+  [
+    LangErrorCode.DeclaredProgramIdMismatch,
+    "The declared program id does not match the actual program id",
+  ],
+
+  // Deprecated
   [
     LangErrorCode.Deprecated,
     "The API being used is deprecated and should no longer be used",

+ 2 - 0
ts/src/idl.ts

@@ -102,8 +102,10 @@ export type IdlType =
   | "i16"
   | "u32"
   | "i32"
+  | "f32"
   | "u64"
   | "i64"
+  | "f64"
   | "u128"
   | "i128"
   | "bytes"

+ 1 - 1
ts/src/program/namespace/types.ts

@@ -94,7 +94,7 @@ type TypeMap = {
   bool: boolean;
   string: string;
 } & {
-  [K in "u8" | "i8" | "u16" | "i16" | "u32" | "i32"]: number;
+  [K in "u8" | "i8" | "u16" | "i16" | "u32" | "i32" | "f32" | "f64"]: number;
 } &
   {
     [K in "u64" | "i64" | "u128" | "i128"]: BN;

+ 4 - 4
ts/src/spl/token.ts

@@ -544,7 +544,7 @@ export type SplToken = {
   ];
   accounts: [
     {
-      name: "Mint";
+      name: "mint";
       type: {
         kind: "struct";
         fields: [
@@ -576,7 +576,7 @@ export type SplToken = {
       };
     },
     {
-      name: "Token";
+      name: "token";
       type: {
         kind: "struct";
         fields: [
@@ -1150,7 +1150,7 @@ export const IDL: SplToken = {
   ],
   accounts: [
     {
-      name: "Mint",
+      name: "mint",
       type: {
         kind: "struct",
         fields: [
@@ -1182,7 +1182,7 @@ export const IDL: SplToken = {
       },
     },
     {
-      name: "Token",
+      name: "token",
       type: {
         kind: "struct",
         fields: [

+ 4 - 4
ts/yarn.lock

@@ -855,10 +855,10 @@
     "@nodelib/fs.scandir" "2.1.4"
     fastq "^1.6.0"
 
-"@project-serum/borsh@^0.2.4":
-  version "0.2.4"
-  resolved "https://registry.yarnpkg.com/@project-serum/borsh/-/borsh-0.2.4.tgz#8884c3a759984a39d54bf5b7390bd1ee0b579f16"
-  integrity sha512-tQPc1ktAp1Jtn9D72DmObAfhAic9ivfYBOS5b+T4H7MvkQ84uML88LY1LfvGep30mCy+ua5rf+X9ocPfg6u9MA==
+"@project-serum/borsh@^0.2.5":
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/@project-serum/borsh/-/borsh-0.2.5.tgz#6059287aa624ecebbfc0edd35e4c28ff987d8663"
+  integrity sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q==
   dependencies:
     bn.js "^5.1.2"
     buffer-layout "^1.2.0"