Hack: make ts/ into the repo root, so yarn can work

This commit is contained in:
Christian Kamm 2022-07-14 11:21:39 +02:00
parent 01106c1bb1
commit 4ef5a52ab8
573 changed files with 5 additions and 53776 deletions

18
.gitmodules vendored
View File

@ -1,21 +1,3 @@
[submodule "examples/swap/deps/serum-dex"]
path = tests/swap/deps/serum-dex
url = https://github.com/project-serum/serum-dex
[submodule "examples/cfo/deps/serum-dex"]
path = tests/cfo/deps/serum-dex
url = https://github.com/project-serum/serum-dex
[submodule "examples/cfo/deps/swap"]
path = tests/cfo/deps/swap
url = https://github.com/project-serum/swap.git
branch = armani/cfo
[submodule "examples/cfo/deps/stake"]
path = tests/cfo/deps/stake
url = https://github.com/project-serum/stake.git
branch = armani/cfo
[submodule "examples/permissioned-markets/deps/serum-dex"]
path = tests/permissioned-markets/deps/serum-dex
url = https://github.com/project-serum/serum-dex
[submodule "tests/auction-house"]
path = tests/auction-house
url = https://github.com/armaniferrante/auction-house
branch = armani/pda

View File

@ -1,608 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
**Note:** Version 0 of Semantic Versioning is handled differently from version 1 and above.
The minor version will be incremented upon a breaking change and the patch version will be incremented for features.
## [Unreleased]
## [0.24.2] - 2022-04-13
### Fixes
* lang: Fix `returns` being serialized as `null` instead of `undefined` in IDL ([#1782](https://github.com/project-serum/anchor/pull/1782)).
## [0.24.1] - 2022-04-12
### Fixes
* lang: Fix `anchor build` failing if `Test.toml` included a relative path that didn't exist yet because it's created by `anchor build` ([#1772](https://github.com/project-serum/anchor/pull/1772)).
* cli: Update js/ts template to use new `AnchorProvider` class ([#1770](https://github.com/project-serum/anchor/pull/1770)).
## [0.24.0] - 2022-04-12
### Features
* lang: Add support for multiple test suites with separate local validators ([#1681](https://github.com/project-serum/anchor/pull/1681)).
* lang: Add return values to CPI client ([#1598](https://github.com/project-serum/anchor/pull/1598)).
* ts: Add view functions ([#1695](https://github.com/project-serum/anchor/pull/1695)).
* avm: New `avm update` command to update the Anchor CLI to the latest version ([#1670](https://github.com/project-serum/anchor/pull/1670)).
* cli: Update js/ts templates to use new `program.methods` syntax ([#1732](https://github.com/project-serum/anchor/pull/1732)).
* cli: Workspaces created with `anchor init` now come with the `prettier` formatter and scripts included ([#1741](https://github.com/project-serum/anchor/pull/1741)).
* ts: Add `pubkeys` function to methods builder to get all instruction account addresses ([#1733](https://github.com/project-serum/anchor/pull/1733)).
* ts: Export `LangErrorCode` and `LangErrorMessage` from `error.ts` ([#1756](https://github.com/project-serum/anchor/pull/1756)).
### Fixes
* avm: `avm install` no longer downloads the version if already installed in the machine ([#1670](https://github.com/project-serum/anchor/pull/1670)).
* cli: make `anchor test` fail when used with `--skip-deploy` option and without `--skip-local-validator` option but there already is a running validator ([#1675](https://github.com/project-serum/anchor/pull/1675)).
* lang: Return proper error instead of panicking if account length is smaller than discriminator in functions of `(Account)Loader` ([#1678](https://github.com/project-serum/anchor/pull/1678)).
* cli: Add `@types/bn.js` to `devDependencies` in cli template ([#1712](https://github.com/project-serum/anchor/pull/1712)).
* ts: Event listener no longer crashes on Program Upgrade or any other unexpected log ([#1757](https://github.com/project-serum/anchor/pull/1757)).
### Breaking
* avm: `avm install` switches to the newly installed version after installation finishes ([#1670](https://github.com/project-serum/anchor/pull/1670)).
* spl: Re-export the `spl_token` crate ([#1665](https://github.com/project-serum/anchor/pull/1665)).
* lang, cli, spl: Update solana toolchain to v1.9.13 ([#1653](https://github.com/project-serum/anchor/pull/1653) and [#1751](https://github.com/project-serum/anchor/pull/1751)).
* lang: `Program` type now deserializes `programdata_address` only on demand ([#1723](https://github.com/project-serum/anchor/pull/1723)).
* ts: Make `Provider` an interface and adjust its signatures and add `AnchorProvider` implementor class ([#1707](https://github.com/project-serum/anchor/pull/1707)).
* spl: Change "to" to "from" in `token::burn` ([#1080](https://github.com/project-serum/anchor/pull/1080)).
## [0.23.0] - 2022-03-20
### Features
* cli: Add `anchor clean` command that's the same as `cargo clean` but preserves keypairs inside `target/deploy` ([#1470](https://github.com/project-serum/anchor/issues/1470)).
* cli: Running `anchor init` now initializes a new git repository for the workspace. This can be disabled with the `--no-git` flag ([#1605](https://github.com/project-serum/anchor/pull/1605)).
* cli: Add support for `anchor idl fetch` to work outside anchor workspace ([#1509](https://github.com/project-serum/anchor/pull/1509)).
* cli: [[test.validator.clone]] also clones the program data account of programs owned by the bpf upgradeable loader ([#1481](https://github.com/project-serum/anchor/issues/1481)).
* lang: Add new `AccountSysvarMismatch` error code and test cases for sysvars ([#1535](https://github.com/project-serum/anchor/pull/1535)).
* lang: Replace `std::io::Cursor` with a custom `Write` impl that uses the Solana mem syscalls ([#1589](https://github.com/project-serum/anchor/pull/1589)).
* lang: Add `require_neq`, `require_keys_neq`, `require_gt`, and `require_gte` comparison macros ([#1622](https://github.com/project-serum/anchor/pull/1622)).
* lang: Handle arrays with const as size in instruction data ([#1623](https://github.com/project-serum/anchor/issues/1623).
* spl: Add support for revoke instruction ([#1493](https://github.com/project-serum/anchor/pull/1493)).
* ts: Add provider parameter to `Spl.token` factory method ([#1597](https://github.com/project-serum/anchor/pull/1597)).
### Fixes
* ts: Fix the loss of strict typing using the `methods` namespace on builder functions ([#1539](https://github.com/project-serum/anchor/pull/1539)).
* spl: Update `spl/governance` to use new errors ([#1582](https://github.com/project-serum/anchor/pull/1582)).
* client: Fix `Cluster`'s `FromStr` implementation ([#1362](https://github.com/project-serum/anchor/pull/1362)).
* lang: Implement `Key` for `Pubkey` again, so `associated_token::*` constraints can use pubkey targets again ([#1601](https://github.com/project-serum/anchor/pull/1601)).
* lang: Adjust error code so `#[error_code]` works with just importing `anchor_lang::error_code` ([#1610](https://github.com/project-serum/anchor/pull/1610)).
* ts: Fix `spl-token` coder account parsing ([#1604](https://github.com/project-serum/anchor/pull/1604)).
* cli: Fix `npm install` fallback if `yarn` install doesn't work ([#1643](https://github.com/project-serum/anchor/pull/1643)).
* lang: Fix bug where `owner = <target>` would not compile because of missing type annotation ([#1648](https://github.com/project-serum/anchor/pull/1648)).
* ts: Adjust `send` and `simulate` functions in `provider.ts`, so they use the return value of `Wallet.signTransaction`([#1527](https://github.com/project-serum/anchor/pull/1527)).
### Breaking
* ts: Mark `transaction`, `instruction`, `simulate` and `rpc` program namespaces as deprecated in favor of `methods` ([#1539](https://github.com/project-serum/anchor/pull/1539)).
* ts: No longer allow manual setting of globally resolvable program public keys in `methods#accounts()`. ([#1548][https://github.com/project-serum/anchor/pull/1548])
* lang/ts: Events are now emitted using the `sol_log_data` syscall ([#1608](https://github.com/project-serum/anchor/pull/1608)).
* lang: Remove space calculation using `#[derive(Default)]` ([#1519](https://github.com/project-serum/anchor/pull/1519)).
* lang: Add support for logging expected and actual values and pubkeys. Add `require_eq` and `require_keys_eq` macros. Add default error code to `require` macro ([#1572](https://github.com/project-serum/anchor/pull/1572)).
* lang: Add `system_program` CPI wrapper functions. Make `system_program` module public instead of re-exporting `system_program::System`([#1629](https://github.com/project-serum/anchor/pull/1629)).
* cli: `avm use` no long prompts [y/n] if an install is needed first - it just tells the user to `avm install` ([#1565](https://github.com/project-serum/anchor/pull/1565))
* ts: Add `AnchorError` with program stack and also a program stack for non-`AnchorError` errors ([#1640](https://github.com/project-serum/anchor/pull/1640)). `AnchorError` is not returned for `processed` tx that have `skipPreflight` set to `true` (it falls back to `ProgramError` or the raw solana library error).
## [0.22.1] - 2022-02-28
### Fixes
* cli: Fix rust template ([#1488](https://github.com/project-serum/anchor/pull/1488)).
* lang: Handle array sizes with variable sizes in events and array size casting in IDL parsing ([#1485](https://github.com/project-serum/anchor/pull/1485))
## [0.22.0] - 2022-02-20
### 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)).
* cli: Add `--skip-lint` option to disable check linting introduced in ([#1452](https://github.com/project-serum/anchor/pull/1452)) for rapid prototyping ([#1482](https://github.com/project-serum/anchor/pull/1482)).
### Fixes
* ts: Allow nullable types for `Option<T>` mapped types ([#1428](https://github.com/project-serum/anchor/pull/1428)).
### Breaking
* lang: Enforce that the payer for an init-ed account be marked `mut` ([#1271](https://github.com/project-serum/anchor/pull/1271)).
* 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)).
* lang: add [`error!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.error.html) and [`err!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.err.html) macro and `Result` type ([#1462](https://github.com/project-serum/anchor/pull/1462)).
This change will break most programs. Do the following to upgrade:
* change all `ProgramResult`'s to `Result<()>`
* change `#[error]` to `#[error_code]`
* change all `Err(MyError::SomeError.into())` to `Err(error!(MyError::SomeError))` and all `Err(ProgramError::SomeProgramError)` to `Err(ProgramError::SomeProgramError.into())` or `Err(Error::from(ProgramError::SomeProgramError).with_source(source!()))` to provide file and line source of the error (`with_source` is most useful with `ProgramError`s. `error!` already adds source information for custom and anchor internal errors).
* change all `solana_program::program::invoke()` to `solana_program::program::invoke().map_err(Into::into)` and `solana_program::program::invoke_signed()` to `solana_program::program::invoke_signed().map_err(Into::into)`
## [0.21.0] - 2022-02-07
### Fixes
* ts: Fix the root type declaration of the `Wallet` / `NodeWallet` class ([#1363](https://github.com/project-serum/anchor/pull/1363)).
* ts: Improve type mapping of Account fields into Typescript with additional support for `Option<T>` and `Vec<String>` types ([#1393](https://github.com/project-serum/anchor/pull/1393)).
### Features
* lang: Add `seeds::program` constraint for specifying which program_id to use when deriving PDAs ([#1197](https://github.com/project-serum/anchor/pull/1197)).
* lang: `Context` now has a new `bumps: BTree<String, u8>` argument, mapping account name to bump seed "found" by the accounts context. This allows one to access bump seeds without having to pass them in from the client or recalculate them in the handler ([#1367](https://github.com/project-serum/anchor/pull/1367)).
* lang, ts: Automatically infer PDA addresses ([#1331](https://github.com/project-serum/anchor/pull/1331)).
* ts: Remove error logging in the event parser when log websocket encounters a program error ([#1313](https://github.com/project-serum/anchor/pull/1313)).
* ts: Add new `methods` namespace to the program client, introducing a more ergonomic builder API ([#1324](https://github.com/project-serum/anchor/pull/1324)).
* ts: Add registry utility for fetching the latest verified build ([#1371](https://github.com/project-serum/anchor/pull/1371)).
* cli: Expose the solana-test-validator --account flag in Anchor.toml via [[test.validator.account]] ([#1366](https://github.com/project-serum/anchor/pull/1366)).
* cli: Add avm, a tool for managing anchor-cli versions ([#1385](https://github.com/project-serum/anchor/pull/1385)).
### Breaking
* lang: Put `init_if_needed` behind a feature flag to decrease wrong usage ([#1258](https://github.com/project-serum/anchor/pull/1258)).
* lang: rename `loader_account` module to `account_loader` module ([#1279](https://github.com/project-serum/anchor/pull/1279))
* lang: The `Accounts` trait's `try_accounts` method now has an additional `bumps: &mut BTreeMap<String, u8>` argument, which accumulates bump seeds ([#1367](https://github.com/project-serum/anchor/pull/1367)).
* lang: Providing `bump = <target>` targets with `init` will now error. On `init` only, it is required to use `bump` without a target and access the seed inside function handlers via `ctx.bumps.get("<pda-account-name")`. For subsequent seeds constraints (without init), it is recommended to store the bump on your account and use it as a `bump = <target>` target to minimize compute units used ([#1380](https://github.com/project-serum/anchor/pull/1380)).
* ts: `Coder` is now an interface and the existing class has been renamed to `BorshCoder`. This change allows the generation of Anchor clients for non anchor programs ([#1259](https://github.com/project-serum/anchor/pull/1259/files)).
* cli: [[test.clone]] key in Anchor.toml is renamed to [[test.validator.clone]] ([#1366](https://github.com/project-serum/anchor/pull/1366)).
## [0.20.1] - 2022-01-09
### Fixes
* lang: Improved error msgs when required programs are missing when using the `init` constraint([#1257](https://github.com/project-serum/anchor/pull/1257))
### Features
* lang: Allow repr overrides for zero copy accounts ([#1273](https://github.com/project-serum/anchor/pull/1273)).
## [0.20.0] - 2022-01-06
### Fixes
* lang: `init_if_needed` now checks rent exemption when init is not needed ([#1250](https://github.com/project-serum/anchor/pull/1250)).
* lang: Add missing owner check when `associated_token::authority` is used ([#1240](https://github.com/project-serum/anchor/pull/1240)).
* ts: Add type declarations for conditional `workspace` and `Wallet` exports ([#1137](https://github.com/project-serum/anchor/pull/1137)).
* ts: Change commitment message `recent` to `processed` and `max` to `finalized` ([#1128](https://github.com/project-serum/anchor/pull/1128))
* ts: fix `translateAddress` which currently leads to failing browser code. Now uses `PublicKey` constructor instead of prototype chain constructor name checking which doesn't work in the presence of code minifying/mangling([#1138](https://github.com/project-serum/anchor/pull/1138))
* lang: add missing check that verifies that account is ATA when using `init_if_needed` and init is not needed([#1221](https://github.com/project-serum/anchor/pull/1221))
### Features
* lang: Add `programdata_address: Option<Pubkey>` field to `Program` account. Will be populated if account is a program owned by the upgradable bpf loader ([#1125](https://github.com/project-serum/anchor/pull/1125))
* lang,ts,ci,cli,docs: update solana toolchain to version 1.8.5([#1133](https://github.com/project-serum/anchor/pull/1133)).
* lang: Account wrappers for non-Anchor programs no longer have to implement the `serialize` function because it has a default impl now. Similarly, they no longer have to implement `try_deserialize` which now delegates to `try_deserialize_unchecked` by default([#1156](https://github.com/project-serum/anchor/pull/1156)).
* lang: Add `set_inner` method to `Account<'a, T>` to enable easy updates ([#1177](https://github.com/project-serum/anchor/pull/1177)).
* lang: Handle arrays with const as length ([#968](https://github.com/project-serum/anchor/pull/968)).
* ts: Add optional commitment argument to `fetch` and `fetchMultiple` ([#1171](https://github.com/project-serum/anchor/pull/1171)).
* lang: Implement `AsRef<T>` for `Account<'a, T>`([#1173](https://github.com/project-serum/anchor/pull/1173))
* cli: Add `anchor expand` command which wraps around `cargo expand` ([#1160](https://github.com/project-serum/anchor/pull/1160))
### Breaking
* client: Client::new and Client::new_with_options now accept `Rc<dyn Signer>` instead of `Keypair` ([#975](https://github.com/project-serum/anchor/pull/975)).
* lang, ts: Change error enum name and message for 'wrong program ownership' account validation ([#1154](https://github.com/project-serum/anchor/pull/1154)).
* lang: Change from `#[repr(packed)]` to `#[repr(C)]` for zero copy accounts ([#1106](https://github.com/project-serum/anchor/pull/1106)).
* lang: Account types can now be found either in the `prelude` module or the `accounts` module but not longer directly under the root.
Deprecated account types are no longer imported by the prelude ([#1208](https://github.com/project-serum/anchor/pull/1208)).
## [0.19.0] - 2021-12-08
### Fixes
* lang: Add `deprecated` attribute to `ProgramAccount` ([#1014](https://github.com/project-serum/anchor/pull/1014)).
* cli: Add version number from programs `Cargo.toml` into extracted IDL ([#1061](https://github.com/project-serum/anchor/pull/1061)).
* lang: Add `deprecated` attribute to `Loader`([#1078](https://github.com/project-serum/anchor/pull/1078)).
* lang: the `init_if_needed` attribute now checks that given attributes (e.g. space, owner, token::authority etc.) are validated even when init is not needed ([#1096](https://github.com/project-serum/anchor/pull/1096)).
### Features
* lang: Add `ErrorCode::AccountNotInitialized` error to separate the situation when the account has the wrong owner from when it does not exist (#[1024](https://github.com/project-serum/anchor/pull/1024)).
* lang: Called instructions now log their name by default. This can be turned off with the `no-log-ix-name` flag ([#1057](https://github.com/project-serum/anchor/pull/1057)).
* lang: `ProgramData` and `UpgradableLoaderState` can now be passed into `Account` as generics. see [UpgradeableLoaderState](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/enum.UpgradeableLoaderState.html). `UpgradableLoaderState` can also be matched on to get `ProgramData`, but when `ProgramData` is used instead, anchor does the serialization and checking that it is actually program data for you ([#1095](https://github.com/project-serum/anchor/pull/1095)).
* ts: Add better error msgs in the ts client if something wrong (i.e. not a pubkey or a string) is passed in as an account in an instruction accounts object ([#1098](https://github.com/project-serum/anchor/pull/1098)).
* ts: Add inputs `postInstructions` and `preInstructions` as a replacement for (the now deprecated) `instructions` ([#1007](https://github.com/project-serum/anchor/pull/1007)).
* ts: Add `getAccountInfo` helper method to account namespace/client ([#1084](https://github.com/project-serum/anchor/pull/1084)).
### Breaking
* lang, ts: Error codes have been mapped to new numbers to allow for more errors per namespace ([#1096](https://github.com/project-serum/anchor/pull/1096)).
## [0.18.2] - 2021-11-14
* cli: Replace global JavaScript dependency installs with local.
### Features
* lang: Add `SystemAccount<'info>` account type for generic wallet addresses or accounts owned by the system program ([#954](https://github.com/project-serum/anchor/pull/954))
### Fixes
* cli: fix dns in NODE_OPTIONS ([#928](https://github.com/project-serum/anchor/pull/928)).
* cli: output TypeScript IDL in `idl parse` subcommand ([#941](https://github.com/project-serum/anchor/pull/941)).
* cli: Add fields `os` and `cpu` to npm package `@project-serum/anchor-cli` ([#976](https://github.com/project-serum/anchor/pull/976)).
* cli: Allow specify output directory for TypeScript IDL ([#940](https://github.com/project-serum/anchor/pull/940)).
### Breaking
* spl: Move permissioned markets into dex repository ([#962](https://github.com/project-serum/anchor/pull/962)).
## [0.18.0] - 2021-10-24
### Features
* cli: Add support for configuration options for `solana-test-validator` in Anchor.toml ([#834](https://github.com/project-serum/anchor/pull/834)).
* cli: `target/types` directory now created on build to store a TypeScript types file for each program's IDL ([#795](https://github.com/project-serum/anchor/pull/795)).
* ts: `Program<T>` can now be typed with an IDL type ([#795](https://github.com/project-serum/anchor/pull/795)).
* lang: Add `mint::freeze_authority` keyword for mint initialization within `#[derive(Accounts)]` ([#835](https://github.com/project-serum/anchor/pull/835)).
* lang: Add `AccountLoader` type for `zero_copy` accounts with support for CPI ([#792](https://github.com/project-serum/anchor/pull/792)).
* lang: Add `#[account(init_if_needed)]` keyword for allowing one to invoke the same instruction even if the account was created already ([#906](https://github.com/project-serum/anchor/pull/906)).
* lang: Add custom errors support for raw constraints ([#905](https://github.com/project-serum/anchor/pull/905)).
* lang, cli, spl: Update solana toolchain to v1.8.0 ([#886](https://github.com/project-serum/anchor/pull/886)).
* lang: Add custom errors support for `signer`, `mut`, `has_one`, `owner`, raw constraints and `address` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)).
### Breaking
* lang: Accounts marked with the `#[account(signer)]` constraint now enforce signer when the `"cpi"` feature is enabled ([#849](https://github.com/project-serum/anchor/pull/849)).
## [0.17.0] - 2021-10-03
### Features
* cli: Add `localnet` command for starting a local `solana-test-validator` with the workspace deployed ([#820](https://github.com/project-serum/anchor/pull/820)).
### Breaking
* `CpiContext` accounts must now be used with the accounts struct generated in the `crate::cpi::accounts::*` module. These structs correspond to the accounts context for each instruction, except that each field is of type `AccountInfo` ([#824](https://github.com/project-serum/anchor/pull/824)).
## [0.16.2] - 2021-09-27
### Features
* lang: Add `--detach` flag to `anchor test` ([#770](https://github.com/project-serum/anchor/pull/770)).
* lang: Add `associated_token` keyword for initializing associated token accounts within `#[derive(Accounts)]` ([#790](https://github.com/project-serum/anchor/pull/790)).
* cli: Allow passing through cargo flags for build command ([#719](https://github.com/project-serum/anchor/pull/719)).
* cli: Allow passing through cargo flags for test, verify, and publish commands ([#804](https://github.com/project-serum/anchor/pull/804)).
### Fixes
* lang: Generated `AccountMeta`s for Rust clients now properly set the `isSigner` field ([#762](https://github.com/project-serum/anchor/pull/762)).
## [0.16.1] - 2021-09-17
### Fixes
* lang: `Signer` type now sets isSigner to true in the IDL ([#750](https://github.com/project-serum/anchor/pull/750)).
## [0.16.0] - 2021-09-16
### Features
* lang: `Program` type introduced for executable accounts ([#705](https://github.com/project-serum/anchor/pull/705)).
* lang: `Signer` type introduced for signing accounts where data is not used ([#705](https://github.com/project-serum/anchor/pull/705)).
* lang: `UncheckedAccount` type introduced as a preferred alias for `AccountInfo` ([#745](https://github.com/project-serum/anchor/pull/745)).
### Breaking Changes
* lang: `#[account(owner = <pubkey>)]` now requires a `Pubkey` instead of an account ([#691](https://github.com/project-serum/anchor/pull/691)).
## [0.15.0] - 2021-09-07
### Features
* lang: Add new `Account` type to replace `ProgramAccount` and `CpiAccount`, both of which are deprecated ([#686](https://github.com/project-serum/anchor/pull/686)).
* lang: `Box` can be used with `Account` types to reduce stack usage ([#686](https://github.com/project-serum/anchor/pull/686)).
* lang: Add `Owner` trait, which is automatically implemented by all `#[account]` structs ([#686](https://github.com/project-serum/anchor/pull/686)).
* lang: Check that ProgramAccount writable before mut borrow (`anchor-debug` only) ([#681](https://github.com/project-serum/anchor/pull/681)).
### Breaking Changes
* lang: All programs must now define their program id in source via `declare_id!` ([#686](https://github.com/project-serum/anchor/pull/686)).
## [0.14.0] - 2021-09-02
### Features
* lang: Ignore `Unnamed` structs instead of panic ([#605](https://github.com/project-serum/anchor/pull/605)).
* lang: Add constraints for initializing mint accounts as pdas, `#[account(init, seeds = [...], mint::decimals = <expr>, mint::authority = <expr>)]` ([#562](https://github.com/project-serum/anchor/pull/562)).
* lang: Add `AsRef<AccountInfo>` for `AccountInfo` wrappers ([#652](https://github.com/project-serum/anchor/pull/652)).
* lang: Optimize `trait Key` by removing `AccountInfo` cloning ([#652](https://github.com/project-serum/anchor/pull/652)).
* cli, client, lang: Update solana toolchain to v1.7.11 ([#653](https://github.com/project-serum/anchor/pull/653)).
### Breaking Changes
* lang: Change `#[account(init, seeds = [...], token = <expr>, authority = <expr>)]` to `#[account(init, token::mint = <expr> token::authority = <expr>)]` ([#562](https://github.com/project-serum/anchor/pull/562)).
* lang: `#[associated]` and `#[account(associated = <target>, with = <target>)]` are both removed ([#612](https://github.com/project-serum/anchor/pull/612)).
* cli: Removed `anchor launch` command ([#634](https://github.com/project-serum/anchor/pull/634)).
* lang: `#[account(init)]` now creates the account inside the same instruction to be consistent with initializing PDAs. To maintain the old behavior of `init`, replace it with `#[account(zero)]` ([#641](https://github.com/project-serum/anchor/pull/641)).
* lang: `bump` must be provided when using the `seeds` constraint. This has been added as an extra safety constraint to ensure that whenever a PDA is initialized via a constraint the bump used is the one created by `Pubkey::find_program_address` ([#641](https://github.com/project-serum/anchor/pull/641)).
* lang: `try_from_init` has been removed from `Loader`, `ProgramAccount`, and `CpiAccount` and replaced with `try_from_unchecked` ([#641](https://github.com/project-serum/anchor/pull/641)).
* lang: Remove `AccountsInit` trait ([#641](https://github.com/project-serum/anchor/pull/641)).
* lang: `try_from` methods for `ProgramAccount`, `Loader`, and `ProgramState` now take in an additional `program_id: &Pubkey` parameter ([#660](https://github.com/project-serum/anchor/pull/660)).
## [0.13.2] - 2021-08-11
### Fixes
* cli: Fix `anchor init` command "Workspace not found" regression ([#598](https://github.com/project-serum/anchor/pull/598)).
## [0.13.1] - 2021-08-10
### Features
* cli: Programs embedded into genesis during tests will produce program logs ([#594](https://github.com/project-serum/anchor/pull/594)).
### Fixes
* cli: Allows Cargo.lock to exist in workspace subdirectories when publishing ([#593](https://github.com/project-serum/anchor/pull/593)).
## [0.13.0] - 2021-08-08
### Features
* cli: Adds a `[registry]` section in the Anchor toml ([#570](https://github.com/project-serum/anchor/pull/570)).
* cli: Adds the `anchor login <api-token>` command ([#570](https://github.com/project-serum/anchor/pull/570)).
* cli: Adds the `anchor publish <package>` command ([#570](https://github.com/project-serum/anchor/pull/570)).
* cli: Adds a root level `anchor_version` field to the Anchor.toml for specifying the anchor docker image to use for verifiable builds ([#570](https://github.com/project-serum/anchor/pull/570)).
* cli: Adds a root level `solana_version` field to the Anchor.toml for specifying the solana toolchain to use for verifiable builds ([#570](https://github.com/project-serum/anchor/pull/570)).
* lang: Dynamically fetch rent sysvar for when using `init` ([#587](https://github.com/project-serum/anchor/pull/587)).
### Breaking
* cli: `[clusters.<network>]` Anchor.toml section has been renamed to `[programs.<network>]` ([#570](https://github.com/project-serum/anchor/pull/570)).
* cli: `[workspace]` member and exclude arrays must now be filepaths relative to the workpsace root ([#570](https://github.com/project-serum/anchor/pull/570)).
## [0.12.0] - 2021-08-03
### Features
* cli: Add keys `members` / `exclude` in config `programs` section ([#546](https://github.com/project-serum/anchor/pull/546)).
* cli: Allow program address configuration for test command through `clusters.localnet` ([#554](https://github.com/project-serum/anchor/pull/554)).
* lang: IDLs are now parsed from the entire crate ([#517](https://github.com/project-serum/anchor/pull/517)).
* spl: Dex permissioned markets proxy ([#519](https://github.com/project-serum/anchor/pull/519), [#543](https://github.com/project-serum/anchor/pull/543)).
### Breaking Changes
* ts: Use `hex` by default for decoding Instruction ([#547](https://github.com/project-serum/anchor/pull/547)).
* lang: `CpiAccount::reload` mutates the existing struct instead of returning a new one ([#526](https://github.com/project-serum/anchor/pull/526)).
* cli: Anchor.toml now requires an explicit `[scripts]` test command ([#550](https://github.com/project-serum/anchor/pull/550)).
## [0.11.1] - 2021-07-09
### Features
* lang: Adds `require` macro for specifying assertions that return error codes on failure ([#483](https://github.com/project-serum/anchor/pull/483)).
* lang: Allow one to specify arbitrary programs as the owner when creating PDA ([#483](https://github.com/project-serum/anchor/pull/483)).
* lang: A new `bump` keyword is added to the accounts constraints, which is used to add an optional bump seed to the end of a `seeds` array. When used in conjunction with *both* `init` and `seeds`, then the program executes `find_program_address` to assert that the given bump is the canonical bump ([#483](https://github.com/project-serum/anchor/pull/483)).
### Fixes
* lang: Preserve all instruction data for fallback functions ([#483](https://github.com/project-serum/anchor/pull/483)).
* ts: Event listener not firing when creating associated accounts ([#356](https://github.com/project-serum/anchor/issues/356)).
## [0.11.0] - 2021-07-03
### Features
* lang: Add fallback functions ([#457](https://github.com/project-serum/anchor/pull/457)).
* lang: Add feature flag for using the old state account discriminator. This is a temporary flag for those with programs built prior to v0.7.0 but want to use the latest Anchor version. Expect this to be removed in a future version ([#446](https://github.com/project-serum/anchor/pull/446)).
* lang: Add generic support to Accounts ([#496](https://github.com/project-serum/anchor/pull/496)).
### Breaking Changes
* cli: Remove `.spec` suffix on TypeScript tests files ([#441](https://github.com/project-serum/anchor/pull/441)).
* lang: Remove `belongs_to` constraint ([#459](https://github.com/project-serum/anchor/pull/459)).
## [0.10.0] - 2021-06-27
### Features
* lang: Add `#[account(address = <expr>)]` constraint for asserting the address of an account ([#400](https://github.com/project-serum/anchor/pull/400)).
* lang: Add `#[account(init, token = <mint-target>, authority = <token-owner-target>...)]` constraint for initializing SPL token accounts as program derived addresses for the program. Can be used when initialized via `seeds` or `associated` ([#400](https://github.com/project-serum/anchor/pull/400)).
* lang: Add `associated_seeds!` macro for generating signer seeds for CPIs signed by an `#[account(associated = <target>)]` account ([#400](https://github.com/project-serum/anchor/pull/400)).
* cli: Add `[scripts]` section to the Anchor.toml for specifying workspace scripts that can be run via `anchor run <script>` ([#400](https://github.com/project-serum/anchor/pull/400)).
* cli: `[clusters.<network>]` table entries can now also use `{ address = <base58-str>, idl = <filepath-str> }` to specify workspace programs ([#400](https://github.com/project-serum/anchor/pull/400)).
### Breaking Changes
* cli: Remove `--yarn` flag in favor of using `npx` ([#432](https://github.com/project-serum/anchor/pull/432)).
## [0.9.0] - 2021-06-15
### Features
* lang: Instruction data is now available to accounts constraints ([#386](https://github.com/project-serum/anchor/pull/386)).
* lang: Initialize program derived addresses with accounts constraints ([#386](https://github.com/project-serum/anchor/pull/386)).
### Breaking Changes
* lang: Event field names in IDLs are now mixed case. ([#379](https://github.com/project-serum/anchor/pull/379)).
* lang: Accounts trait now accepts an additional `&[u8]` parameter ([#386](https://github.com/project-serum/anchor/pull/386)).
## [0.8.0] - 2021-06-10
### Features
* cli: Add `--program-name` option for build command to build a single program at a time ([#362](https://github.com/project-serum/anchor/pull/362)).
* cli, client: Parse custom cluster urls from str ([#369](https://github.com/project-serum/anchor/pull/369)).
* cli, client, lang: Update solana toolchain to v1.7.1 ([#368](https://github.com/project-serum/anchor/pull/369)).
* ts: Instruction decoding and formatting ([#372](https://github.com/project-serum/anchor/pull/372)).
* lang: Add `#[account(close = <destination>)]` constraint for closing accounts and sending the rent exemption lamports to a specified destination account ([#371](https://github.com/project-serum/anchor/pull/371)).
### Fixes
* lang: Allows one to use `remaining_accounts` with `CpiContext` by implementing the `ToAccountMetas` trait on `CpiContext` ([#351](https://github.com/project-serum/anchor/pull/351/files)).
### Breaking
* lang, ts: Framework defined error codes are introduced, reserving error codes 0-300 for Anchor, and 300 and up for user defined error codes ([#354](https://github.com/project-serum/anchor/pull/354)).
## [0.7.0] - 2021-05-31
### Features
* cli: Add global options for override Anchor.toml values ([#313](https://github.com/project-serum/anchor/pull/313)).
* spl: Add `SetAuthority` instruction ([#307](https://github.com/project-serum/anchor/pull/307/files)).
* spl: Add init and close open orders instructions ([#245](https://github.com/project-serum/anchor/pull/245)).
* lang: `constraint = <expression>` added as a replacement for (the now deprecated) string literal constraints ([#341](https://github.com/project-serum/anchor/pull/341)).
* lang: Span information is now preserved, providing informative compiler error messages ([#341](https://github.com/project-serum/anchor/pull/341)).
* ts: Address metadata is now optional for `anchor.workspace` clients ([#310](https://github.com/project-serum/anchor/pull/310)).
### Breaking Changes
* ts: Retrieving deserialized accounts from the `<program>.account.<my-account>` and `<program>.state` namespaces now require explicitly invoking the `fetch` API. For example, `program.account.myAccount(<adddress>)` and `program.state()` is now `program.account.myAccount.fetch(<address>)` and `program.state.fetch()` ([#322](https://github.com/project-serum/anchor/pull/322)).
* lang: `#[account(associated)]` now requires `init` to be provided to create an associated account. If not provided, then the address will be assumed to exist, and a constraint will be added to ensure the correctness of the address ([#318](https://github.com/project-serum/anchor/pull/318)).
* lang, ts: Change account discriminator pre-image of the `#[state]` account discriminator to be namespaced by "state:" ([#320](https://github.com/project-serum/anchor/pull/320)).
* lang, ts: Change domain delimiters for the pre-image of the instruciton sighash to be a single colon `:` to be consistent with accounts ([#321](https://github.com/project-serum/anchor/pull/321)).
* lang: Associated constraints no longer automatically implement `mut` ([#341](https://github.com/project-serum/anchor/pull/341)).
* lang: Associated `space` constraints must now be literal integers instead of literal strings ([#341](https://github.com/project-serum/anchor/pull/341)).
## [0.6.0] - 2021-05-23
### Features
* ts: Add `program.simulate` namespace ([#266](https://github.com/project-serum/anchor/pull/266)).
* ts: Introduce `Address` type, allowing one to use Base 58 encoded strings in public APIs ([#304](https://github.com/project-serum/anchor/pull/304)).
* ts: Replace deprecated `web3.Account` with `web3.Signer` in public APIs ([#296](https://github.com/project-serum/anchor/pull/296)).
* ts: Generated `anchor.workspace` clients can now be customized per network with `[cluster.<slug>]` in the Anchor.toml ([#308](https://github.com/project-serum/anchor/pull/308)).
* cli: Add yarn flag to test command ([#267](https://github.com/project-serum/anchor/pull/267)).
* cli: Add `--skip-build` flag to test command ([301](https://github.com/project-serum/anchor/pull/301)).
* cli: Add `anchor shell` command to spawn a node shell populated with an Anchor.toml based environment ([#303](https://github.com/project-serum/anchor/pull/303)).
### Breaking Changes
* cli: The Anchor.toml's `wallet` and `cluster` settings must now be under the `[provider]` table ([#305](https://github.com/project-serum/anchor/pull/305)).
* ts: Event coder `decode` API changed to decode strings directly instead of buffers ([#292](https://github.com/project-serum/anchor/pull/292)).
* ts: Event coder `encode` API removed ([#292](https://github.com/project-serum/anchor/pull/292)).
## [0.5.0] - 2021-05-07
### Features
* client: Adds support for state instructions ([#248](https://github.com/project-serum/anchor/pull/248)).
* lang: Add `anchor-debug` feature flag for logging ([#253](https://github.com/project-serum/anchor/pull/253)).
* ts: Add support for u16 ([#255](https://github.com/project-serum/anchor/pull/255)).
### Breaking Changes
* client: Renames `RequestBuilder::new` to `RequestBuilder::from` ([#248](https://github.com/project-serum/anchor/pull/248)).
* lang: Renames the generated `instruction::state::Ctor` struct to `instruction::state::New` ([#248](https://github.com/project-serum/anchor/pull/248)).
## [0.4.5] - 2021-04-29
* spl: Add serum DEX CPI client ([#224](https://github.com/project-serum/anchor/pull/224)).
## [0.4.4] - 2021-04-18
### Features
* lang: Allows one to specify multiple `with` targets when creating associated acconts ([#197](https://github.com/project-serum/anchor/pull/197)).
* lang, ts: Add array support ([#202](https://github.com/project-serum/anchor/pull/202)).
* lang: Zero copy deserialization for accounts ([#202](https://github.com/project-serum/anchor/pull/202), [#206](https://github.com/project-serum/anchor/pull/206)).
* lang, spl, cli, client: Upgrade solana toolchain to 1.6.6 ([#210](https://github.com/project-serum/anchor/pull/210)).
## [0.4.3] - 2021-04-13
### Features
* lang: CPI clients for program state instructions ([#43](https://github.com/project-serum/anchor/pull/43)).
* lang: Add `#[account(owner = <program>)]` constraint ([#178](https://github.com/project-serum/anchor/pull/178)).
* lang, cli, ts: Add `#[account(associated = <target>)]` and `#[associated]` attributes for creating associated program accounts within programs. The TypeScript package can fetch these accounts with a new `<program>.account.<account-name>.associated` (and `associatedAddress`) method ([#186](https://github.com/project-serum/anchor/pull/186)).
### Fixes
* lang: Unused `#[account]`s are now parsed into the IDL correctly ([#177](https://github.com/project-serum/anchor/pull/177)).
## [0.4.2] - 2021-04-10
### Features
* cli: Fund Anchor.toml configured wallet when testing ([#164](https://github.com/project-serum/anchor/pull/164)).
* spl: Add initialize_account instruction for spl tokens ([#166](https://github.com/project-serum/anchor/pull/166)).
## [0.4.1] - 2021-04-06
* cli: Version verifiable docker builder ([#145](https://github.com/project-serum/anchor/pull/145)).
## [0.4.0] - 2021-04-04
### Features
* cli: Specify test files to run ([#118](https://github.com/project-serum/anchor/pull/118)).
* lang: Allow overriding the `#[state]` account's size ([#121](https://github.com/project-serum/anchor/pull/121)).
* lang, client, ts: Add event emission and subscriptions ([#89](https://github.com/project-serum/anchor/pull/89)).
* lang/account: Allow namespacing account discriminators ([#128](https://github.com/project-serum/anchor/pull/128)).
* cli: TypeScript migrations ([#132](https://github.com/project-serum/anchor/pull/132)).
* lang: Add `#[account(executable)]` attribute ([#140](https://github.com/project-serum/anchor/pull/140)).
### Breaking Changes
* client: Replace url str with `Cluster` struct when constructing clients ([#89](https://github.com/project-serum/anchor/pull/89)).
* lang: Changes the account discriminator of `IdlAccount` to be namespaced by `"internal"` ([#128](https://github.com/project-serum/anchor/pull/128)).
* lang, spl, cli: Upgrade solana toolchain to 1.6.3, a major version upgrade even though only the minor version is incremented. This allows for the removal of `-#![feature(proc_macro_hygiene)]`. ([#139](https://github.com/project-serum/anchor/pull/139)).
## [0.3.0] - 2021-03-12
### Features
* ts: Allow preloading instructions for state rpc transactions ([cf9c84](https://github.com/project-serum/anchor/commit/cf9c847e4144989b5bc1936149d171e90204777b)).
* ts: Export sighash coder function ([734c75](https://github.com/project-serum/anchor/commit/734c751882f43beec7ea3f0f4d988b502e3f24e4)).
* cli: Specify programs to embed into local validator genesis via Anchor.toml while testing ([b3803a](https://github.com/project-serum/anchor/commit/b3803aec03fbbae1a794c9aa6a789e6cb58fda99)).
* cli: Allow skipping the creation of a local validator when testing against localnet ([#93](https://github.com/project-serum/anchor/pull/93)).
* cli: Adds support for tests with Typescript ([#94](https://github.com/project-serum/anchor/pull/94)).
* cli: Deterministic and verifiable builds ([#100](https://github.com/project-serum/anchor/pull/100)).
* cli, lang: Add write buffers for IDL upgrades ([#107](https://github.com/project-serum/anchor/pull/107)).
## Breaking Changes
* lang: Removes `IdlInstruction::Clear` ([#107](https://github.com/project-serum/anchor/pull/107)).
### Fixes
* cli: Propagates mocha test exit status on error ([79b791](https://github.com/project-serum/anchor/commit/79b791ffa85ffae5b6163fa853562aa568650f21)).
## [0.2.1] - 2021-02-11
### Features
* cli: Embed workspace programs into local validator genesis when testing ([733ec3](https://github.com/project-serum/anchor/commit/733ec300b0308e7d007873b0975585d836333fd4)).
* cli: Stream program logs to `.anchor/program-logs` directory when testing ([ce5ca7](https://github.com/project-serum/anchor/commit/ce5ca7ddab6e0fd579deddcd02094b3f798bbe6a)).
* spl: Add shared memory api [(d92cb1)](https://github.com/project-serum/anchor/commit/d92cb1516b78696d1257e41d0c5ac6821716300e).
* lang/attribute/access-control: Allow specifying multiple modifier functions ([845df6](https://github.com/project-serum/anchor/commit/845df6d1960bb544fa0f2e3331ec79cc804edeb6)).
* lang/syn: Allow state structs that don't have a ctor or impl block (just trait implementations) ([a78000](https://github.com/project-serum/anchor/commit/a7800026833d64579e5b19c90d724ecc20d2a455)).
* ts: Add instruction method to state namespace ([627c27](https://github.com/project-serum/anchor/commit/627c275e9cdf3dafafcf44473ba8146cc7979d44)).
* lang/syn, ts: Add support for u128 and i128 ([#83](https://github.com/project-serum/anchor/pull/83)).
## [0.2.0] - 2021-02-08
### Features
* lang: Adds the ability to create and use CPI program interfaces ([#66](https://github.com/project-serum/anchor/pull/66/files?file-filters%5B%5D=)).
### Breaking Changes
* lang, client, ts: Migrate from rust enum based method dispatch to a variant of sighash ([#64](https://github.com/project-serum/anchor/pull/64)).
## [0.1.0] - 2021-01-31
Initial release.
### Includes
* lang: `anchor-lang` crate providing a Rust eDSL for Solana.
* lang/attribute/access-control: Internal attribute macro for function modifiers.
* lang/attribute/account: Internal attribute macro for defining Anchor accounts.
* lang/attribute/error: Internal attribute macro for defining Anchor program errors.
* lang/attribute/program: Internal attribute macro for defining an Anchor program.
* lang/attribute/state: Internal attribute macro for defining an Anchor program state struct.
* lang/derive/accounts: Internal derive macro for defining deserialized account structs.
* lang/syn: Internal crate for parsing the Anchor eDSL, generating code, and an IDL.
* spl: `anchor-spl` crate providing CPI clients for Anchor programs.
* client: `anchor-client` crate providing Rust clients for Anchor programs.
* ts: `@project-serum/anchor` package for generating TypeScript clients.
* cli: Command line interface for managing Anchor programs.

View File

@ -1,3 +0,0 @@
# Code of Conduct
The Anchor repository follows the Rust [Code of Conduct](https://www.rust-lang.org/conduct.html).

View File

@ -1,41 +0,0 @@
# Contributing to Anchor
Thank you for your interest in contributing to Anchor! All contributions are welcome no
matter how big or small. This includes (but is not limited to) filing issues,
adding documentation, fixing bugs, creating examples, and implementing features.
## Finding issues to work on
If you're looking to get started,
check out [good first issues](https://github.com/project-serum/anchor/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
or issues where [help is wanted](https://github.com/project-serum/anchor/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22).
For simple documentation changes or typos, 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).
## Choosing an issue
If you'd like to contribute, please claim an issue by commenting, forking, and
opening a pull request, even if empty. This allows the maintainers to track who
is working on what issue as to not overlap work.
## Issue Guidelines
Please follow these guidelines:
Before coding:
- choose a branch name that describes the issue you're working on
- enable [commit signing](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
While coding:
- Submit a draft PR asap
- Only change code directly relevant to your PR. Sometimes you might find some code that could really need some refactoring. However, if it's not relevant to your PR, do not touch it. File an issue instead. This allows the reviewer to focus on a single problem at a time.
- If you write comments, do not exceed 80 chars per line. This allows contributors who work with multiple open windows to still read the comments without horizontally scrolling.
- Write adversarial tests. For example, if you're adding a new account type, do not only write tests where the instruction succeeds. Also write tests that test whether the instruction fails, if a check inside the new type is violated.
After coding:
- If you've moved code around, build the docs with `cargo doc --open` and adjust broken links
- Adjust the cli templates if necessary
- If you made a change to anchor's periphery (avm or cli), make a PR to the `anchor-book` repo if necessary
- If you've added a new folder to the `tests` directory, add it to the [CI](./.github/workflows/tests.yaml).

4097
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
[profile.release]
lto = true
[profile.release.package.anchor-cli]
codegen-units = 1
[workspace]
members = [
"cli",
"client",
"lang",
"lang/attribute/*",
"lang/derive/*",
"lang/syn",
"spl",
]
exclude = [
"tests/swap/deps/serum-dex",
"tests/cfo/deps/serum-dex",
"tests/permissioned-markets/deps/serum-dex",
]

202
LICENSE
View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 Serum Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,38 +0,0 @@
.PHONY: build-cli
build-cli:
cargo build -p anchor-cli --release
cp target/release/anchor cli/npm-package/anchor
.PHONY: clean
clean:
find . -type d -name .anchor -print0 | xargs -0 rm -rf
find . -type d -name node_modules -print0 | xargs -0 rm -rf
find . -type d -name target -print0 | xargs -0 rm -rf
.PHONY: publish
publish:
cd lang/syn/ && cargo publish && cd ../../
sleep 25
cd lang/derive/accounts/ && cargo publish && cd ../../../
sleep 25
cd lang/attribute/access-control/ && cargo publish && cd ../../../
sleep 25
cd lang/attribute/account/ && cargo publish && cd ../../../
sleep 25
cd lang/attribute/constant/ && cargo publish && cd ../../../
sleep 25
cd lang/attribute/error/ && cargo publish && cd ../../../
sleep 25
cd lang/attribute/interface/ && cargo publish && cd ../../../
sleep 25
cd lang/attribute/program/ && cargo publish && cd ../../..
sleep 25
cd lang/attribute/state/ && cargo publish && cd ../../../
sleep 25
cd lang/attribute/event/ && cargo publish && cd ../../../
sleep 25
cd lang/ && cargo publish && cd ../
sleep 25
cd spl/ && cargo publish && cd ../
sleep 25
cd client/ && cargo publish && cd ../

119
README.md
View File

@ -1,119 +1,10 @@
<div align="center">
<img height="170x" src="https://media.discordapp.net/attachments/813444514949103658/890278520553603092/export.png?width=746&height=746" />
# @project-serum/anchor
<h1>Anchor</h1>
[![npm](https://img.shields.io/npm/v/@project-serum/anchor.svg?color=blue)](https://www.npmjs.com/package/@project-serum/anchor)
[![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://project-serum.github.io/anchor/ts/index.html)
<p>
<strong>Solana Sealevel Framework</strong>
</p>
<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.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>
Anchor is a framework for Solana's [Sealevel](https://medium.com/solana-labs/sealevel-parallel-processing-thousands-of-smart-contracts-d814b378192) runtime providing several convenient developer tools for writing smart contracts.
- Rust eDSL for writing Solana programs
- [IDL](https://en.wikipedia.org/wiki/Interface_description_language) specification
- TypeScript package for generating clients from IDL
- CLI and workspace management for developing complete applications
If you're familiar with developing in Ethereum's [Solidity](https://docs.soliditylang.org/en/v0.7.4/), [Truffle](https://www.trufflesuite.com/), [web3.js](https://github.com/ethereum/web3.js), then the experience will be familiar. Although the DSL syntax and semantics are targeted at Solana, the high level flow of writing RPC request handlers, emitting an IDL, and generating clients from IDL is the same.
## Getting Started
For a quickstart guide and in depth tutorials, see the [anchor book](https://book.anchor-lang.com) and the older [documentation](https://project-serum.github.io/anchor/getting-started/introduction.html) that is being phased out.
To jump straight to examples, go [here](https://github.com/project-serum/anchor/tree/master/examples). For the latest Rust and TypeScript API documentation, see [docs.rs](https://docs.rs/anchor-lang) and the [typedoc](https://project-serum.github.io/anchor/ts/index.html).
## Packages
| Package | Description | Version | Docs |
| :-- | :-- | :--| :-- |
| `anchor-lang` | Rust primitives for writing programs on Solana | [![Crates.io](https://img.shields.io/crates/v/anchor-lang?color=blue)](https://crates.io/crates/anchor-lang) | [![Docs.rs](https://docs.rs/anchor-lang/badge.svg)](https://docs.rs/anchor-lang) |
| `anchor-spl` | CPI clients for SPL programs on Solana | ![crates](https://img.shields.io/crates/v/anchor-spl?color=blue) | [![Docs.rs](https://docs.rs/anchor-spl/badge.svg)](https://docs.rs/anchor-spl) |
| `anchor-client` | Rust client for Anchor programs | ![crates](https://img.shields.io/crates/v/anchor-client?color=blue) | [![Docs.rs](https://docs.rs/anchor-client/badge.svg)](https://docs.rs/anchor-client) |
| `@project-serum/anchor` | TypeScript client for Anchor programs | [![npm](https://img.shields.io/npm/v/@project-serum/anchor.svg?color=blue)](https://www.npmjs.com/package/@project-serum/anchor) | [![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://project-serum.github.io/anchor/ts/index.html) |
| `@project-serum/anchor-cli` | CLI to support building and managing an Anchor workspace | [![npm](https://img.shields.io/npm/v/@project-serum/anchor-cli.svg?color=blue)](https://www.npmjs.com/package/@project-serum/anchor-cli) | [![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://project-serum.github.io/anchor/cli/commands.html) |
TypeScript client for Anchor programs.
## Note
* **Anchor is in active development, so all APIs are subject to change.**
* **This code is unaudited. Use at your own risk.**
## Examples
Here's a counter program, where only the designated `authority`
can increment the count.
```rust
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
mod counter {
use super::*;
pub fn initialize(ctx: Context<Initialize>, start: u64) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.authority = *ctx.accounts.authority.key;
counter.count = start;
Ok(())
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.count += 1;
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = authority, space = 48)]
pub counter: Account<'info, Counter>,
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut, has_one = authority)]
pub counter: Account<'info, Counter>,
pub authority: Signer<'info>,
}
#[account]
pub struct Counter {
pub authority: Pubkey,
pub count: u64,
}
```
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!
Please see the [CONTRIBUTING.md](./CONTRIBUTING.md) to learn how.
### Thanks ❤️
<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>
* `@project-serum/anchor` depends on node.js native modules. Therefore, webpack 5 will not work with current version. You will either need to rollback to webpack 4, or use a polyfill for each missing dependency.

View File

@ -1 +0,0 @@
0.24.2

1174
avm/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +0,0 @@
[package]
name = "avm"
version = "0.24.2"
rust-version = "1.56"
edition = "2021"
[[bin]]
name = "avm"
path = "src/main.rs"
[[bin]]
name = "anchor"
path = "src/anchor/main.rs"
[dependencies]
clap = { version = "3.0.13", features = [ "derive" ]}
cfg-if = "1.0.0"
anyhow = "1.0.32"
dirs = "1.0.5"
semver = "1.0.4"
serde = { version = "1.0.136", features = [ "derive" ]}
serde_json = "1.0.78"
thiserror = "1.0.30"
once_cell = { version = "1.8.0" }
reqwest = { version = "0.11.9", features = ['blocking', 'json'] }
tempfile = "3.3.0"
[workspace]

View File

@ -1,24 +0,0 @@
use std::{env, fs, process::Command};
fn main() -> anyhow::Result<()> {
let args = env::args().skip(1).collect::<Vec<String>>();
let version = avm::current_version()
.map_err(|_e| anyhow::anyhow!("Anchor version not set. Please run `avm use latest`."))?;
let binary_path = avm::version_binary_path(&version);
if fs::metadata(&binary_path).is_err() {
anyhow::bail!(
"anchor-cli {} not installed. Please run `avm use {}`.",
version,
version
);
}
Command::new(binary_path)
.args(args)
.spawn()?
.wait_with_output()
.expect("Failed to run anchor-cli");
Ok(())
}

View File

@ -1,316 +0,0 @@
use anyhow::{anyhow, Result};
use once_cell::sync::Lazy;
use reqwest::header::USER_AGENT;
use semver::Version;
use serde::{de, Deserialize};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process::Stdio;
/// Storage directory for AVM, ~/.avm
pub static AVM_HOME: Lazy<PathBuf> = Lazy::new(|| {
cfg_if::cfg_if! {
if #[cfg(test)] {
let dir = tempfile::tempdir().expect("Could not create temporary directory");
dir.path().join(".avm")
} else {
let mut user_home = dirs::home_dir().expect("Could not find home directory");
user_home.push(".avm");
user_home
}
}
});
/// Path to the current version file ~/.avm/.version
pub fn current_version_file_path() -> PathBuf {
let mut current_version_file_path = AVM_HOME.to_path_buf();
current_version_file_path.push(".version");
current_version_file_path
}
/// Read the current version from the version file
pub fn current_version() -> Result<Version> {
let v = fs::read_to_string(current_version_file_path().as_path())
.map_err(|e| anyhow!("Could not read version file: {}", e))?;
Version::parse(v.trim_end_matches('\n').to_string().as_str())
.map_err(|e| anyhow!("Could not parse version file: {}", e))
}
/// Path to the binary for the given version
pub fn version_binary_path(version: &Version) -> PathBuf {
let mut version_path = AVM_HOME.join("bin");
version_path.push(format!("anchor-{}", version));
version_path
}
/// Update the current version to a new version
pub fn use_version(version: &Version) -> Result<()> {
let installed_versions = read_installed_versions();
// Make sure the requested version is installed
if !installed_versions.contains(version) {
if let Ok(current) = current_version() {
println!(
"Version {} is not installed, staying on version {}.",
version, current
);
} else {
println!("Version {} is not installed, no current version.", version);
}
return Err(anyhow!(
"You need to run 'avm install {}' to install it before using it.",
version
));
}
let mut current_version_file = fs::File::create(current_version_file_path().as_path())?;
current_version_file.write_all(version.to_string().as_bytes())?;
println!("Now using anchor version {}.", current_version()?);
Ok(())
}
/// Update to the latest version
pub fn update() -> Result<()> {
// Find last stable version
let version = &get_latest_version();
install_version(version, false)
}
/// Install a version of anchor-cli
pub fn install_version(version: &Version, force: bool) -> Result<()> {
// If version is already installed we ignore the request.
let installed_versions = read_installed_versions();
if installed_versions.contains(version) && !force {
println!("Version {} is already installed", version);
return Ok(());
}
let exit = std::process::Command::new("cargo")
.args(&[
"install",
"--git",
"https://github.com/project-serum/anchor",
"--tag",
&format!("v{}", &version),
"anchor-cli",
"--locked",
"--root",
AVM_HOME.to_str().unwrap(),
])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.map_err(|e| {
anyhow::format_err!("Cargo install for {} failed: {}", version, e.to_string())
})?;
if !exit.status.success() {
return Err(anyhow!(
"Failed to install {}, is it a valid version?",
version
));
}
fs::rename(
&AVM_HOME.join("bin").join("anchor"),
&AVM_HOME.join("bin").join(format!("anchor-{}", version)),
)?;
// If .version file is empty or not parseable, write the newly installed version to it
if current_version().is_err() {
let mut current_version_file = fs::File::create(current_version_file_path().as_path())?;
current_version_file.write_all(version.to_string().as_bytes())?;
}
use_version(version)
}
/// Remove an installed version of anchor-cli
pub fn uninstall_version(version: &Version) -> Result<()> {
let version_path = AVM_HOME.join("bin").join(format!("anchor-{}", version));
if !version_path.exists() {
return Err(anyhow!("anchor-cli {} is not installed", version));
}
if version == &current_version().unwrap() {
return Err(anyhow!("anchor-cli {} is currently in use", version));
}
fs::remove_file(version_path.as_path())?;
Ok(())
}
/// Ensure the users home directory is setup with the paths required by AVM.
pub fn ensure_paths() {
let home_dir = AVM_HOME.to_path_buf();
if !home_dir.as_path().exists() {
fs::create_dir_all(home_dir.clone()).expect("Could not create .avm directory");
}
let bin_dir = home_dir.join("bin");
if !bin_dir.as_path().exists() {
fs::create_dir_all(bin_dir).expect("Could not create .avm/bin directory");
}
if !current_version_file_path().exists() {
fs::File::create(current_version_file_path()).expect("Could not create .version file");
}
}
/// Retrieve a list of installable versions of anchor-cli using the GitHub API and tags on the Anchor
/// repository.
pub fn fetch_versions() -> Vec<semver::Version> {
#[derive(Deserialize)]
struct Release {
#[serde(rename = "name", deserialize_with = "version_deserializer")]
version: semver::Version,
}
fn version_deserializer<'de, D>(deserializer: D) -> Result<semver::Version, D::Error>
where
D: de::Deserializer<'de>,
{
let s: &str = de::Deserialize::deserialize(deserializer)?;
Version::parse(s.trim_start_matches('v')).map_err(de::Error::custom)
}
let client = reqwest::blocking::Client::new();
let versions: Vec<Release> = client
.get("https://api.github.com/repos/project-serum/anchor/tags")
.header(USER_AGENT, "avm https://github.com/project-serum/anchor")
.send()
.unwrap()
.json()
.unwrap();
versions.into_iter().map(|r| r.version).collect()
}
/// Print available versions and flags indicating installed, current and latest
pub fn list_versions() -> Result<()> {
let installed_versions = read_installed_versions();
let mut available_versions = fetch_versions();
// Reverse version list so latest versions are printed last
available_versions.reverse();
available_versions.iter().enumerate().for_each(|(i, v)| {
print!("{}", v);
let mut flags = vec![];
if i == available_versions.len() - 1 {
flags.push("latest");
}
if installed_versions.contains(v) {
flags.push("installed");
}
if current_version().is_ok() && current_version().unwrap() == v.clone() {
flags.push("current");
}
if flags.is_empty() {
println!();
} else {
println!("\t({})", flags.join(", "));
}
});
Ok(())
}
pub fn get_latest_version() -> semver::Version {
let available_versions = fetch_versions();
available_versions.first().unwrap().clone()
}
/// Read the installed anchor-cli versions by reading the binaries in the AVM_HOME/bin directory.
pub fn read_installed_versions() -> Vec<semver::Version> {
let home_dir = AVM_HOME.to_path_buf();
let mut versions = vec![];
for file in fs::read_dir(&home_dir.join("bin")).unwrap() {
let file_name = file.unwrap().file_name();
// Match only things that look like anchor-*
if file_name.to_str().unwrap().starts_with("anchor-") {
let version = file_name
.to_str()
.unwrap()
.trim_start_matches("anchor-")
.parse::<semver::Version>()
.unwrap();
versions.push(version);
}
}
versions
}
#[cfg(test)]
mod tests {
use crate::*;
use semver::Version;
use std::fs;
use std::io::Write;
#[test]
fn test_ensure_paths() {
ensure_paths();
assert!(AVM_HOME.exists());
let bin_dir = AVM_HOME.join("bin");
assert!(bin_dir.exists());
let current_version_file = AVM_HOME.join(".version");
assert!(current_version_file.exists());
}
#[test]
fn test_current_version_file_path() {
ensure_paths();
assert!(current_version_file_path().exists());
}
#[test]
fn test_version_binary_path() {
assert!(
version_binary_path(&Version::parse("0.18.2").unwrap())
== AVM_HOME.join("bin/anchor-0.18.2")
);
}
#[test]
fn test_current_version() {
ensure_paths();
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());
}
#[test]
#[should_panic(expected = "anchor-cli 0.18.1 is not installed")]
fn test_uninstall_non_installed_version() {
uninstall_version(&Version::parse("0.18.1").unwrap()).unwrap();
}
#[test]
#[should_panic(expected = "anchor-cli 0.18.2 is currently in use")]
fn test_uninstalled_in_use_version() {
ensure_paths();
let version = Version::parse("0.18.2").unwrap();
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();
}
#[test]
fn test_read_installed_versions() {
ensure_paths();
let version = Version::parse("0.18.2").unwrap();
// Create a fake binary for anchor-0.18.2 in the bin directory
fs::File::create(version_binary_path(&version)).unwrap();
let expected = vec![version];
assert!(read_installed_versions() == expected);
// Should ignore this file because its not anchor- prefixed
fs::File::create(AVM_HOME.join("bin").join("garbage").as_path()).unwrap();
assert!(read_installed_versions() == expected);
}
}

View File

@ -1,65 +0,0 @@
use anyhow::{Error, Result};
use clap::{Parser, Subcommand};
use semver::Version;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[derive(Parser)]
#[clap(name = "avm", about = "Anchor version manager", version)]
pub struct Cli {
#[clap(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
#[clap(about = "Use a specific version of Anchor")]
Use {
#[clap(parse(try_from_str = parse_version))]
version: Version,
},
#[clap(about = "Install a version of Anchor")]
Install {
#[clap(parse(try_from_str = parse_version))]
version: Version,
#[clap(long)]
/// Flag to force installation even if the version
/// is already installed
force: bool,
},
#[clap(about = "Uninstall a version of Anchor")]
Uninstall {
#[clap(parse(try_from_str = parse_version))]
version: Version,
},
#[clap(about = "List available versions of Anchor")]
List {},
#[clap(about = "Update to the latest Anchor version")]
Update {},
}
// If `latest` is passed use the latest available version.
fn parse_version(version: &str) -> Result<Version, Error> {
if version == "latest" {
Ok(avm::get_latest_version())
} else {
Version::parse(version).map_err(|e| anyhow::anyhow!(e))
}
}
pub fn entry(opts: Cli) -> Result<()> {
match opts.command {
Commands::Use { version } => avm::use_version(&version),
Commands::Install { version, force } => avm::install_version(&version, force),
Commands::Uninstall { version } => avm::uninstall_version(&version),
Commands::List {} => avm::list_versions(),
Commands::Update {} => avm::update(),
}
}
fn main() -> Result<()> {
// Make sure the user's home directory is setup with the paths required by AVM.
avm::ensure_paths();
let opt = Cli::parse();
entry(opt)
}

View File

@ -1,44 +0,0 @@
[package]
name = "anchor-cli"
version = "0.24.2"
authors = ["armaniferrante <armaniferrante@gmail.com>"]
rust-version = "1.56"
edition = "2021"
[[bin]]
name = "anchor"
path = "src/bin/main.rs"
[features]
dev = []
default = []
[dependencies]
clap = { version = "3.0.13", features = ["derive"] }
anyhow = "1.0.32"
syn = { version = "1.0.60", features = ["full", "extra-traits"] }
anchor-lang = { path = "../lang" }
anchor-client = { path = "../client" }
anchor-syn = { path = "../lang/syn", features = ["idl", "init-if-needed"] }
serde_json = "1.0"
shellexpand = "2.1.0"
toml = "0.5.8"
semver = "1.0.4"
serde = { version = "1.0.122", features = ["derive"] }
solana-sdk = "~1.9.13"
solana-program = "~1.9.13"
solana-client = "~1.9.13"
solana-cli-config = "~1.9.13"
solana-faucet = "~1.9.13"
dirs = "3.0"
heck = "0.3.1"
flate2 = "1.0.19"
rand = "0.7.3"
tar = "0.4.35"
reqwest = { version = "0.11.4", features = ["multipart", "blocking"] }
tokio = "1.0"
pathdiff = "0.2.0"
cargo_toml = "0.9.2"
walkdir = "2.3.2"
chrono = "0.4.19"
portpicker = "0.1.1"

View File

@ -1,97 +0,0 @@
#!/usr/bin/env node
const fs = require("fs");
const { spawn, spawnSync } = require("child_process");
const path = require("path");
const { arch, platform } = require("os");
const { version } = require("./package.json");
const PACKAGE_VERSION = `anchor-cli ${version}`;
const PACKAGE_ANCHOR_PATH = path.join(__dirname, "anchor");
function getBinaryVersion(location) {
const result = spawnSync(location, ["--version"]);
const error =
(result.error && result.error.toString()) ||
(result.stderr.length > 0 && result.stderr.toString().trim()) ||
null;
return [error, result.stdout && result.stdout.toString().trim()];
}
function runAnchor(location) {
const args = process.argv.slice(2);
const anchor = spawn(location, args, { stdio: "inherit" });
anchor.on("exit", (code, signal) => {
process.on("exit", () => {
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit(code);
}
});
});
process.on("SIGINT", function () {
anchor.kill("SIGINT");
anchor.kill("SIGTERM");
});
}
function tryPackageAnchor() {
if (arch() !== "x64" || platform() !== "linux") {
console.error(`Only x86_64 / Linux distributed in NPM package right now.`);
return false;
}
const [error, binaryVersion] = getBinaryVersion(PACKAGE_ANCHOR_PATH);
if (error !== null) {
console.error(`Failed to get version of local binary: ${error}`);
return false;
}
if (binaryVersion !== PACKAGE_VERSION) {
console.error(
`Package binary version is not correct. Expected "${PACKAGE_VERSION}", found "${binaryVersion}".`
);
return false;
}
runAnchor(PACKAGE_ANCHOR_PATH);
return true;
}
function trySystemAnchor() {
console.error("Trying globally installed anchor.");
const absolutePath = process.env.PATH.split(":")
.filter((dir) => dir !== path.dirname(process.argv[1]))
.find((dir) => {
try {
fs.accessSync(`${dir}/anchor`, fs.constants.X_OK);
} catch {
return false;
}
return true;
});
if (!absolutePath) {
console.error(`Could not find globally installed anchor, install with cargo.`);
process.exit();
}
const absoluteBinaryPath = `${absolutePath}/anchor`;
const [error, binaryVersion] = getBinaryVersion(absoluteBinaryPath);
if (error !== null) {
console.error(`Failed to get version of global binary: ${error}`);
return;
}
if (binaryVersion !== PACKAGE_VERSION) {
console.error(
`Globally installed anchor version is not correct. Expected "${PACKAGE_VERSION}", found "${binaryVersion}".`
);
return;
}
runAnchor(absoluteBinaryPath);
}
tryPackageAnchor() || trySystemAnchor();

View File

@ -1,23 +0,0 @@
{
"name": "@project-serum/anchor-cli",
"version": "0.24.2",
"description": "Anchor CLI tool",
"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"
},
"license": "(MIT OR Apache-2.0)",
"bin": {
"anchor": "./anchor.js"
},
"scripts": {
"prepack": "[ \"$(uname -op)\" != \"x86_64 GNU/Linux\" ] && (echo Can be packed only on x86_64 GNU/Linux && exit 1) || ([ \"$(./anchor --version)\" != \"anchor-cli $(jq -r .version package.json)\" ] && (echo Check anchor binary version && exit 2) || exit 0)"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,7 +0,0 @@
use anchor_cli::Opts;
use anyhow::Result;
use clap::Parser;
fn main() -> Result<()> {
anchor_cli::entry(Opts::parse())
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +0,0 @@
#[macro_export]
macro_rules! home_path {
($my_struct:ident, $path:literal) => {
#[derive(Clone, Debug)]
pub struct $my_struct(String);
impl Default for $my_struct {
fn default() -> Self {
match dirs::home_dir() {
None => {
println!("$HOME doesn't exist. This probably won't do what you want.");
$my_struct(".".to_string())
}
Some(mut path) => {
path.push($path);
$my_struct(path.as_path().display().to_string())
}
}
}
}
impl ToString for $my_struct {
fn to_string(&self) -> String {
self.0.clone()
}
}
impl FromStr for $my_struct {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.to_string()))
}
}
};
}

View File

@ -1,376 +0,0 @@
use crate::config::ProgramWorkspace;
use crate::VERSION;
use anchor_syn::idl::Idl;
use anyhow::Result;
use heck::{CamelCase, MixedCase, SnakeCase};
use solana_sdk::pubkey::Pubkey;
pub fn default_program_id() -> Pubkey {
"Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
.parse()
.unwrap()
}
pub fn virtual_manifest() -> &'static str {
r#"[workspace]
members = [
"programs/*"
]
"#
}
pub fn credentials(token: &str) -> String {
format!(
r#"[registry]
token = "{}"
"#,
token
)
}
pub fn idl_ts(idl: &Idl) -> Result<String> {
let mut idl = idl.clone();
for acc in idl.accounts.iter_mut() {
acc.name = acc.name.to_mixed_case();
}
let idl_json = serde_json::to_string_pretty(&idl)?;
Ok(format!(
r#"export type {} = {};
export const IDL: {} = {};
"#,
idl.name.to_camel_case(),
idl_json,
idl.name.to_camel_case(),
idl_json
))
}
pub fn cargo_toml(name: &str) -> String {
format!(
r#"[package]
name = "{0}"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "{1}"
[features]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
default = []
[profile.release]
overflow-checks = true
[dependencies]
anchor-lang = "{2}"
"#,
name,
name.to_snake_case(),
VERSION,
)
}
pub fn deploy_js_script_host(cluster_url: &str, script_path: &str) -> String {
format!(
r#"
const anchor = require('@project-serum/anchor');
// Deploy script defined by the user.
const userScript = require("{0}");
async function main() {{
const url = "{1}";
const preflightCommitment = 'recent';
const connection = new anchor.web3.Connection(url, preflightCommitment);
const wallet = anchor.Wallet.local();
const provider = new anchor.AnchorProvider(connection, wallet, {{
preflightCommitment,
commitment: 'recent',
}});
// Run the user's deploy script.
userScript(provider);
}}
main();
"#,
script_path, cluster_url,
)
}
pub fn deploy_ts_script_host(cluster_url: &str, script_path: &str) -> String {
format!(
r#"import * as anchor from '@project-serum/anchor';
// Deploy script defined by the user.
const userScript = require("{0}");
async function main() {{
const url = "{1}";
const preflightCommitment = 'recent';
const connection = new anchor.web3.Connection(url, preflightCommitment);
const wallet = anchor.Wallet.local();
const provider = new anchor.AnchorProvider(connection, wallet, {{
preflightCommitment,
commitment: 'recent',
}});
// Run the user's deploy script.
userScript(provider);
}}
main();
"#,
script_path, cluster_url,
)
}
pub fn deploy_script() -> &'static str {
r#"// 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.
};
"#
}
pub fn ts_deploy_script() -> &'static str {
r#"// 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.
};
"#
}
pub fn xargo_toml() -> &'static str {
r#"[target.bpfel-unknown-unknown.dependencies.std]
features = []
"#
}
pub fn lib_rs(name: &str) -> String {
format!(
r#"use anchor_lang::prelude::*;
declare_id!("{}");
#[program]
pub mod {} {{
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {{
Ok(())
}}
}}
#[derive(Accounts)]
pub struct Initialize {{}}
"#,
default_program_id(),
name.to_snake_case(),
)
}
pub fn mocha(name: &str) -> String {
format!(
r#"const anchor = require("@project-serum/anchor");
describe("{}", () => {{
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.env());
it("Is initialized!", async () => {{
// Add your test here.
const program = anchor.workspace.{};
const tx = await program.methods.initialize().rpc();
console.log("Your transaction signature", tx);
}});
}});
"#,
name,
name.to_camel_case(),
)
}
pub fn package_json() -> String {
format!(
r#"{{
"scripts": {{
"lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
"lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
}},
"dependencies": {{
"@project-serum/anchor": "^{0}"
}},
"devDependencies": {{
"chai": "^4.3.4",
"mocha": "^9.0.3",
"prettier": "^2.6.2"
}}
}}
"#,
VERSION
)
}
pub fn ts_package_json() -> String {
format!(
r#"{{
"scripts": {{
"lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
"lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
}},
"dependencies": {{
"@project-serum/anchor": "^{0}"
}},
"devDependencies": {{
"chai": "^4.3.4",
"mocha": "^9.0.3",
"ts-mocha": "^8.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"
}}
}}
"#,
VERSION
)
}
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("{}", () => {{
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.{} as Program<{}>;
it("Is initialized!", async () => {{
// Add your test here.
const tx = await program.methods.initialize().rpc();
console.log("Your transaction signature", tx);
}});
}});
"#,
name.to_camel_case(),
name.to_snake_case(),
name,
name.to_camel_case(),
name.to_camel_case(),
)
}
pub fn ts_config() -> &'static str {
r#"{
"compilerOptions": {
"types": ["mocha", "chai"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2015"],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true
}
}
"#
}
pub fn git_ignore() -> &'static str {
r#"
.anchor
.DS_Store
target
**/*.rs.bk
node_modules
test-ledger
"#
}
pub fn prettier_ignore() -> &'static str {
r#"
.anchor
.DS_Store
target
node_modules
dist
build
test-ledger
"#
}
pub fn node_shell(
cluster_url: &str,
wallet_path: &str,
programs: Vec<ProgramWorkspace>,
) -> Result<String> {
let mut eval_string = format!(
r#"
const anchor = require('@project-serum/anchor');
const web3 = anchor.web3;
const PublicKey = anchor.web3.PublicKey;
const Keypair = anchor.web3.Keypair;
const __wallet = new anchor.Wallet(
Keypair.fromSecretKey(
Buffer.from(
JSON.parse(
require('fs').readFileSync(
"{}",
{{
encoding: "utf-8",
}},
),
),
),
),
);
const __connection = new web3.Connection("{}", "processed");
const provider = new anchor.AnchorProvider(__connection, __wallet, {{
commitment: "processed",
preflightcommitment: "processed",
}});
anchor.setProvider(provider);
"#,
wallet_path, cluster_url,
);
for program in programs {
eval_string.push_str(&format!(
r#"
anchor.workspace.{} = new anchor.Program({}, new PublicKey("{}"), provider);
"#,
program.name.to_camel_case(),
serde_json::to_string(&program.idl)?,
program.program_id
));
}
Ok(eval_string)
}

View File

@ -1,22 +0,0 @@
[package]
name = "anchor-client"
version = "0.24.2"
authors = ["Serum Foundation <foundation@projectserum.com>"]
rust-version = "1.56"
edition = "2021"
license = "Apache-2.0"
description = "Rust client for Anchor programs"
[features]
debug = []
[dependencies]
anchor-lang = { path = "../lang", version = "0.24.2" }
anyhow = "1.0.32"
regex = "1.4.5"
serde = { version = "1.0.122", features = ["derive"] }
solana-client = "~1.9.13"
solana-sdk = "~1.9.13"
solana-account-decoder = "~1.9.13"
thiserror = "1.0.20"
url = "2.2.2"

View File

@ -1,20 +0,0 @@
[package]
name = "example"
version = "0.1.0"
authors = ["Armani Ferrante <armaniferrante@gmail.com>"]
rust-version = "1.56"
edition = "2021"
[workspace]
[dependencies]
anchor-client = { path = "../", features = ["debug"] }
basic-2 = { path = "../../examples/tutorial/basic-2/programs/basic-2", features = ["no-entrypoint"] }
basic-4 = { path = "../../examples/tutorial/basic-4/programs/basic-4", features = ["no-entrypoint"] }
composite = { path = "../../tests/composite/programs/composite", features = ["no-entrypoint"] }
events = { path = "../../tests/events/programs/events", features = ["no-entrypoint"] }
shellexpand = "2.1.0"
anyhow = "1.0.32"
rand = "0.7.3"
clap = { version = "3.0.0-rc.0", features = ["derive"] }
solana-sdk = "~1.9.13"

View File

@ -1,66 +0,0 @@
#!/bin/bash
################################################################################
#
# A script to run the example as an integration test. It starts up a localnet
# and executes the current directory's rust binary.
#
# Usage:
#
# ./run.sh
#
# Run this script from within the `example/` directory in which it is located.
# The anchor cli must be installed.
#
# cargo install --git https://github.com/project-serum/anchor anchor-cli --locked
#
################################################################################
set -euox pipefail
main() {
#
# Build programs.
#
local composite_pid="EHthziFziNoac9LBGxEaVN47Y3uUiRoXvqAiR6oes4iU"
local basic_2_pid="Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
local basic_4_pid="CwrqeMj2U8tFr1Rhkgwc84tpAsqbt9pTt2a4taoTADPr"
local events_pid="2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy"
#
# Bootup validator.
#
solana-test-validator -r \
--bpf-program $composite_pid ../../tests/composite/target/deploy/composite.so \
--bpf-program $basic_2_pid ../../examples/tutorial/basic-2/target/deploy/basic_2.so \
--bpf-program $basic_4_pid ../../examples/tutorial/basic-4/target/deploy/basic_4.so \
--bpf-program $events_pid ../../tests/events/target/deploy/events.so \
> test-validator.log &
sleep 5
#
# Run Test.
#
cargo run -- --composite-pid $composite_pid --basic-2-pid $basic_2_pid --basic-4-pid $basic_4_pid --events-pid $events_pid
}
cleanup() {
pkill -P $$ || true
wait || true
}
trap_add() {
trap_add_cmd=$1; shift || fatal "${FUNCNAME} usage error"
for trap_add_name in "$@"; do
trap -- "$(
extract_trap_cmd() { printf '%s\n' "${3:-}"; }
eval "extract_trap_cmd $(trap -p "${trap_add_name}")"
printf '%s\n' "${trap_add_cmd}"
)" "${trap_add_name}" \
|| fatal "unable to add to trap ${trap_add_name}"
done
}
declare -f -t trap_add
trap_add 'cleanup' EXIT
main

View File

@ -1,229 +0,0 @@
use anchor_client::solana_sdk::commitment_config::CommitmentConfig;
use anchor_client::solana_sdk::pubkey::Pubkey;
use anchor_client::solana_sdk::signature::read_keypair_file;
use anchor_client::solana_sdk::signature::{Keypair, Signer};
use anchor_client::solana_sdk::system_instruction;
use anchor_client::{Client, Cluster, EventContext};
use anyhow::Result;
use solana_sdk::system_program;
// The `accounts` and `instructions` modules are generated by the framework.
use basic_2::accounts as basic_2_accounts;
use basic_2::instruction as basic_2_instruction;
use basic_2::Counter;
use events::instruction as events_instruction;
use events::MyEvent;
// The `accounts` and `instructions` modules are generated by the framework.
use basic_4::accounts as basic_4_accounts;
use basic_4::basic_4::Counter as CounterState;
use basic_4::instruction as basic_4_instruction;
use clap::Parser;
// The `accounts` and `instructions` modules are generated by the framework.
use composite::accounts::{Bar, CompositeUpdate, Foo, Initialize};
use composite::instruction as composite_instruction;
use composite::{DummyA, DummyB};
use rand::rngs::OsRng;
use std::rc::Rc;
use std::time::Duration;
#[derive(Parser, Debug)]
pub struct Opts {
#[clap(long)]
composite_pid: Pubkey,
#[clap(long)]
basic_2_pid: Pubkey,
#[clap(long)]
basic_4_pid: Pubkey,
#[clap(long)]
events_pid: Pubkey,
}
// This example assumes a local validator is running with the programs
// deployed at the addresses given by the CLI args.
fn main() -> Result<()> {
println!("Starting test...");
let opts = Opts::parse();
// Wallet and cluster params.
let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json"))
.expect("Example requires a keypair file");
let url = Cluster::Custom(
"http://localhost:8899".to_string(),
"ws://127.0.0.1:8900".to_string(),
);
// Client.
let client = Client::new_with_options(url, Rc::new(payer), CommitmentConfig::processed());
// Run tests.
composite(&client, opts.composite_pid)?;
basic_2(&client, opts.basic_2_pid)?;
basic_4(&client, opts.basic_4_pid)?;
events(&client, opts.events_pid)?;
// Success.
Ok(())
}
// Runs a client for examples/tutorial/composite.
//
// Make sure to run a localnet with the program deploy to run this example.
fn composite(client: &Client, pid: Pubkey) -> Result<()> {
// Program client.
let program = client.program(pid);
// `Initialize` parameters.
let dummy_a = Keypair::generate(&mut OsRng);
let dummy_b = Keypair::generate(&mut OsRng);
// Build and send a transaction.
program
.request()
.instruction(system_instruction::create_account(
&program.payer(),
&dummy_a.pubkey(),
program.rpc().get_minimum_balance_for_rent_exemption(500)?,
500,
&program.id(),
))
.instruction(system_instruction::create_account(
&program.payer(),
&dummy_b.pubkey(),
program.rpc().get_minimum_balance_for_rent_exemption(500)?,
500,
&program.id(),
))
.signer(&dummy_a)
.signer(&dummy_b)
.accounts(Initialize {
dummy_a: dummy_a.pubkey(),
dummy_b: dummy_b.pubkey(),
})
.args(composite_instruction::Initialize)
.send()?;
// Assert the transaction worked.
let dummy_a_account: DummyA = program.account(dummy_a.pubkey())?;
let dummy_b_account: DummyB = program.account(dummy_b.pubkey())?;
assert_eq!(dummy_a_account.data, 0);
assert_eq!(dummy_b_account.data, 0);
// Build and send another transaction, using composite account parameters.
program
.request()
.accounts(CompositeUpdate {
foo: Foo {
dummy_a: dummy_a.pubkey(),
},
bar: Bar {
dummy_b: dummy_b.pubkey(),
},
})
.args(composite_instruction::CompositeUpdate {
dummy_a: 1234,
dummy_b: 4321,
})
.send()?;
// Assert the transaction worked.
let dummy_a_account: DummyA = program.account(dummy_a.pubkey())?;
let dummy_b_account: DummyB = program.account(dummy_b.pubkey())?;
assert_eq!(dummy_a_account.data, 1234);
assert_eq!(dummy_b_account.data, 4321);
println!("Composite success!");
Ok(())
}
// Runs a client for examples/tutorial/basic-2.
//
// Make sure to run a localnet with the program deploy to run this example.
fn basic_2(client: &Client, pid: Pubkey) -> Result<()> {
let program = client.program(pid);
// `Create` parameters.
let counter = Keypair::generate(&mut OsRng);
let authority = program.payer();
// Build and send a transaction.
program
.request()
.signer(&counter)
.accounts(basic_2_accounts::Create {
counter: counter.pubkey(),
user: authority,
system_program: system_program::ID,
})
.args(basic_2_instruction::Create { authority })
.send()?;
let counter_account: Counter = program.account(counter.pubkey())?;
assert_eq!(counter_account.authority, authority);
assert_eq!(counter_account.count, 0);
println!("Basic 2 success!");
Ok(())
}
fn events(client: &Client, pid: Pubkey) -> Result<()> {
let program = client.program(pid);
let (sender, receiver) = std::sync::mpsc::channel();
let handle = program.on(move |_ctx: &EventContext, event: MyEvent| {
sender.send(event).unwrap();
})?;
std::thread::sleep(Duration::from_millis(1000));
program
.request()
.args(events_instruction::Initialize {})
.send()?;
let event = receiver.recv().unwrap();
assert_eq!(event.data, 5);
assert_eq!(event.label, "hello".to_string());
// TODO: remove once https://github.com/solana-labs/solana/issues/16102
// is addressed. Until then, drop the subscription handle in another
// thread so that we deadlock in the other thread as to not block
// this thread.
std::thread::spawn(move || {
drop(handle);
});
println!("Events success!");
Ok(())
}
pub fn basic_4(client: &Client, pid: Pubkey) -> Result<()> {
let program = client.program(pid);
let authority = program.payer();
// Invoke the state's `new` constructor.
program
.state_request()
.accounts(basic_4_accounts::Auth { authority })
.new(basic_4_instruction::state::New)
.send()?;
let counter_account: CounterState = program.state()?;
assert_eq!(counter_account.authority, authority);
assert_eq!(counter_account.count, 0);
// Call a state method.
program
.state_request()
.accounts(basic_4_accounts::Auth { authority })
.args(basic_4_instruction::state::Increment)
.send()?;
let counter_account: CounterState = program.state()?;
assert_eq!(counter_account.authority, authority);
assert_eq!(counter_account.count, 1);
println!("Basic 4 success!");
Ok(())
}

View File

@ -1,169 +0,0 @@
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use url::Url;
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Cluster {
Testnet,
Mainnet,
Devnet,
Localnet,
Debug,
Custom(String, String),
}
impl Default for Cluster {
fn default() -> Self {
Cluster::Localnet
}
}
impl FromStr for Cluster {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Cluster> {
match s.to_lowercase().as_str() {
"t" | "testnet" => Ok(Cluster::Testnet),
"m" | "mainnet" => Ok(Cluster::Mainnet),
"d" | "devnet" => Ok(Cluster::Devnet),
"l" | "localnet" => Ok(Cluster::Localnet),
"g" | "debug" => Ok(Cluster::Debug),
_ if s.starts_with("http") => {
let http_url = s;
// Taken from:
// https://github.com/solana-labs/solana/blob/aea8f0df1610248d29d8ca3bc0d60e9fabc99e31/web3.js/src/util/url.ts
let mut ws_url = Url::parse(http_url)?;
if let Some(port) = ws_url.port() {
ws_url.set_port(Some(port + 1))
.map_err(|_| anyhow!("Unable to set port"))?;
}
if ws_url.scheme() == "https" {
ws_url.set_scheme("wss")
.map_err(|_| anyhow!("Unable to set scheme"))?;
} else {
ws_url.set_scheme("ws")
.map_err(|_| anyhow!("Unable to set scheme"))?;
}
Ok(Cluster::Custom(http_url.to_string(), ws_url.to_string()))
}
_ => Err(anyhow::Error::msg(
"Cluster must be one of [localnet, testnet, mainnet, devnet] or be an http or https url\n",
)),
}
}
}
impl std::fmt::Display for Cluster {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let clust_str = match self {
Cluster::Testnet => "testnet",
Cluster::Mainnet => "mainnet",
Cluster::Devnet => "devnet",
Cluster::Localnet => "localnet",
Cluster::Debug => "debug",
Cluster::Custom(url, _ws_url) => url,
};
write!(f, "{}", clust_str)
}
}
impl Cluster {
pub fn url(&self) -> &str {
match self {
Cluster::Devnet => "https://api.devnet.solana.com",
Cluster::Testnet => "https://api.testnet.solana.com",
Cluster::Mainnet => "https://api.mainnet-beta.solana.com",
Cluster::Localnet => "http://127.0.0.1:8899",
Cluster::Debug => "http://34.90.18.145:8899",
Cluster::Custom(url, _ws_url) => url,
}
}
pub fn ws_url(&self) -> &str {
match self {
Cluster::Devnet => "wss://api.devnet.solana.com",
Cluster::Testnet => "wss://api.testnet.solana.com",
Cluster::Mainnet => "wss://api.mainnet-beta.solana.com",
Cluster::Localnet => "ws://127.0.0.1:9000",
Cluster::Debug => "ws://34.90.18.145:9000",
Cluster::Custom(_url, ws_url) => ws_url,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_cluster(name: &str, cluster: Cluster) {
assert_eq!(Cluster::from_str(name).unwrap(), cluster);
}
#[test]
fn test_cluster_parse() {
test_cluster("testnet", Cluster::Testnet);
test_cluster("mainnet", Cluster::Mainnet);
test_cluster("devnet", Cluster::Devnet);
test_cluster("localnet", Cluster::Localnet);
test_cluster("debug", Cluster::Debug);
}
#[test]
#[should_panic]
fn test_cluster_bad_parse() {
let bad_url = "httq://my_custom_url.test.net";
Cluster::from_str(bad_url).unwrap();
}
#[test]
fn test_http_port() {
let url = "http://my-url.com:7000/";
let cluster = Cluster::from_str(url).unwrap();
assert_eq!(
Cluster::Custom(url.to_string(), "ws://my-url.com:7001/".to_string()),
cluster
);
}
#[test]
fn test_http_no_port() {
let url = "http://my-url.com/";
let cluster = Cluster::from_str(url).unwrap();
assert_eq!(
Cluster::Custom(url.to_string(), "ws://my-url.com/".to_string()),
cluster
);
}
#[test]
fn test_https_port() {
let url = "https://my-url.com:7000/";
let cluster = Cluster::from_str(url).unwrap();
assert_eq!(
Cluster::Custom(url.to_string(), "wss://my-url.com:7001/".to_string()),
cluster
);
}
#[test]
fn test_https_no_port() {
let url = "https://my-url.com/";
let cluster = Cluster::from_str(url).unwrap();
assert_eq!(
Cluster::Custom(url.to_string(), "wss://my-url.com/".to_string()),
cluster
);
}
#[test]
fn test_upper_case() {
let url = "http://my-url.com/FooBar";
let cluster = Cluster::from_str(url).unwrap();
assert_eq!(
Cluster::Custom(url.to_string(), "ws://my-url.com/FooBar".to_string()),
cluster
);
}
}

View File

@ -1,591 +0,0 @@
//! `anchor_client` provides an RPC client to send transactions and fetch
//! deserialized accounts from Solana programs written in `anchor_lang`.
use anchor_lang::solana_program::instruction::{AccountMeta, Instruction};
use anchor_lang::solana_program::program_error::ProgramError;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::solana_program::system_program;
use anchor_lang::{AccountDeserialize, Discriminator, InstructionData, ToAccountMetas};
use regex::Regex;
use solana_account_decoder::UiAccountEncoding;
use solana_client::client_error::ClientError as SolanaClientError;
use solana_client::pubsub_client::{PubsubClient, PubsubClientError, PubsubClientSubscription};
use solana_client::rpc_client::RpcClient;
use solana_client::rpc_config::{
RpcAccountInfoConfig, RpcProgramAccountsConfig, RpcTransactionLogsConfig,
RpcTransactionLogsFilter,
};
use solana_client::rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType};
use solana_client::rpc_response::{Response as RpcResponse, RpcLogsResponse};
use solana_sdk::account::Account;
use solana_sdk::bs58;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::signature::{Signature, Signer};
use solana_sdk::transaction::Transaction;
use std::convert::Into;
use std::iter::Map;
use std::rc::Rc;
use std::vec::IntoIter;
use thiserror::Error;
pub use anchor_lang;
pub use cluster::Cluster;
pub use solana_client;
pub use solana_sdk;
mod cluster;
const PROGRAM_LOG: &str = "Program log: ";
const PROGRAM_DATA: &str = "Program data: ";
/// EventHandle unsubscribes from a program event stream on drop.
pub type EventHandle = PubsubClientSubscription<RpcResponse<RpcLogsResponse>>;
/// Client defines the base configuration for building RPC clients to
/// communicate with Anchor programs running on a Solana cluster. It's
/// primary use is to build a `Program` client via the `program` method.
pub struct Client {
cfg: Config,
}
impl Client {
pub fn new(cluster: Cluster, payer: Rc<dyn Signer>) -> Self {
Self {
cfg: Config {
cluster,
payer,
options: None,
},
}
}
pub fn new_with_options(
cluster: Cluster,
payer: Rc<dyn Signer>,
options: CommitmentConfig,
) -> Self {
Self {
cfg: Config {
cluster,
payer,
options: Some(options),
},
}
}
pub fn program(&self, program_id: Pubkey) -> Program {
Program {
program_id,
cfg: Config {
cluster: self.cfg.cluster.clone(),
options: self.cfg.options,
payer: self.cfg.payer.clone(),
},
}
}
}
// Internal configuration for a client.
#[derive(Debug)]
struct Config {
cluster: Cluster,
payer: Rc<dyn Signer>,
options: Option<CommitmentConfig>,
}
/// Program is the primary client handle to be used to build and send requests.
#[derive(Debug)]
pub struct Program {
program_id: Pubkey,
cfg: Config,
}
impl Program {
pub fn payer(&self) -> Pubkey {
self.cfg.payer.pubkey()
}
/// Returns a request builder.
pub fn request(&self) -> RequestBuilder {
RequestBuilder::from(
self.program_id,
self.cfg.cluster.url(),
self.cfg.payer.clone(),
self.cfg.options,
RequestNamespace::Global,
)
}
/// Returns a request builder for program state.
pub fn state_request(&self) -> RequestBuilder {
RequestBuilder::from(
self.program_id,
self.cfg.cluster.url(),
self.cfg.payer.clone(),
self.cfg.options,
RequestNamespace::State { new: false },
)
}
/// Returns the account at the given address.
pub fn account<T: AccountDeserialize>(&self, address: Pubkey) -> Result<T, ClientError> {
let rpc_client = RpcClient::new_with_commitment(
self.cfg.cluster.url().to_string(),
self.cfg.options.unwrap_or_default(),
);
let account = rpc_client
.get_account_with_commitment(&address, CommitmentConfig::processed())?
.value
.ok_or(ClientError::AccountNotFound)?;
let mut data: &[u8] = &account.data;
T::try_deserialize(&mut data).map_err(Into::into)
}
/// Returns all program accounts of the given type matching the given filters
pub fn accounts<T: AccountDeserialize + Discriminator>(
&self,
filters: Vec<RpcFilterType>,
) -> Result<Vec<(Pubkey, T)>, ClientError> {
self.accounts_lazy(filters)?.collect()
}
/// Returns all program accounts of the given type matching the given filters as an iterator
/// Deserialization is executed lazily
pub fn accounts_lazy<T: AccountDeserialize + Discriminator>(
&self,
filters: Vec<RpcFilterType>,
) -> Result<ProgramAccountsIterator<T>, ClientError> {
let account_type_filter = RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Base58(bs58::encode(T::discriminator()).into_string()),
encoding: None,
});
let config = RpcProgramAccountsConfig {
filters: Some([vec![account_type_filter], filters].concat()),
account_config: RpcAccountInfoConfig {
encoding: Some(UiAccountEncoding::Base64),
data_slice: None,
commitment: None,
},
with_context: None,
};
Ok(ProgramAccountsIterator {
inner: self
.rpc()
.get_program_accounts_with_config(&self.id(), config)?
.into_iter()
.map(|(key, account)| {
Ok((key, T::try_deserialize(&mut (&account.data as &[u8]))?))
}),
})
}
pub fn state<T: AccountDeserialize>(&self) -> Result<T, ClientError> {
self.account(anchor_lang::__private::state::address(&self.program_id))
}
pub fn rpc(&self) -> RpcClient {
RpcClient::new_with_commitment(
self.cfg.cluster.url().to_string(),
self.cfg.options.unwrap_or_default(),
)
}
pub fn id(&self) -> Pubkey {
self.program_id
}
pub fn on<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
&self,
f: impl Fn(&EventContext, T) + Send + 'static,
) -> Result<EventHandle, ClientError> {
let addresses = vec![self.program_id.to_string()];
let filter = RpcTransactionLogsFilter::Mentions(addresses);
let ws_url = self.cfg.cluster.ws_url().to_string();
let cfg = RpcTransactionLogsConfig {
commitment: self.cfg.options,
};
let self_program_str = self.program_id.to_string();
let (client, receiver) = PubsubClient::logs_subscribe(&ws_url, filter, cfg)?;
std::thread::spawn(move || {
loop {
match receiver.recv() {
Ok(logs) => {
let ctx = EventContext {
signature: logs.value.signature.parse().unwrap(),
slot: logs.context.slot,
};
let mut logs = &logs.value.logs[..];
if !logs.is_empty() {
if let Ok(mut execution) = Execution::new(&mut logs) {
for l in logs {
// Parse the log.
let (event, new_program, did_pop) = {
if self_program_str == execution.program() {
handle_program_log(&self_program_str, l).unwrap_or_else(
|e| {
println!("Unable to parse log: {}", e);
std::process::exit(1);
},
)
} else {
let (program, did_pop) =
handle_system_log(&self_program_str, l);
(None, program, did_pop)
}
};
// Emit the event.
if let Some(e) = event {
f(&ctx, e);
}
// Switch program context on CPI.
if let Some(new_program) = new_program {
execution.push(new_program);
}
// Program returned.
if did_pop {
execution.pop();
}
}
}
}
}
Err(_err) => {
return;
}
}
}
});
Ok(client)
}
}
/// Iterator with items of type (Pubkey, T). Used to lazily deserialize account structs.
/// Wrapper type hides the inner type from usages so the implementation can be changed.
pub struct ProgramAccountsIterator<T> {
inner: Map<IntoIter<(Pubkey, Account)>, AccountConverterFunction<T>>,
}
/// Function type that accepts solana accounts and returns deserialized anchor accounts
type AccountConverterFunction<T> = fn((Pubkey, Account)) -> Result<(Pubkey, T), ClientError>;
impl<T> Iterator for ProgramAccountsIterator<T> {
type Item = Result<(Pubkey, T), ClientError>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
fn handle_program_log<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
self_program_str: &str,
l: &str,
) -> Result<(Option<T>, Option<String>, bool), ClientError> {
// Log emitted from the current program.
if let Some(log) = l
.strip_prefix(PROGRAM_LOG)
.or_else(|| l.strip_prefix(PROGRAM_DATA))
{
let borsh_bytes = match anchor_lang::__private::base64::decode(&log) {
Ok(borsh_bytes) => borsh_bytes,
_ => {
#[cfg(feature = "debug")]
println!("Could not base64 decode log: {}", log);
return Ok((None, None, false));
}
};
let mut slice: &[u8] = &borsh_bytes[..];
let disc: [u8; 8] = {
let mut disc = [0; 8];
disc.copy_from_slice(&borsh_bytes[..8]);
slice = &slice[8..];
disc
};
let mut event = None;
if disc == T::discriminator() {
let e: T = anchor_lang::AnchorDeserialize::deserialize(&mut slice)
.map_err(|e| ClientError::LogParseError(e.to_string()))?;
event = Some(e);
}
Ok((event, None, false))
}
// System log.
else {
let (program, did_pop) = handle_system_log(self_program_str, l);
Ok((None, program, did_pop))
}
}
fn handle_system_log(this_program_str: &str, log: &str) -> (Option<String>, bool) {
if log.starts_with(&format!("Program {} log:", this_program_str)) {
(Some(this_program_str.to_string()), false)
} else if log.contains("invoke") {
(Some("cpi".to_string()), false) // Any string will do.
} else {
let re = Regex::new(r"^Program (.*) success*$").unwrap();
if re.is_match(log) {
(None, true)
} else {
(None, false)
}
}
}
struct Execution {
stack: Vec<String>,
}
impl Execution {
pub fn new(logs: &mut &[String]) -> Result<Self, ClientError> {
let l = &logs[0];
*logs = &logs[1..];
let re = Regex::new(r"^Program (.*) invoke.*$").unwrap();
let c = re
.captures(l)
.ok_or_else(|| ClientError::LogParseError(l.to_string()))?;
let program = c
.get(1)
.ok_or_else(|| ClientError::LogParseError(l.to_string()))?
.as_str()
.to_string();
Ok(Self {
stack: vec![program],
})
}
pub fn program(&self) -> String {
assert!(!self.stack.is_empty());
self.stack[self.stack.len() - 1].clone()
}
pub fn push(&mut self, new_program: String) {
self.stack.push(new_program);
}
pub fn pop(&mut self) {
assert!(!self.stack.is_empty());
self.stack.pop().unwrap();
}
}
#[derive(Debug)]
pub struct EventContext {
pub signature: Signature,
pub slot: u64,
}
#[derive(Debug, Error)]
pub enum ClientError {
#[error("Account not found")]
AccountNotFound,
#[error("{0}")]
AnchorError(#[from] anchor_lang::error::Error),
#[error("{0}")]
ProgramError(#[from] ProgramError),
#[error("{0}")]
SolanaClientError(#[from] SolanaClientError),
#[error("{0}")]
SolanaClientPubsubError(#[from] PubsubClientError),
#[error("Unable to parse log: {0}")]
LogParseError(String),
}
/// `RequestBuilder` provides a builder interface to create and send
/// transactions to a cluster.
pub struct RequestBuilder<'a> {
cluster: String,
program_id: Pubkey,
accounts: Vec<AccountMeta>,
options: CommitmentConfig,
instructions: Vec<Instruction>,
payer: Rc<dyn Signer>,
// Serialized instruction data for the target RPC.
instruction_data: Option<Vec<u8>>,
signers: Vec<&'a dyn Signer>,
// True if the user is sending a state instruction.
namespace: RequestNamespace,
}
#[derive(PartialEq)]
pub enum RequestNamespace {
Global,
State {
// True if the request is to the state's new ctor.
new: bool,
},
Interface,
}
impl<'a> RequestBuilder<'a> {
pub fn from(
program_id: Pubkey,
cluster: &str,
payer: Rc<dyn Signer>,
options: Option<CommitmentConfig>,
namespace: RequestNamespace,
) -> Self {
Self {
program_id,
payer,
cluster: cluster.to_string(),
accounts: Vec::new(),
options: options.unwrap_or_default(),
instructions: Vec::new(),
instruction_data: None,
signers: Vec::new(),
namespace,
}
}
#[must_use]
pub fn payer(mut self, payer: Rc<dyn Signer>) -> Self {
self.payer = payer;
self
}
#[must_use]
pub fn cluster(mut self, url: &str) -> Self {
self.cluster = url.to_string();
self
}
#[must_use]
pub fn instruction(mut self, ix: Instruction) -> Self {
self.instructions.push(ix);
self
}
#[must_use]
pub fn program(mut self, program_id: Pubkey) -> Self {
self.program_id = program_id;
self
}
#[must_use]
pub fn accounts(mut self, accounts: impl ToAccountMetas) -> Self {
let mut metas = accounts.to_account_metas(None);
self.accounts.append(&mut metas);
self
}
#[must_use]
pub fn options(mut self, options: CommitmentConfig) -> Self {
self.options = options;
self
}
#[must_use]
pub fn args(mut self, args: impl InstructionData) -> Self {
self.instruction_data = Some(args.data());
self
}
/// Invokes the `#[state]`'s `new` constructor.
#[allow(clippy::wrong_self_convention)]
#[must_use]
pub fn new(mut self, args: impl InstructionData) -> Self {
assert!(self.namespace == RequestNamespace::State { new: false });
self.namespace = RequestNamespace::State { new: true };
self.instruction_data = Some(args.data());
self
}
#[must_use]
pub fn signer(mut self, signer: &'a dyn Signer) -> Self {
self.signers.push(signer);
self
}
pub fn instructions(&self) -> Result<Vec<Instruction>, ClientError> {
let mut accounts = match self.namespace {
RequestNamespace::State { new } => match new {
false => vec![AccountMeta::new(
anchor_lang::__private::state::address(&self.program_id),
false,
)],
true => vec![
AccountMeta::new_readonly(self.payer.pubkey(), true),
AccountMeta::new(
anchor_lang::__private::state::address(&self.program_id),
false,
),
AccountMeta::new_readonly(
Pubkey::find_program_address(&[], &self.program_id).0,
false,
),
AccountMeta::new_readonly(system_program::ID, false),
AccountMeta::new_readonly(self.program_id, false),
],
},
_ => Vec::new(),
};
accounts.extend_from_slice(&self.accounts);
let mut instructions = self.instructions.clone();
if let Some(ix_data) = &self.instruction_data {
instructions.push(Instruction {
program_id: self.program_id,
data: ix_data.clone(),
accounts,
});
}
Ok(instructions)
}
pub fn send(self) -> Result<Signature, ClientError> {
let instructions = self.instructions()?;
let mut signers = self.signers;
signers.push(&*self.payer);
let rpc_client = RpcClient::new_with_commitment(self.cluster, self.options);
let tx = {
let latest_hash = rpc_client.get_latest_blockhash()?;
Transaction::new_signed_with_payer(
&instructions,
Some(&self.payer.pubkey()),
&signers,
latest_hash,
)
};
rpc_client
.send_and_confirm_transaction(&tx)
.map_err(Into::into)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_execution() {
let mut logs: &[String] =
&["Program 7Y8VDzehoewALqJfyxZYMgYCnMTCDhWuGfJKUvjYWATw invoke [1]".to_string()];
let exe = Execution::new(&mut logs).unwrap();
assert_eq!(
exe.stack[0],
"7Y8VDzehoewALqJfyxZYMgYCnMTCDhWuGfJKUvjYWATw".to_string()
);
}
#[test]
fn handle_system_log_pop() {
let log = "Program 7Y8VDzehoewALqJfyxZYMgYCnMTCDhWuGfJKUvjYWATw success";
let (program, did_pop) = handle_system_log("asdf", log);
assert_eq!(program, None);
assert!(did_pop);
}
#[test]
fn handle_system_log_no_pop() {
let log = "Program 7swsTUiQ6KUK4uFYquQKg4epFRsBnvbrTf2fZQCa2sTJ qwer";
let (program, did_pop) = handle_system_log("asdf", log);
assert_eq!(program, None);
assert!(!did_pop);
}
}

View File

@ -1,34 +0,0 @@
WORKDIR=$(PWD)
#
# Extract anchor version from the Cargo.toml.
#
ANCHOR_CLI=v$(shell awk -F ' = ' '$$1 ~ /version/ { gsub(/[\"]/, "", $$2); printf("%s",$$2) }' ../cli/Cargo.toml)
#
# Solana toolchain.
#
SOLANA_CLI=v1.9.13
#
# Build version should match the Anchor cli version.
#
IMG_ORG ?= projectserum
IMG_VER ?= $(ANCHOR_CLI)
.PHONY: build build-push build-shell publish
default:
build: build/Dockerfile
@docker build \
--build-arg ANCHOR_CLI=$(ANCHOR_CLI) \
--build-arg SOLANA_CLI=$(SOLANA_CLI) \
$@ -t $(IMG_ORG)/$@:$(IMG_VER)
build-push:
@docker push $(IMG_ORG)/build:$(IMG_VER)
build-shell:
@docker run -ti --rm --net=host \
-v $(WORKDIR)/..:/workdir \
$(IMG_ORG)/build:$(IMG_VER) bash
publish: build build-push

View File

@ -1,49 +0,0 @@
#
# Docker image to generate deterministic, verifiable builds of Anchor programs.
# This must be run *after* a given ANCHOR_CLI version is published and a git tag
# is released on GitHub.
#
FROM ubuntu:18.04
ARG DEBIAN_FRONTEND=noninteractive
ARG SOLANA_CLI
ARG ANCHOR_CLI
ENV NODE_VERSION="v17.0.1"
ENV HOME="/root"
ENV PATH="${HOME}/.cargo/bin:${PATH}"
ENV PATH="${HOME}/.local/share/solana/install/active_release/bin:${PATH}"
ENV PATH="${HOME}/.nvm/versions/node/${NODE_VERSION}/bin:${PATH}"
# Install base utilities.
RUN mkdir -p /workdir && mkdir -p /tmp && \
apt-get update -qq && apt-get upgrade -qq && apt-get install -qq \
build-essential git curl wget jq pkg-config python3-pip \
libssl-dev libudev-dev
# Install rust.
RUN curl "https://sh.rustup.rs" -sfo rustup.sh && \
sh rustup.sh -y && \
rustup component add rustfmt clippy
# Install node / npm / yarn.
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
ENV NVM_DIR="${HOME}/.nvm"
RUN . $NVM_DIR/nvm.sh && \
nvm install ${NODE_VERSION} && \
nvm use ${NODE_VERSION} && \
nvm alias default node && \
npm install -g yarn
# Install Solana tools.
RUN sh -c "$(curl -sSfL https://release.solana.com/${SOLANA_CLI}/install)"
# Install anchor.
RUN cargo install --git https://github.com/project-serum/anchor --tag ${ANCHOR_CLI} anchor-cli --locked
# Build a dummy program to bootstrap the BPF SDK (doing this speeds up builds).
RUN mkdir -p /tmp && cd tmp && anchor init dummy && cd dummy && anchor build
WORKDIR /workdir

12
docs/.gitignore vendored
View File

@ -1,12 +0,0 @@
pids
logs
node_modules
npm-debug.log
coverage/
run
dist
.DS_Store
.nyc_output
.basement
config.local.js
basement_dist

View File

@ -1,24 +0,0 @@
{
"name": "anchor",
"version": "0.0.1",
"description": "",
"main": "index.js",
"authors": {
"name": "",
"email": ""
},
"repository": "/anchor",
"scripts": {
"deploy": "gh-pages -d src/.vuepress/dist",
"dev": "vuepress dev src",
"build": "vuepress build src"
},
"license": "MIT",
"devDependencies": {
"@xiaopanda/vuepress-plugin-code-copy": "^1.0.3",
"gh-pages": "^3.1.0",
"vuepress": "^1.5.3",
"vuepress-plugin-dehydrate": "^1.1.5",
"vuepress-theme-default-prefers-color-scheme": "^2.0.0"
}
}

View File

@ -1,15 +0,0 @@
<template>
<p class="demo">
{{ msg }}
</p>
</template>
<script>
export default {
data () {
return {
msg: 'Hello this is <Foo-Bar>'
}
}
}
</script>

View File

@ -1,3 +0,0 @@
<template>
<p class="demo">This is another component</p>
</template>

View File

@ -1,15 +0,0 @@
<template>
<p class="demo">
{{ msg }}
</p>
</template>
<script>
export default {
data() {
return {
msg: 'Hello this is <demo-component>'
}
}
}
</script>

View File

@ -1,104 +0,0 @@
const { description } = require("../../package");
module.exports = {
base: "/anchor/",
/**
* Refhttps://v1.vuepress.vuejs.org/config/#title
*/
title: "⚓ Anchor",
/**
* Refhttps://v1.vuepress.vuejs.org/config/#description
*/
description: description,
/**
* Extra tags to be injected to the page HTML `<head>`
*
* refhttps://v1.vuepress.vuejs.org/config/#head
*/
head: [
["link", { rel: "icon", href: "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚓ </text></svg>"}],
["meta", { name: "theme-color", content: "#3eaf7c" }],
["meta", { name: "apple-mobile-web-app-capable", content: "yes" }],
[
"meta",
{ name: "apple-mobile-web-app-status-bar-style", content: "black" },
],
],
theme: "default-prefers-color-scheme",
/**
* Theme configuration, here is the default theme configuration for VuePress.
*
* refhttps://v1.vuepress.vuejs.org/theme/default-theme-config.html
*/
themeConfig: {
repo: "",
editLinks: false,
docsDir: "",
editLinkText: "",
lastUpdated: false,
sidebarDepth: 2,
sidebar: [
{
collapsable: false,
title: "Getting Started",
children: [
"/getting-started/introduction",
"/getting-started/installation",
],
},
{
collapsable: false,
title: "Teams",
children: [
"/getting-started/projects",
],
},
{
collapsable: false,
title: "Tutorials",
children: [
"/tutorials/tutorial-0",
"/tutorials/tutorial-1",
"/tutorials/tutorial-2",
"/tutorials/tutorial-3",
"/tutorials/tutorial-4",
],
},
{
collapsable: false,
title: "CLI",
children: [
"/cli/commands",
],
},
{
collapsable: false,
title: "Source Verification",
children: [
"/getting-started/verification",
"/getting-started/publishing",
],
},
],
nav: [
{ text: "The Anchor Book", link: "https://book.anchor-lang.com" },
{ text: "Rust", link: "https://docs.rs/anchor-lang/latest/anchor_lang/" },
{ text: "TypeScript", link: "https://project-serum.github.io/anchor/ts/index.html" },
{ text: "GitHub", link: "https://github.com/project-serum/anchor" }
],
},
/**
* Apply pluginsrefhttps://v1.vuepress.vuejs.org/zh/plugin/
*/
plugins: [
"dehydrate",
"@vuepress/plugin-back-to-top",
"@vuepress/plugin-medium-zoom",
"@xiaopanda/vuepress-plugin-code-copy",
],
};

View File

@ -1,15 +0,0 @@
/**
* Client app enhancement file.
*
* https://v1.vuepress.vuejs.org/guide/basic-config.html#app-level-enhancements
*/
export default ({
Vue, // the version of Vue being used in the VuePress app
options, // the options for the root Vue instance
router, // the router instance for the app
siteData, // site metadata
}) => {
// ...apply enhancements for the site.
router.addRoutes([{ path: "/", redirect: "/getting-started/introduction" }]);
};

View File

@ -1,8 +0,0 @@
/**
* Custom Styles here.
*
* refhttps://v1.vuepress.vuejs.org/config/#index-styl
*/
.home .hero img
max-width 450px!important

View File

@ -1,10 +0,0 @@
/**
* Custom palette here.
*
* refhttps://v1.vuepress.vuejs.org/zh/config/#palette-styl
*/
$accentColor = #3eaf7c
$textColor = #2c3e50
$borderColor = #eaecef
$codeBgColor = #282c34

View File

@ -1,245 +0,0 @@
# Commands
A CLI is provided to support building and managing an Anchor workspace.
For a comprehensive list of commands and options, run `anchor -h` on any
of the following subcommands.
```
anchor-cli
USAGE:
anchor <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
build Builds the workspace
cluster Cluster commands
deploy Deploys each program in the workspace
expand Expands the macros of a program or the workspace
help Prints this message or the help of the given subcommand(s)
idl Commands for interacting with interface definitions
init Initializes a workspace
migrate Runs the deploy migration script
new Creates a new program
test Runs integration tests against a localnetwork
upgrade Upgrades a single program. The configured wallet must be the upgrade authority
verify Verifies the on-chain bytecode matches the locally compiled artifact. Run this
command inside a program subdirectory, i.e., in the dir containing the program's
Cargo.toml
```
## Build
```
anchor build
```
Builds programs in the workspace targeting Solana's BPF runtime and emitting IDLs in the `target/idl` directory.
```
anchor build --verifiable
```
Runs the build inside a docker image so that the output binary is deterministic (assuming a Cargo.lock file is used). This command must be run from within a single crate subdirectory within the workspace. For example, `programs/<my-program>/`.
## Cluster
### Cluster list
```
anchor cluster list
```
This lists cluster endpoints:
```
Cluster Endpoints:
* Mainnet - https://solana-api.projectserum.com
* Mainnet - https://api.mainnet-beta.solana.com
* Devnet - https://api.devnet.solana.com
* Testnet - https://api.testnet.solana.com
```
## Deploy
```
anchor deploy
```
Deploys all programs in the workspace to the configured cluster.
::: tip Note
This is different from the `solana program deploy` command, because everytime it's run
it will generate a *new* program address.
:::
## Expand
```
anchor expand
```
If run inside a program folder, expands the macros of the program.
If run in the workspace but outside a program folder, expands the macros of the workspace.
If run with the `--program-name` option, expand only the given program.
## Idl
The `idl` subcommand provides commands for interacting with interface definition files.
It's recommended to use these commands to store an IDL on chain, at a deterministic
address, as a function of nothing but the the program's ID. This
allows us to generate clients for a program using nothing but the program ID.
### Idl Init
```
anchor idl init -f <target/idl/program.json> <program-id>
```
Creates an idl account, writing the given `<target/idl/program.json>` file into a program owned account. By default, the size of the account is double the size of the IDL,
allowing room for growth in case the idl needs to be upgraded in the future.
### Idl Fetch
```
anchor idl fetch -o <out-file.json> <program-id>
```
Fetches an IDL from the configured blockchain. For example, make sure
your `Anchor.toml` is pointing to the `mainnet` cluster and run
```
anchor idl fetch GrAkKfEpTKQuVHG2Y97Y2FF4i7y7Q5AHLK94JBy7Y5yv
```
### Idl Authority
```
anchor idl authority <program-id>
```
Outputs the IDL account's authority. This is the wallet that has the ability to
update the IDL.
### Idl Erase Authority
```
anchor idl erase-authority -p <program-id>
```
Erases the IDL account's authority so that upgrades can no longer occur. The
configured wallet must be the current authority.
### Idl Upgrade
```
anchor idl upgrade <program-id> -f <target/idl/program.json>
```
Upgrades the IDL file on chain to the new `target/idl/program.json` idl.
The configured wallet must be the current authority.
```
anchor idl set-authority -n <new-authority> -p <program-id>
```
Sets a new authority on the IDL account. Both the `new-authority` and `program-id`
must be encoded in base 58.
## Init
```
anchor init
```
Initializes a project workspace with the following structure.
* `Anchor.toml`: Anchor configuration file.
* `Cargo.toml`: Rust workspace configuration file.
* `package.json`: JavaScript dependencies file.
* `programs/`: Directory for Solana program crates.
* `app/`: Directory for your application frontend.
* `tests/`: Directory for JavaScript integration tests.
* `migrations/deploy.js`: Deploy script.
## Migrate
```
anchor migrate
```
Runs the deploy script located at `migrations/deploy.js`, injecting a provider configured
from the workspace's `Anchor.toml`. For example,
```javascript
// File: migrations/deploys.js
const anchor = require("@project-serum/anchor");
module.exports = async function (provider) {
anchor.setProvider(provider);
// Add your deploy script here.
}
```
Migrations are a new feature
and only support this simple deploy script at the moment.
## New
```
anchor new <program-name>
```
Creates a new program in the workspace's `programs/` directory initialized with boilerplate.
## Test
```
anchor test
```
Run an integration test suit against the configured cluster, deploying new versions
of all workspace programs before running them.
If the configured network is a localnet, then automatically starts the localnetwork and runs
the test.
::: tip Note
Be sure to shutdown any other local validators, otherwise `anchor test` will fail to run.
If you'd prefer to run the program against your local validator use `anchor test --skip-local-validator`.
:::
When running tests we stream program logs to `.anchor/program-logs/<address>.<program-name>.log`
::: tip Note
The Anchor workflow [recommends](https://www.parity.io/paritys-checklist-for-secure-smart-contract-development/)
to test your program using integration tests in a language other
than Rust to make sure that bugs related to syntax misunderstandings
are coverable with tests and not just replicated in tests.
:::
## Upgrade
```
anchor upgrade <target/deploy/program.so> --program-id <program-id>
```
Uses Solana's upgradeable BPF loader to upgrade the on chain program code.
## Verify
```
anchor verify <program-id>
```
Verifies the on-chain bytecode matches the locally compiled artifact.

View File

@ -1,74 +0,0 @@
# Installing Dependencies
To get started, make sure to setup all the prerequisite tools on your local machine
(an installer has not yet been developed).
## Install Rust
For an introduction to Rust, see the excellent Rust [book](https://doc.rust-lang.org/book/).
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
rustup component add rustfmt
```
## Install Solana
See the solana [docs](https://docs.solana.com/cli/install-solana-cli-tools) for installation instructions. On macOS and Linux,
```bash
sh -c "$(curl -sSfL https://release.solana.com/v1.9.1/install)"
```
## Install Yarn
[Yarn](https://yarnpkg.com/) is recommended for JavaScript package management.
```bash
npm install -g yarn
```
## Install Anchor
### Install using pre-build binary on x86_64 Linux
Anchor binaries are available via an NPM package [`@project-serum/anchor-cli`](https://www.npmjs.com/package/@project-serum/anchor-cli). Only x86_64 Linux is supported currently, you must build from source for other OS'.
```bash
npm i -g @project-serum/anchor-cli
```
### Build from source for other operating systems
For now, we can use Cargo to install the CLI.
```bash
cargo install --git https://github.com/project-serum/anchor --tag v0.24.2 anchor-cli --locked
```
On Linux systems you may need to install additional dependencies if `cargo install` fails. On Ubuntu,
```bash
sudo apt-get update && sudo apt-get upgrade && sudo apt-get install -y pkg-config build-essential libudev-dev
```
Now verify the CLI is installed properly.
```bash
anchor --version
```
## Start a Project
To initialize a new project, simply run:
```bash
anchor init <new-project-name>
```
## Minimum version requirements
| Build tool | Version |
|:------------|:---------------|
| Node.js | v11.0.0 |

View File

@ -1,18 +0,0 @@
# Introduction
<div style="border: 2px solid red; text-align: center; padding: 10px 10px 10px 10px; box-sizing: border-box"> This documentation is being sunset in favor of <a href="https://book.anchor-lang.com" rel="noopener noreferrer" target="_blank">The Anchor Book</a>. At this point in time, either documentation may contain information that the other does not.</div>
Anchor is a framework for Solana's [Sealevel](https://medium.com/solana-labs/sealevel-parallel-processing-thousands-of-smart-contracts-d814b378192) runtime providing several convenient developer tools.
- Rust crates and eDSL for writing Solana programs
- [IDL](https://en.wikipedia.org/wiki/Interface_description_language) specification
- TypeScript package for generating clients from IDL
- CLI and workspace management for developing complete applications
If you're familiar with developing in Ethereum's [Solidity](https://docs.soliditylang.org/en/v0.7.4/), [Truffle](https://www.trufflesuite.com/), [web3.js](https://github.com/ethereum/web3.js) or Parity's [Ink!](https://github.com/paritytech/ink), then the experience will be familiar. Although the DSL syntax and semantics are targeted at Solana, the high level flow of writing RPC request handlers, emitting an IDL, and generating clients from IDL is the same.
Here, we'll walk through several tutorials demonstrating how to use Anchor. To skip the tutorials and jump straight to examples, go [here](https://github.com/project-serum/anchor/blob/master/examples). For an introduction to Solana, see the [docs](https://docs.solana.com/developing/programming-model/overview).
::: tip NOTE
Anchor is in active development, so all APIs are subject to change. If you are one of the early developers to try it out and have feedback, please reach out by [filing an issue](https://github.com/project-serum/anchor/issues/new). This documentation is a work in progress and is expected to change dramatically as features continue to be built out. If you have any problems, consult the [source](https://github.com/project-serum/anchor) or feel free to ask questions on the [Discord](https://discord.gg/JgVgQ82erk).
:::

View File

@ -1,24 +0,0 @@
# Projects
Open a pull request to add your project to the [list](https://github.com/project-serum/anchor/blob/master/docs/src/getting-started/projects.md).
* [Serum](https://github.com/project-serum)
* [Synthetify](https://github.com/Synthetify)
* [SolFarm](https://solfarm.io/)
* [Zeta Markets](https://zeta.markets/)
* [Saber](https://saber.so)
* [01](https://01protocol.com/)
* [Parrot Finance](https://parrot.fi/)
* [Marinade Finance](https://marinade.finance/)
* [Aldrin](https://dex.aldrin.com/)
* [Cyclos](https://cyclos.io/)
* [Solend](https://solend.fi)
* [Drift](https://www.drift.trade/)
* [Fabric](https://stake.fsynth.io/)
* [Jet Protocol](https://jetprotocol.io/)
* [Quarry](https://quarry.so/)
* [PsyOptions](https://psyoptions.io/)
* [sosol](https://sosol.app/)
* [Arrow Protocol](https://arrowprotocol.com/)
* [Hubble Protocol](https://hubbleprotocol.io/)

View File

@ -1,88 +0,0 @@
# Publishing Source
The Anchor Program Registry at [anchor.projectserum.com](https://anchor.projectserum.com)
hosts a catalog of verified programs on Solana both written with and without Anchor. It is recommended
that authors of smart contracts publish their source to promote best
practices for security and transparency.
::: tip note
The Anchor Program Registry is currently in alpha testing. For access to publishing
please ask on [Discord](https://discord.gg/rg5ZZPmmTm).
:::
## Getting Started
The process for publishing is mostly identical to `crates.io`.
* Signup for an account [here](https://anchor.projectserum.com/signup).
* Confirm your email by clicking the link sent to your address.
* Navigate to your Username -> Account Settings on the top navbar.
* Click "New Token" in the **API Access** section.
* Run `anchor login <token>` at the command line.
And you're ready to interact with the registry.
## Configuring a Build
Whether your program is written in Anchor or not, all source being published must
have an `Anchor.toml` to define the build.
An example `Anchor.toml` config looks as follows,
```toml
anchor_version = "0.24.2"
[workspace]
members = ["programs/multisig"]
[provider]
cluster = "mainnet"
wallet = "~/.config/solana/id.json"
[programs.mainnet]
multisig = "A9HAbnCwoD6f2NkZobKFf6buJoN9gUVVvX5PoUnDHS6u"
[programs.localnet]
multisig = "A9HAbnCwoD6f2NkZobKFf6buJoN9gUVVvX5PoUnDHS6u"
```
Here there are four sections.
1. `anchor_version` (optional) - sets the anchor docker image to use. By default, the builder will use the latest version of Anchor.
2. `[workspace]` (optional) - sets the paths--relative to the `Anchor.toml`--
to all programs in the local
workspace, i.e., the path to the `Cargo.toml` manifest associated with each
program that can be compiled by the `anchor` CLI. For programs using the
standard Anchor workflow, this can be ommitted. For programs not written in Anchor
but still want to publish, this should be added.
3. `[provider]` - configures the wallet and cluster settings. Here, `mainnet` is used because the registry only supports `mainnet` binary verification at the moment.
3. `[programs.mainnet]` - configures each program in the workpace, providing
the `address` of the program to verify.
::: tip
When defining program in `[programs.mainnet]`, make sure the name provided
matches the **lib** name for your program, which is defined
by your program's Cargo.toml.
:::
### Examples
#### Anchor Program
An example of a toml file for an Anchor program can be found [here](https://anchor.projectserum.com/build/2).
#### Non Anchor Program
An example of a toml file for a non-anchor program can be found [here](https://anchor.projectserum.com/build/1).
## Publishing
To publish to the Anchor Program Registry, change directories to the `Anchor.toml`
defined root and run
```bash
anchor publish <program-name>
```
where `<program-name>` is as defined in `[programs.mainnet]`, i.e., `multisig`
in the example above.

View File

@ -1,52 +0,0 @@
# Verifiable Builds
Building programs with the Solana CLI may embed machine specfic
code into the resulting binary. As a result, building the same program
on different machines may produce different executables. To get around this
problem, one can build inside a docker image with pinned dependencies to produce
a verifiable build.
Anchor makes this easy by providing CLI commands to build and take care of
docker for you. To get started, first make sure you
[install](https://docs.docker.com/get-docker/) docker on your local machine.
## Building
To produce a verifiable build, run
```bash
anchor build --verifiable
```
## Verifying
To verify a build against a program deployed on mainnet, run
```bash
anchor verify -p <lib-name> <program-id>
```
where the `<lib-name>` is defined by your program's Cargo.toml.
If the program has an IDL, it will also check the IDL deployed on chain matches.
## Images
A docker image for each version of Anchor is published on [Docker Hub](https://hub.docker.com/r/projectserum/build). They are tagged in the form `projectserum/build:<version>`. For example, to get the image for Anchor `v0.24.2` one can run
```
docker pull projectserum/build:v0.24.2
```
## Removing an Image
In the event you run a verifiable build from the CLI and exit prematurely,
it's possible the docker image may still be building in the background.
To remove, run
```
docker rm -f anchor-program
```
where `anchor-program` is the name of the image created by default from within
the Anchor CLI.

View File

@ -1,23 +0,0 @@
---
home: true
heroText: Anchor
tagline: A framework for building Solana programs
actionText: Get Started →
actionLink: /getting-started/introduction
features:
- title: Security
details: Anchor eliminates many footguns of raw Solana programs by default and allows you to add more security checks without disrupting your business logic.
- title: Code Generation
details: (De)Serialization, cross-program invocations, account initialization, and more.
- title: IDL & Client Generation
details: Anchor generates an IDL based on your program and automatically creates a typescript client with it.
- title: Verifiability
details: Anchor programs can be built verifiably, so users know that the on-chain program matches the code base.
- title: Workspace Management
details: The CLI helps you manage workspaces with multiple programs, e2e tests, and more.
- title: Compatibility
details: Anchor programs can interact with all non-anchor programs on Solana.
footer: Apache License 2.0
---
<div style="border: 2px solid red; text-align: center; padding: 10px 10px 10px 10px; box-sizing: border-box"> This documentation is being sunset in favor of <a href="https://book.anchor-lang.com" rel="noopener noreferrer" target="_blank">The Anchor Book</a>. At this point in time, either documentation may contain information that the other does not.</div>

View File

@ -1,189 +0,0 @@
# A Minimal Example
Here, we introduce Anchor's core syntax elements and project workflow. This tutorial assumes all
[prerequisites](../getting-started/installation.md) are installed.
## Clone the Repo
To get started, clone the repo.
```bash
git clone https://github.com/project-serum/anchor
```
Next, checkout the tagged branch of the same version of the anchor cli you have installed.
```bash
git checkout tags/<version>
```
Change directories to the [example](https://github.com/project-serum/anchor/tree/master/examples/tutorial/basic-0).
```bash
cd anchor/examples/tutorial/basic-0
```
And install any additional JavaScript dependencies:
```bash
yarn install
```
## Starting a Localnet
In a separate terminal, start a local network. If you're running solana
for the first time, generate a wallet.
```
solana-keygen new
```
Then run
```
solana-test-validator
```
Then, shut it down.
The test validator will be used when testing Anchor programs. Make sure to turn off the validator before you begin testing Anchor programs.
::: details
As you'll see later, starting a localnet manually like this is not necessary when testing with Anchor,
but is done for educational purposes in this tutorial.
:::
## Defining a Program
We define the minimum viable program as follows.
<<< @/../examples/tutorial/basic-0/programs/basic-0/src/lib.rs
* `#[program]` First, notice that a program is defined with the `#[program]` attribute, where each
inner method defines an RPC request handler, or, in Solana parlance, an "instruction"
handler. These handlers are the entrypoints to your program that clients may invoke, as
we will see soon.
* `Context<Initialize>` The first parameter of _every_ RPC handler is the `Context` struct, which is a simple
container for the currently executing `program_id` generic over
`Accounts`--here, the `Initialize` struct.
* `#[derive(Accounts)]` The `Accounts` derive macro marks a struct containing all the accounts that must be
specified for a given instruction. To understand Accounts on Solana, see the
[docs](https://docs.solana.com/developing/programming-model/accounts).
In subsequent tutorials, we'll demonstrate how an `Accounts` struct can be used to
specify constraints on accounts given to your program. Since this example doesn't touch any
accounts, we skip this (important) detail.
## Building and Emitting an IDL
After creating a program, you can use the `anchor` CLI to build and emit an IDL, from which clients
can be generated.
```bash
anchor build
```
::: details
The `build` command is a convenience combining two steps.
1) `cargo build-bpf`
2) `anchor idl parse -f program/src/lib.rs -o target/idl/basic_0.json`.
:::
Once run, you should see your build artifacts, as usual, in your `target/` directory. Additionally,
a `target/idl/basic_0.json` file is created. Inspecting its contents you should see
```json
{
"version": "0.1.0",
"name": "basic_0",
"instructions": [
{
"name": "initialize",
"accounts": [],
"args": []
}
]
}
```
From this file a client can be generated. Note that this file is created by parsing the `src/lib.rs`
file in your program's crate.
::: tip
If you've developed on Ethereum, the IDL is analogous to the `abi.json`.
:::
## Deploying
Once built, we can deploy the program by running
```bash
anchor deploy
```
Take note of the program's deployed address. We'll use it next.
## Generating a Client
Now that we've built a program, deployed it to a local cluster, and generated an IDL,
we can use the IDL to generate a client to speak to our on-chain program. For example,
see [client.js](https://github.com/project-serum/anchor/tree/master/examples/tutorial/basic-0/client.js).
<<< @/../examples/tutorial/basic-0/client.js#main
Notice how we dynamically created the `initialize` method under
the `rpc` namespace.
Now, make sure to plugin your program's address into `<YOUR-PROGRAM-ID>` (a mild
annoyance that we'll address next). In order to run the client, you'll also need the path
to your wallet's keypair you generated when you ran `solana-keygen new`; you can find it
by running
```bash
solana config get keypair
```
Once you've got it, run the client with the environment variable `ANCHOR_WALLET` set to
that path, e.g.
```bash
ANCHOR_WALLET=<YOUR-KEYPAIR-PATH> node client.js
```
You just successfully created a client and executed a transaction on your localnet.
## Workspaces
So far we've seen the basics of how to create, deploy, and make RPCs to a program, but
deploying a program, copy and pasting the address, and explicitly reading
an IDL is all a bit tedious, and can easily get out of hand the more tests and the more
programs you have. For this reason, we introduce the concept of a workspace.
Inspecting [tests/basic-0.js](https://github.com/project-serum/anchor/tree/master/examples/tutorial/basic-0/tests/basic-0.js), we see the above example can be reduced to
<<< @/../examples/tutorial/basic-0/tests/basic-0.js#code
The `workspace` namespace provides access to all programs in the local project and is
automatically updated to reflect the latest deployment, making it easy to change
your program, update your JavaScript, and run your tests in a fast feedback loop.
::: tip NOTE
For now, the workspace feature is only available when running the `anchor test` command,
which will automatically `build`, `deploy`, and `test` all programs against a localnet
in one command.
:::
Finally, we can run the test. Don't forget to kill the local validator started earlier.
We won't need to start one manually for any future tutorials.
```bash
anchor test
```
## Next Steps
We've introduced the basic syntax of writing programs in Anchor along with a productive
workflow for building and testing. However, programs aren't all that interesting without
interacting with persistent state. We'll cover that next.

View File

@ -1,106 +0,0 @@
# Arguments and Accounts
This tutorial covers the basics of creating and mutating accounts using Anchor.
It's recommended to read [Tutorial 0](./tutorial-0.md) first, as this tutorial will
build on top of it.
## Clone the Repo
To get started, clone the repo.
```bash
git clone https://github.com/project-serum/anchor
```
Change directories to the [example](https://github.com/project-serum/anchor/tree/master/examples/tutorial/basic-1).
```bash
cd anchor/examples/tutorial/basic-1
```
And install any additional JavaScript dependencies:
```bash
yarn install
```
## Defining a Program
We define our program as follows
<<< @/../examples/tutorial/basic-1/programs/basic-1/src/lib.rs
Some new syntax elements are introduced here.
### `initialize` instruction
First, let's start with the initialize instruction. Notice the `data` argument passed into the program. This argument and any other valid
Rust types can be passed to the instruction to define inputs to the program.
Additionally,
notice how we take a mutable reference to `my_account` and assign the `data` to it. This leads us to
the `Initialize` struct, deriving `Accounts`. There are two things to notice about `Initialize`.
1. The `my_account` field is of type `Account<'info, MyAccount>` and the deserialized data structure is `MyAccount`.
2. The `my_account` field is marked with the `init` attribute. This will create a new
account owned by the current program, zero initialized. When using `init`, one must also provide
`payer`, which will fund the account creation, `space`, which defines how large the account should be,
and the `system_program`, which is required by the runtime for creating the account.
::: details
All accounts created with Anchor are laid out as follows: `8-byte-discriminator || borsh
serialized data`. The 8-byte-discriminator is created from the first 8 bytes of the
`Sha256` hash of the account's type--using the example above, `sha256("account:MyAccount")[..8]`.
The `account:` is a fixed prefix.
Importantly, this allows a program to know for certain an account is indeed of a given type.
Without it, a program would be vulnerable to account injection attacks, where a malicious user
specifies an account of an unexpected type, causing the program to do unexpected things.
On account creation, this 8-byte discriminator doesn't exist, since the account storage is
zeroed. The first time an Anchor program mutates an account, this discriminator is prepended
to the account storage array and all subsequent accesses to the account (not decorated with
`#[account(init)]`) will check for this discriminator.
:::
### `update` instruction
Similarly, the `Update` accounts struct is marked with the `#[account(mut)]` attribute.
Marking an account as `mut` persists any changes made upon exiting the program.
Here we've covered the basics of how to interact with accounts. In a later tutorial,
we'll delve more deeply into deriving `Accounts`, but for now, just know
you must mark an account `init` when using it for the first time and `mut`
for persisting changes.
## Creating and Initializing Accounts
We can interact with the program as follows.
<<< @/../examples/tutorial/basic-1/tests/basic-1.js#code-simplified
The last element passed into the method is common amongst all dynamically generated
methods on the `rpc` namespace, containing several options for a transaction. Here,
we specify the `accounts` field, an object of all the addresses the transaction
needs to touch, and the `signers` array of all `Signer` objects needed to sign the
transaction. Because `myAccount` is being created, the Solana runtime requires it
to sign the transaction.
::: details
If you've developed on Solana before, you might notice two things 1) the ordering of the accounts doesn't
matter and 2) the `isWritable` and `isSigner`
options are not specified on the account anywhere. In both cases, the framework takes care
of these details for you, by reading the IDL.
:::
As before, we can run the example tests.
```
anchor test
```
## Next Steps
We've covered all the basics of developing applications using Anchor. However, we've
left out one important aspect to ensure the security of our programs--validating input
and access control. We'll cover that next.

View File

@ -1,77 +0,0 @@
# Account Constraints and Access Control
This tutorial covers how to specify constraints and access control on accounts, a problem
somewhat unique to the parallel nature of Solana.
On Solana, a transaction must specify all accounts required for execution. And because an untrusted client specifies those accounts, a program must responsibly validate all such accounts are what the client claims they are--in addition to any instruction specific access control the program needs to do.
For example, you could imagine easily writing a faulty token program that forgets to check if the **signer** of a transaction claiming to be the **owner** of a Token `Account` actually matches the **owner** on that account. Furthermore, imagine what might happen if the program expects a `Mint` account but a malicious user gives a token `Account`.
To address these problems, Anchor provides several types, traits, and macros. It's easiest to understand by seeing how they're used in an example, but a couple include
- [Accounts](https://docs.rs/anchor-lang/latest/anchor_lang/derive.Accounts.html): derive macro implementing the `Accounts` [trait](https://docs.rs/anchor-lang/latest/anchor_lang/trait.Accounts.html), allowing a struct to transform
from the untrusted `&[AccountInfo]` slice given to a Solana program into a validated struct
of deserialized account types.
- [#[account]](https://docs.rs/anchor-lang/latest/anchor_lang/attr.account.html): attribute macro implementing [AccountSerialize](https://docs.rs/anchor-lang/latest/anchor_lang/trait.AccountSerialize.html) and [AccountDeserialize](https://docs.rs/anchor-lang/latest/anchor_lang/trait.AnchorDeserialize.html), automatically prepending a unique 8 byte discriminator to the account array. The discriminator is defined by the first 8 bytes of the `Sha256` hash of the account's Rust identifier--i.e., the struct type name--and ensures no account can be substituted for another.
- [Account](https://docs.rs/anchor-lang/latest/anchor_lang/accounts/account/struct.Account.html): a wrapper type for a deserialized account implementing `AccountDeserialize`. Using this type within an `Accounts` struct will ensure the account is **owned** by the address defined by `declare_id!` where the inner account was defined.
With the above, we can define preconditions for any instruction handler expecting a certain set of
accounts, allowing us to more easily reason about the security of our programs.
## Clone the Repo
To get started, clone the repo.
```bash
git clone https://github.com/project-serum/anchor
```
Change directories to the [example](https://github.com/project-serum/anchor/tree/master/examples/tutorial/basic-2).
```bash
cd anchor/examples/tutorial/basic-2
```
And install any additional JavaScript dependencies:
```bash
yarn install
```
## Defining a Program
Here we have a simple **Counter** program, where anyone can create a counter, but only the assigned
**authority** can increment it.
<<< @/../examples/tutorial/basic-2/programs/basic-2/src/lib.rs
If you've gone through the previous tutorials the `create` instruction should be straightforward.
Let's focus on the `increment` instruction, specifically the `Increment` struct deriving
`Accounts`.
```rust
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut, has_one = authority)]
pub counter: Account<'info, Counter>,
pub authority: Signer<'info>,
}
```
Here, a couple `#[account(..)]` attributes are used.
- `mut`: tells the program to persist all changes to the account.
- `has_one`: enforces the constraint that `Increment.counter.authority == Increment.authority.key`.
Another new concept here is the `Signer` type. This enforces the constraint that the `authority`
account **signed** the transaction. However, anchor doesn't fetch the data on that account.
If any of these constraints do not hold, then the `increment` instruction will never be executed.
This allows us to completely separate account validation from our program's business logic, allowing us
to reason about each concern more easily. For more, see the full [list](https://docs.rs/anchor-lang/latest/anchor_lang/derive.Accounts.html) of account constraints.
## Next Steps
We've covered the basics for writing a single program using Anchor on Solana. But the power of
blockchains come not from a single program, but from combining multiple _composable_ programs
(buzzword...check). Next, we'll see how to call one program from another.

View File

@ -1,84 +0,0 @@
# Cross Program Invocations (CPI)
This tutorial covers how to call one program from another, a process known as
*cross-program-invocation* (CPI).
## Clone the Repo
To get started, clone the repo.
```bash
git clone https://github.com/project-serum/anchor
```
Change directories to the [example](https://github.com/project-serum/anchor/tree/master/examples/tutorial/basic-3).
```bash
cd anchor/examples/tutorial/basic-3
```
And install any additional JavaScript dependencies:
```bash
yarn install
```
## Defining a Puppet Program
We start with the program that will be called by another program, the puppet.
<<< @/../examples/tutorial/basic-3/programs/puppet/src/lib.rs
If you've followed along the other tutorials, this should be straight forward. We have
a program with two instructions, `initialize`, which does nothing other than the
initialization of the account (remember, the program *transparently* prepends a unique 8
byte discriminator the first time an account is used), and `set_data`, which takes a previously
initialized account, and sets its data field.
Now, suppose we wanted to call `set_data` from another program.
## Defining a Puppet Master Program
We define a new `puppet-master` crate, which successfully executes the Puppet program's `set_data`
instruction via CPI.
<<< @/../examples/tutorial/basic-3/programs/puppet-master/src/lib.rs#core
Things to notice
* We create a `CpiContext` object with the target instruction's accounts and program,
here `SetData` and `puppet_program`.
* To invoke an instruction on another program, just use the `cpi` module on the crate, here, `puppet::cpi::set_data`.
* Our `Accounts` struct contains the puppet account we are calling into via CPI. Accounts used for CPI are not specifically denoted
as such with the `CpiAccount` label since v0.15. Accounts used for CPI are not fundamentally different from `Program` or `Signer`
accounts except for their role and ownership in the specific context in which they are used.
::: tip
When using another Anchor program for CPI, make sure to specify the `cpi` feature in your `Cargo.toml`.
If you look at the `Cargo.toml` for this example, you'll see
`puppet = { path = "../puppet", features = ["cpi"] }`.
:::
## Signer Seeds
Often it's useful for a program to sign instructions. For example, if a program controls a token
account and wants to send tokens to another account, it must sign. In Solana, this is done by specifying
"signer seeds" on CPI. To do this using the example above, simply change
`CpiContext::new(cpi_accounts, cpi_program)` to
`CpiContext::new_with_signer(cpi_accounts, cpi_program, signer_seeds)`.
For more background on signing with program derived addresses, see the official Solana [documentation](https://docs.solana.com/developing/programming-model/calling-between-programs#program-signed-accounts).
## Return values
Solana currently has no way to return values from CPI, alas. However, you can approximate this
by having the callee write return values to an account and the caller read that account to
retrieve the return value. In future work, Anchor should do this transparently.
## Conclusion
Now that you can have your programs call other programs, you should be able to access all the work being done by other developers in your own applications!
## Next Steps
We just covered Cross Program Invocation and showed how anchor can handle talking to multiple different programs in the solana ecosystem. In the next step, we will teach you how to handle errors and in Anchor.

View File

@ -1,56 +0,0 @@
# Errors
If you've ever programmed on a blockchain, you've probably been frustrated by
either non existent or opaque error codes. Anchor attempts to address this by
providing the `#[error_code]` attribute, which can be used to create typed Errors with
descriptive messages that automatically propagate to the client.
## Defining a Program
For example,
```rust
use anchor_lang::prelude::*;
#[program]
mod errors {
use super::*;
pub fn hello(_ctx: Context<Hello>) -> Result<()> {
Err(error!(ErrorCode::Hello))
}
}
#[derive(Accounts)]
pub struct Hello {}
#[error_code]
pub enum ErrorCode {
#[msg("This is an error message clients will automatically display")]
Hello,
}
```
Observe the [#[error_code]](https://docs.rs/anchor-lang/latest/anchor_lang/attr.error_code.html) attribute on the `ErrorCode` enum.
This macro generates internal anchor code that helps anchor turn the error code into an error and display it properly.
To create an error, use the [`error!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.error.html) macro together with an error code. This macro creates an [`AnchorError`](https://docs.rs/anchor-lang/latest/anchor_lang/error/struct.AnchorError.html) that includes helpful information like the file and line the error was created in.
To make writing errors even easier, anchor also provides the [`err!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.err.html) and the [`require!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.require.html) macros.
## Using the Client
When using the client, we get the error message.
```javascript
try {
const tx = await program.rpc.hello();
assert.ok(false);
} catch (err) {
const errMsg = "This is an error message clients will automatically display";
assert.equal(err.toString(), errMsg);
}
```
It's that easy. :)
To run the full example, go [here](https://github.com/project-serum/anchor/tree/master/examples/tutorial/basic-4).

View File

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

View File

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

View File

@ -1,29 +0,0 @@
// client.js is used to introduce the reader to generating clients from IDLs.
// It is not expected users directly test with this example. For a more
// ergonomic example, see `tests/basic-0.js` in this workspace.
const anchor = require("@project-serum/anchor");
// Configure the local cluster.
anchor.setProvider(anchor.AnchorProvider.local());
async function main() {
// #region main
// Read the generated IDL.
const idl = JSON.parse(
require("fs").readFileSync("./target/idl/basic_0.json", "utf8")
);
// Address of the deployed program.
const programId = new anchor.web3.PublicKey("<YOUR-PROGRAM-ID>");
// Generate the program client from IDL.
const program = new anchor.Program(idl, programId);
// Execute the RPC.
await program.rpc.initialize();
// #endregion main
}
console.log("Running client.");
main().then(() => console.log("Success"));

View File

@ -1,19 +0,0 @@
{
"name": "basic-0",
"version": "0.24.2",
"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 --skip-lint"
}
}

View File

@ -1,17 +0,0 @@
[package]
name = "basic-0"
version = "0.1.0"
description = "Created with Anchor"
rust-version = "1.56"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "basic_0"
[features]
no-entrypoint = []
cpi = ["no-entrypoint"]
[dependencies]
anchor-lang = { path = "../../../../../lang" }

View File

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

View File

@ -1,14 +0,0 @@
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
mod basic_0 {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}

View File

@ -1,16 +0,0 @@
const anchor = require("@project-serum/anchor");
describe("basic-0", () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.local());
it("Uses the workspace to invoke the initialize instruction", async () => {
// #region code
// Read the deployed program from the workspace.
const program = anchor.workspace.Basic0;
// Execute the RPC.
await program.rpc.initialize();
// #endregion code
});
});

View File

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

View File

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

View File

@ -1,19 +0,0 @@
{
"name": "basic-1",
"version": "0.24.2",
"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 --skip-lint"
}
}

View File

@ -1,17 +0,0 @@
[package]
name = "basic-1"
version = "0.1.0"
description = "Created with Anchor"
rust-version = "1.56"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "basic_1"
[features]
no-entrypoint = []
cpi = ["no-entrypoint"]
[dependencies]
anchor-lang = { path = "../../../../../lang" }

View File

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

View File

@ -1,40 +0,0 @@
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
mod basic_1 {
use super::*;
pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data = data;
Ok(())
}
pub fn update(ctx: Context<Update>, data: u64) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data = data;
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = user, space = 8 + 8)]
pub my_account: Account<'info, MyAccount>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Update<'info> {
#[account(mut)]
pub my_account: Account<'info, MyAccount>,
}
#[account]
pub struct MyAccount {
pub data: u64,
}

View File

@ -1,65 +0,0 @@
const assert = require("assert");
const anchor = require("@project-serum/anchor");
const { SystemProgram } = anchor.web3;
describe("basic-1", () => {
// Use a local provider.
const provider = anchor.AnchorProvider.local();
// Configure the client to use the local cluster.
anchor.setProvider(provider);
it("Creates and initializes an account in a single atomic transaction (simplified)", async () => {
// #region code-simplified
// The program to execute.
const program = anchor.workspace.Basic1;
// The Account to create.
const myAccount = anchor.web3.Keypair.generate();
// Create the new account and initialize it with the program.
// #region code-simplified
await program.rpc.initialize(new anchor.BN(1234), {
accounts: {
myAccount: myAccount.publicKey,
user: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
},
signers: [myAccount],
});
// #endregion code-simplified
// Fetch the newly created account from the cluster.
const account = await program.account.myAccount.fetch(myAccount.publicKey);
// Check it's state was initialized.
assert.ok(account.data.eq(new anchor.BN(1234)));
// Store the account for the next test.
_myAccount = myAccount;
});
it("Updates a previously created account", async () => {
const myAccount = _myAccount;
// #region update-test
// The program to execute.
const program = anchor.workspace.Basic1;
// Invoke the update rpc.
await program.rpc.update(new anchor.BN(4321), {
accounts: {
myAccount: myAccount.publicKey,
},
});
// Fetch the newly updated account.
const account = await program.account.myAccount.fetch(myAccount.publicKey);
// Check it's state was mutated.
assert.ok(account.data.eq(new anchor.BN(4321)));
// #endregion update-test
});
});

View File

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

View File

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

View File

@ -1,19 +0,0 @@
{
"name": "basic-2",
"version": "0.24.2",
"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 --skip-lint"
}
}

View File

@ -1,17 +0,0 @@
[package]
name = "basic-2"
version = "0.1.0"
description = "Created with Anchor"
rust-version = "1.56"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "basic_2"
[features]
no-entrypoint = []
cpi = ["no-entrypoint"]
[dependencies]
anchor-lang = { path = "../../../../../lang" }

View File

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

View File

@ -1,43 +0,0 @@
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
mod basic_2 {
use super::*;
pub fn create(ctx: Context<Create>, authority: Pubkey) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.authority = authority;
counter.count = 0;
Ok(())
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.count += 1;
Ok(())
}
}
#[derive(Accounts)]
pub struct Create<'info> {
#[account(init, payer = user, space = 8 + 40)]
pub counter: Account<'info, Counter>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut, has_one = authority)]
pub counter: Account<'info, Counter>,
pub authority: Signer<'info>,
}
#[account]
pub struct Counter {
pub authority: Pubkey,
pub count: u64,
}

View File

@ -1,48 +0,0 @@
const assert = require("assert");
const anchor = require("@project-serum/anchor");
const { SystemProgram } = anchor.web3;
describe("basic-2", () => {
const provider = anchor.AnchorProvider.local();
// Configure the client to use the local cluster.
anchor.setProvider(provider);
// Counter for the tests.
const counter = anchor.web3.Keypair.generate();
// Program for the tests.
const program = anchor.workspace.Basic2;
it("Creates a counter", async () => {
await program.rpc.create(provider.wallet.publicKey, {
accounts: {
counter: counter.publicKey,
user: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
},
signers: [counter],
});
let counterAccount = await program.account.counter.fetch(counter.publicKey);
assert.ok(counterAccount.authority.equals(provider.wallet.publicKey));
assert.ok(counterAccount.count.toNumber() === 0);
});
it("Updates a counter", async () => {
await program.rpc.increment({
accounts: {
counter: counter.publicKey,
authority: provider.wallet.publicKey,
},
});
const counterAccount = await program.account.counter.fetch(
counter.publicKey
);
assert.ok(counterAccount.authority.equals(provider.wallet.publicKey));
assert.ok(counterAccount.count.toNumber() == 1);
});
});

View File

@ -1,10 +0,0 @@
[provider]
cluster = "localnet"
wallet = "~/.config/solana/id.json"
[programs.localnet]
puppet = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
puppet_master = "HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"
[scripts]
test = "yarn run mocha -t 1000000 tests/"

View File

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

View File

@ -1,19 +0,0 @@
{
"name": "basic-3",
"version": "0.24.2",
"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 --skip-lint"
}
}

View File

@ -1,18 +0,0 @@
[package]
name = "puppet-master"
version = "0.1.0"
description = "Created with Anchor"
rust-version = "1.56"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "puppet_master"
[features]
no-entrypoint = []
cpi = ["no-entrypoint"]
[dependencies]
anchor-lang = { path = "../../../../../lang" }
puppet = { path = "../puppet", features = ["cpi"] }

View File

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

View File

@ -1,28 +0,0 @@
// #region core
use anchor_lang::prelude::*;
use puppet::cpi::accounts::SetData;
use puppet::program::Puppet;
use puppet::{self, Data};
declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L");
#[program]
mod puppet_master {
use super::*;
pub fn pull_strings(ctx: Context<PullStrings>, data: u64) -> anchor_lang::Result<()> {
let cpi_program = ctx.accounts.puppet_program.to_account_info();
let cpi_accounts = SetData {
puppet: ctx.accounts.puppet.to_account_info(),
};
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
puppet::cpi::set_data(cpi_ctx, data)
}
}
#[derive(Accounts)]
pub struct PullStrings<'info> {
#[account(mut)]
pub puppet: Account<'info, Data>,
pub puppet_program: Program<'info, Puppet>,
}
// #endregion core

View File

@ -1,17 +0,0 @@
[package]
name = "puppet"
version = "0.1.0"
description = "Created with Anchor"
rust-version = "1.56"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "puppet"
[features]
no-entrypoint = []
cpi = ["no-entrypoint"]
[dependencies]
anchor-lang = { path = "../../../../../lang" }

View File

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

View File

@ -1,37 +0,0 @@
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod puppet {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
let puppet = &mut ctx.accounts.puppet;
puppet.data = data;
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = user, space = 8 + 8)]
pub puppet: Account<'info, Data>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct SetData<'info> {
#[account(mut)]
pub puppet: Account<'info, Data>,
}
#[account]
pub struct Data {
pub data: u64,
}

View File

@ -1,38 +0,0 @@
const assert = require("assert");
const anchor = require("@project-serum/anchor");
const { SystemProgram } = anchor.web3;
describe("basic-3", () => {
const provider = anchor.AnchorProvider.local();
// Configure the client to use the local cluster.
anchor.setProvider(provider);
it("Performs CPI from puppet master to puppet", async () => {
const puppetMaster = anchor.workspace.PuppetMaster;
const puppet = anchor.workspace.Puppet;
// Initialize a new puppet account.
const newPuppetAccount = anchor.web3.Keypair.generate();
const tx = await puppet.rpc.initialize({
accounts: {
puppet: newPuppetAccount.publicKey,
user: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
},
signers: [newPuppetAccount],
});
// Invoke the puppet master to perform a CPI to the puppet.
await puppetMaster.rpc.pullStrings(new anchor.BN(111), {
accounts: {
puppet: newPuppetAccount.publicKey,
puppetProgram: puppet.programId,
},
});
// Check the state updated.
puppetAccount = await puppet.account.data.fetch(newPuppetAccount.publicKey);
assert.ok(puppetAccount.data.eq(new anchor.BN(111)));
});
});

View File

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

View File

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

View File

@ -1,19 +0,0 @@
{
"name": "basic-4",
"version": "0.24.2",
"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 --skip-lint"
}
}

View File

@ -1,17 +0,0 @@
[package]
name = "basic-4"
version = "0.1.0"
description = "Created with Anchor"
rust-version = "1.56"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "basic_4"
[features]
no-entrypoint = []
cpi = ["no-entrypoint"]
[dependencies]
anchor-lang = { path = "../../../../../lang" }

View File

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

View File

@ -1,44 +0,0 @@
// #region code
use anchor_lang::prelude::*;
declare_id!("CwrqeMj2U8tFr1Rhkgwc84tpAsqbt9pTt2a4taoTADPr");
#[program]
pub mod basic_4 {
use super::*;
#[state]
pub struct Counter {
pub authority: Pubkey,
pub count: u64,
}
impl Counter {
pub fn new(ctx: Context<Auth>) -> anchor_lang::Result<Self> {
Ok(Self {
authority: *ctx.accounts.authority.key,
count: 0,
})
}
pub fn increment(&mut self, ctx: Context<Auth>) -> anchor_lang::Result<()> {
if &self.authority != ctx.accounts.authority.key {
return Err(error!(ErrorCode::Unauthorized));
}
self.count += 1;
Ok(())
}
}
}
#[derive(Accounts)]
pub struct Auth<'info> {
authority: Signer<'info>,
}
// #endregion code
#[error_code]
pub enum ErrorCode {
#[msg("You are not authorized to perform this action.")]
Unauthorized,
}

View File

@ -1,41 +0,0 @@
const assert = require("assert");
const anchor = require("@project-serum/anchor");
describe("basic-4", () => {
const provider = anchor.AnchorProvider.local();
// Configure the client to use the local cluster.
anchor.setProvider(provider);
const program = anchor.workspace.Basic4;
it("Is runs the constructor", async () => {
// #region ctor
// Initialize the program's state struct.
await program.state.rpc.new({
accounts: {
authority: provider.wallet.publicKey,
},
});
// #endregion ctor
// Fetch the state struct from the network.
// #region accessor
const state = await program.state.fetch();
// #endregion accessor
assert.ok(state.count.eq(new anchor.BN(0)));
});
it("Executes a method on the program", async () => {
// #region instruction
await program.state.rpc.increment({
accounts: {
authority: provider.wallet.publicKey,
},
});
// #endregion instruction
const state = await program.state.fetch();
assert.ok(state.count.eq(new anchor.BN(1)));
});
});

View File

@ -1,22 +0,0 @@
{
"name": "anchor-examples",
"private": true,
"scripts": {
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
},
"workspaces": [
"basic-0",
"basic-1",
"basic-2",
"basic-3",
"basic-4"
],
"dependencies": {
"@project-serum/anchor": "file:../../ts"
},
"devDependencies": {
"mocha": "^9.1.3",
"prettier": "^2.5.1"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1

View File

@ -1,44 +0,0 @@
[package]
name = "anchor-lang"
version = "0.24.2"
authors = ["Serum Foundation <foundation@projectserum.com>"]
repository = "https://github.com/project-serum/anchor"
rust-version = "1.56"
edition = "2021"
license = "Apache-2.0"
description = "Solana Sealevel eDSL"
[features]
init-if-needed = ["anchor-derive-accounts/init-if-needed"]
derive = []
default = []
anchor-debug = [
"anchor-attribute-access-control/anchor-debug",
"anchor-attribute-account/anchor-debug",
"anchor-attribute-constant/anchor-debug",
"anchor-attribute-error/anchor-debug",
"anchor-attribute-event/anchor-debug",
"anchor-attribute-interface/anchor-debug",
"anchor-attribute-program/anchor-debug",
"anchor-attribute-program/anchor-debug",
"anchor-attribute-state/anchor-debug",
"anchor-derive-accounts/anchor-debug"
]
[dependencies]
anchor-attribute-access-control = { path = "./attribute/access-control", version = "0.24.2" }
anchor-attribute-account = { path = "./attribute/account", version = "0.24.2" }
anchor-attribute-constant = { path = "./attribute/constant", version = "0.24.2" }
anchor-attribute-error = { path = "./attribute/error", version = "0.24.2" }
anchor-attribute-program = { path = "./attribute/program", version = "0.24.2" }
anchor-attribute-state = { path = "./attribute/state", version = "0.24.2" }
anchor-attribute-interface = { path = "./attribute/interface", version = "0.24.2" }
anchor-attribute-event = { path = "./attribute/event", version = "0.24.2" }
anchor-derive-accounts = { path = "./derive/accounts", version = "0.24.2" }
arrayref = "0.3.6"
base64 = "0.13.0"
borsh = "0.9"
bytemuck = "1.4.0"
solana-program = "~1.9.13"
thiserror = "1.0.20"
bincode = "1.3.3"

View File

@ -1,23 +0,0 @@
[package]
name = "anchor-attribute-access-control"
version = "0.24.2"
authors = ["Serum Foundation <foundation@projectserum.com>"]
repository = "https://github.com/project-serum/anchor"
license = "Apache-2.0"
description = "Anchor attribute macro for instruction access control"
rust-version = "1.56"
edition = "2021"
[lib]
proc-macro = true
[features]
anchor-debug = ["anchor-syn/anchor-debug"]
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0.60", features = ["full"] }
anyhow = "1.0.32"
anchor-syn = { path = "../../syn", version = "0.24.2" }
regex = "1.0"

View File

@ -1,81 +0,0 @@
extern crate proc_macro;
use quote::quote;
use syn::parse_macro_input;
/// Executes the given access control method before running the decorated
/// instruction handler. Any method in scope of the attribute can be invoked
/// with any arguments from the associated instruction handler.
///
/// # Example
///
/// ```ignore
/// use anchor_lang::prelude::*;
///
/// #[program]
/// mod errors {
/// use super::*;
///
/// #[access_control(Create::accounts(&ctx, bump_seed))]
/// pub fn create(ctx: Context<Create>, bump_seed: u8) -> Result<()> {
/// let my_account = &mut ctx.accounts.my_account;
/// my_account.bump_seed = bump_seed;
/// }
/// }
///
/// #[derive(Accounts)]
/// pub struct Create {
/// #[account(init)]
/// my_account: Account<'info, MyAccount>,
/// }
///
/// impl Create {
/// pub fn accounts(ctx: &Context<Create>, bump_seed: u8) -> Result<()> {
/// let seeds = &[ctx.accounts.my_account.to_account_info().key.as_ref(), &[bump_seed]];
/// Pubkey::create_program_address(seeds, ctx.program_id)
/// .map_err(|_| ErrorCode::InvalidNonce)?;
/// Ok(())
/// }
/// }
/// ```
///
/// This example demonstrates a useful pattern. Not only can you use
/// `#[access_control]` to ensure any invariants or preconditions hold prior to
/// executing an instruction, but also it can be used to finish any validation
/// on the `Accounts` struct, particularly when instruction arguments are
/// needed. Here, we use the given `bump_seed` to verify it creates a valid
/// program-derived address.
#[proc_macro_attribute]
pub fn access_control(
args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let mut args = args.to_string();
args.retain(|c| !c.is_whitespace());
let access_control: Vec<proc_macro2::TokenStream> = args
.split(')')
.filter(|ac| !ac.is_empty())
.map(|ac| format!("{})", ac)) // Put back on the split char.
.map(|ac| format!("{}?;", ac)) // Add `?;` syntax.
.map(|ac| ac.parse().unwrap())
.collect();
let item_fn = parse_macro_input!(input as syn::ItemFn);
let fn_attrs = item_fn.attrs;
let fn_vis = item_fn.vis;
let fn_sig = item_fn.sig;
let fn_block = item_fn.block;
let fn_stmts = fn_block.stmts;
proc_macro::TokenStream::from(quote! {
#(#fn_attrs)*
#fn_vis #fn_sig {
#(#access_control)*
#(#fn_stmts)*
}
})
}

View File

@ -1,24 +0,0 @@
[package]
name = "anchor-attribute-account"
version = "0.24.2"
authors = ["Serum Foundation <foundation@projectserum.com>"]
repository = "https://github.com/project-serum/anchor"
license = "Apache-2.0"
description = "Anchor attribute macro for defining an account"
rust-version = "1.56"
edition = "2021"
[lib]
proc-macro = true
[features]
anchor-debug = ["anchor-syn/anchor-debug"]
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0.60", features = ["full"] }
anyhow = "1.0.32"
anchor-syn = { path = "../../syn", version = "0.24.2", features = ["hash"] }
rustversion = "1.0.3"
bs58 = "0.4.0"

View File

@ -1,296 +0,0 @@
//! Copied from solana/sdk/macro so that Anchor programs don't need to specify
//! `solana_program` as an additional crate dependency, but instead can access
//! it via `anchor_lang::declare_id`.
//!
//! Convenience macro to declare a static public key and functions to interact with it
//!
//! Input: a single literal base58 string representation of a program's id
extern crate proc_macro;
use proc_macro2::{Delimiter, Span, TokenTree};
use quote::{quote, ToTokens};
use std::convert::TryFrom;
use syn::{
bracketed,
parse::{Parse, ParseStream, Result},
punctuated::Punctuated,
token::Bracket,
Expr, Ident, LitByte, LitStr, Path, Token,
};
fn parse_id(
input: ParseStream,
pubkey_type: proc_macro2::TokenStream,
) -> Result<proc_macro2::TokenStream> {
let id = if input.peek(syn::LitStr) {
let id_literal: LitStr = input.parse()?;
parse_pubkey(&id_literal, &pubkey_type)?
} else {
let expr: Expr = input.parse()?;
quote! { #expr }
};
if !input.is_empty() {
let stream: proc_macro2::TokenStream = input.parse()?;
return Err(syn::Error::new_spanned(stream, "unexpected token"));
}
Ok(id)
}
fn id_to_tokens(
id: &proc_macro2::TokenStream,
pubkey_type: proc_macro2::TokenStream,
tokens: &mut proc_macro2::TokenStream,
) {
tokens.extend(quote! {
/// The static program ID
pub static ID: #pubkey_type = #id;
/// Confirms that a given pubkey is equivalent to the program ID
pub fn check_id(id: &#pubkey_type) -> bool {
id == &ID
}
/// Returns the program ID
pub fn id() -> #pubkey_type {
ID
}
#[cfg(test)]
#[test]
fn test_id() {
assert!(check_id(&id()));
}
});
}
fn deprecated_id_to_tokens(
id: &proc_macro2::TokenStream,
pubkey_type: proc_macro2::TokenStream,
tokens: &mut proc_macro2::TokenStream,
) {
tokens.extend(quote! {
/// The static program ID
pub static ID: #pubkey_type = #id;
/// Confirms that a given pubkey is equivalent to the program ID
#[deprecated()]
pub fn check_id(id: &#pubkey_type) -> bool {
id == &ID
}
/// Returns the program ID
#[deprecated()]
pub fn id() -> #pubkey_type {
ID
}
#[cfg(test)]
#[test]
fn test_id() {
#[allow(deprecated)]
assert!(check_id(&id()));
}
});
}
pub struct Id(proc_macro2::TokenStream);
impl Parse for Id {
fn parse(input: ParseStream) -> Result<Self> {
parse_id(
input,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
)
.map(Self)
}
}
impl ToTokens for Id {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
id_to_tokens(
&self.0,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
tokens,
)
}
}
struct IdDeprecated(proc_macro2::TokenStream);
impl Parse for IdDeprecated {
fn parse(input: ParseStream) -> Result<Self> {
parse_id(
input,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
)
.map(Self)
}
}
impl ToTokens for IdDeprecated {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
deprecated_id_to_tokens(
&self.0,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
tokens,
)
}
}
struct ProgramSdkId(proc_macro2::TokenStream);
impl Parse for ProgramSdkId {
fn parse(input: ParseStream) -> Result<Self> {
parse_id(
input,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
)
.map(Self)
}
}
impl ToTokens for ProgramSdkId {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
id_to_tokens(
&self.0,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
tokens,
)
}
}
struct ProgramSdkIdDeprecated(proc_macro2::TokenStream);
impl Parse for ProgramSdkIdDeprecated {
fn parse(input: ParseStream) -> Result<Self> {
parse_id(
input,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
)
.map(Self)
}
}
impl ToTokens for ProgramSdkIdDeprecated {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
deprecated_id_to_tokens(
&self.0,
quote! { anchor_lang::solana_program::pubkey::Pubkey },
tokens,
)
}
}
#[allow(dead_code)] // `respan` may be compiled out
struct RespanInput {
to_respan: Path,
respan_using: Span,
}
impl Parse for RespanInput {
fn parse(input: ParseStream) -> Result<Self> {
let to_respan: Path = input.parse()?;
let _comma: Token![,] = input.parse()?;
let respan_tree: TokenTree = input.parse()?;
match respan_tree {
TokenTree::Group(g) if g.delimiter() == Delimiter::None => {
let ident: Ident = syn::parse2(g.stream())?;
Ok(RespanInput {
to_respan,
respan_using: ident.span(),
})
}
val => Err(syn::Error::new_spanned(
val,
"expected None-delimited group",
)),
}
}
}
fn parse_pubkey(
id_literal: &LitStr,
pubkey_type: &proc_macro2::TokenStream,
) -> Result<proc_macro2::TokenStream> {
let id_vec = bs58::decode(id_literal.value())
.into_vec()
.map_err(|_| syn::Error::new_spanned(&id_literal, "failed to decode base58 string"))?;
let id_array = <[u8; 32]>::try_from(<&[u8]>::clone(&&id_vec[..])).map_err(|_| {
syn::Error::new_spanned(
&id_literal,
format!("pubkey array is not 32 bytes long: len={}", id_vec.len()),
)
})?;
let bytes = id_array.iter().map(|b| LitByte::new(*b, Span::call_site()));
Ok(quote! {
#pubkey_type::new_from_array(
[#(#bytes,)*]
)
})
}
struct Pubkeys {
method: Ident,
num: usize,
pubkeys: proc_macro2::TokenStream,
}
impl Parse for Pubkeys {
fn parse(input: ParseStream) -> Result<Self> {
let pubkey_type = quote! {
anchor_lang::solana_program::pubkey::Pubkey
};
let method = input.parse()?;
let _comma: Token![,] = input.parse()?;
let (num, pubkeys) = if input.peek(syn::LitStr) {
let id_literal: LitStr = input.parse()?;
(1, parse_pubkey(&id_literal, &pubkey_type)?)
} else if input.peek(Bracket) {
let pubkey_strings;
bracketed!(pubkey_strings in input);
let punctuated: Punctuated<LitStr, Token![,]> =
Punctuated::parse_terminated(&pubkey_strings)?;
let mut pubkeys: Punctuated<proc_macro2::TokenStream, Token![,]> = Punctuated::new();
for string in punctuated.iter() {
pubkeys.push(parse_pubkey(string, &pubkey_type)?);
}
(pubkeys.len(), quote! {#pubkeys})
} else {
let stream: proc_macro2::TokenStream = input.parse()?;
return Err(syn::Error::new_spanned(stream, "unexpected token"));
};
Ok(Pubkeys {
method,
num,
pubkeys,
})
}
}
impl ToTokens for Pubkeys {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let Pubkeys {
method,
num,
pubkeys,
} = self;
let pubkey_type = quote! {
anchor_lang::solana_program::pubkey::Pubkey
};
if *num == 1 {
tokens.extend(quote! {
pub fn #method() -> #pubkey_type {
#pubkeys
}
});
} else {
tokens.extend(quote! {
pub fn #method() -> ::std::vec::Vec<#pubkey_type> {
vec![#pubkeys]
}
});
}
}
}

Some files were not shown because too many files have changed in this diff Show More