diff --git a/basics/anchorpy-main/Makefile b/basics/anchorpy-main/Makefile new file mode 100644 index 0000000..b334067 --- /dev/null +++ b/basics/anchorpy-main/Makefile @@ -0,0 +1,12 @@ +test: + poetry run pytest -vv + +init-clientgen-examples: + cd tests/client_gen/example-program/ && anchor idl parse -f programs/example-program/src/lib.rs -o ../../idls/clientgen_example_program.json && cd ../../.. && poetry run anchorpy client-gen tests/idls/clientgen_example_program.json tests/client_gen/example_program_gen --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 --pdas + poetry run anchorpy client-gen tests/idls/basic_2.json examples/client-gen/basic_2 --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 + poetry run anchorpy client-gen tests/idls/tictactoe.json examples/client-gen/tictactoe --program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 + poetry run anchorpy client-gen tests/idls/spl_token.json tests/client_gen/token --program-id TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA + +lint: + poetry run ruff src tests + poetry run mypy src tests diff --git a/basics/anchorpy-main/README.md b/basics/anchorpy-main/README.md new file mode 100644 index 0000000..aceffbb --- /dev/null +++ b/basics/anchorpy-main/README.md @@ -0,0 +1,38 @@ +# AnchorPy + + +AnchorPy is the gateway to interacting with [Anchor](https://github.com/project-serum/anchor) programs in Python. +It provides: + +- A static client generator +- A dynamic client similar to `anchor-ts` +- A Pytest plugin +- A CLI with various utilities for Anchor Python development. + + + + +## Installation (requires Python >=3.9) + +```sh +pip install anchorpy[cli] + +``` +Or, if you're not using the CLI features of AnchorPy you can just run `pip install anchorpy`. + +### Development Setup + +If you want to contribute to AnchorPy, follow these steps to get set up: + +1. Install [poetry](https://python-poetry.org/docs/#installation) +2. Install dev dependencies: +```sh +poetry install + +``` +3. Install [nox-poetry](https://github.com/cjolowicz/nox-poetry) (note: do not use Poetry to install this, see [here](https://medium.com/@cjolowicz/nox-is-a-part-of-your-global-developer-environment-like-poetry-pre-commit-pyenv-or-pipx-1cdeba9198bd)) +4. Activate the poetry shell: +```sh +poetry shell + +``` diff --git a/basics/anchorpy-main/docs/cli/index.md b/basics/anchorpy-main/docs/cli/index.md new file mode 100644 index 0000000..d32f867 --- /dev/null +++ b/basics/anchorpy-main/docs/cli/index.md @@ -0,0 +1,80 @@ +# AnchorPy CLI + +AnchorPy comes with a CLI to make your life easier when using Python with Anchor. + + +```console +$ anchorpy --help +Usage: anchorpy [OPTIONS] COMMAND [ARGS]... + + AnchorPy CLI. + +Options: + --install-completion [bash|zsh|fish|powershell|pwsh] + Install completion for the specified shell. + --show-completion [bash|zsh|fish|powershell|pwsh] + Show completion for the specified shell, to + copy it or customize the installation. + --help Show this message and exit. + +Commands: + init Create a basic Python test file for an Anchor program. + shell Start IPython shell with AnchorPy workspace object initialized. +``` + +## Commands + +### Init + +```console +$ anchorpy init --help +Usage: anchorpy init [OPTIONS] PROGRAM_NAME + + Create a basic Python test file for an Anchor program. + + This does not replace `anchor init`, but rather should be run after it. + + The test file will live at `tests/test_$PROGRAM_NAME.py`. + +Arguments: + PROGRAM_NAME The name of the Anchor program. [required] + +Options: + --help Show this message and exit. +``` + +### Shell + +```console +$ anchorpy shell --help +Usage: anchorpy shell [OPTIONS] + + Start IPython shell with AnchorPy workspace object initialized. + + Note that you should run `anchor localnet` before `anchorpy shell`. + +Options: + --help Show this message and exit. +``` + +#### Example + +
+ +```console +$ cd anchor/examples/tutorial/basic-0 && anchorpy shell +Python 3.9.1 (default, Dec 11 2020, 14:32:07) +Type 'copyright', 'credits' or 'license' for more information +IPython 7.30.1 -- An enhanced Interactive Python. Type '?' for help. + +Hint: type `workspace` to see the Anchor workspace object. + +# In [1]:$ await workspace["basic_0"].rpc["initialize"]() +Out[1]: '2q1Z8BcsSBikMLEFoeFGhUukfsNYLJx7y33rMZ57Eh4gAHJxpJ9oP9b9aFyrizh9wcuiVtAAxvmBifCXdqWeNLor' +``` + +
+ +### Client-gen + +See [Client Generator](../clientgen) \ No newline at end of file diff --git a/basics/anchorpy-main/docs/clientgen/index.md b/basics/anchorpy-main/docs/clientgen/index.md new file mode 100644 index 0000000..d44f8ce --- /dev/null +++ b/basics/anchorpy-main/docs/clientgen/index.md @@ -0,0 +1,206 @@ +# Client Generator + +The `anchorpy client-gen` command generates a Python client based on an Anchor IDL. This client provides functions for +generating instructions and class definitions for fetching and serializing accounts. The output is very similar +to the Typescript code produced by [anchor-client-gen](https://github.com/kklas/anchor-client-gen). + +## Features + +- Fully typed. +- Supports all Anchor field types. +- Makes enums and complex types easy to work with. +- Generates error classes for each error. +- Provides `to_json` and `from_json` utility functions for types and accounts. + +!!! note + It is recommended to use the generated client instead of the dynamic client where possible, as it is easier to + work with and comes with proper type hints. + +## Usage + +```console +$ anchorpy client-gen --help +Usage: anchorpy client-gen [OPTIONS] IDL OUT + + Generate Python client code from the specified anchor IDL. + +Arguments: + IDL Anchor IDL file path [required] + OUT Output directory. [required] + +Options: + --program-id TEXT Optional program ID to be included in the code + --help Show this message and exit. + +``` + +## Example + +
+ +```console +$ anchorpy client-gen path/to/idl.json ./my_client +generating package... +generating program_id.py... +generating errors.py... +generating instructions... +generating types... +generating accounts... +``` + +
+ +This will generate code to `./my_client`: + +``` +. +├── accounts +│ ├── foo_account.py +│ └── __init__.py +├── instructions +│ ├── some_instruction.py +│ ├── other_instruction.py +│ └── __init__.py +├── types +│ ├── bar_struct.py +│ ├── baz_enum.py +│ └── __init__.py +├── errors +│ ├── anchor.py +│ ├── custom.py +│ └── __init__.py +└── program_id.py +``` + +## Using the generated client + +### Instructions + +```python +from solana.transaction import Transaction +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from anchorpy import Provider +from my_client.instructions import some_instruction + + # call an instruction +foo_account = Keypair() + +ix = some_instruction({ + "foo_param": "...", + "bar_param": "...", + ... +}, { + "foo_account": foo_account.pubkey(), # signer + "bar_account": Pubkey("..."), + ... +}) +tx = Transaction().add(ix) + +provider = Provider.local() + +await provider.send(tx, [payer, foo_account]) +``` + +### Accounts + +```python +from solders.pubkey import Pubkey +from my_client.accounts import FooAccount + +# fetch an account +addr = Pubkey("...") + +acc = await FooAccount.fetch(connection, addr) +if acc is None: + # the fetch method returns null when the account is uninitialized + raise ValueError("account not found") + + +# convert to a JSON object +obj = acc.to_json() +print(obj) + +# load from JSON +acc_from_json = FooAccount.from_json(obj) +``` + +### Types + +```python +# structs + +from my_client.types import BarStruct + +bar_struct = BarStruct( + some_field="...", + other_field="...", +) + +print(bar_struct.to_json()) +``` + +```python +# enums + +from my_client.types import baz_enum + +tuple_enum = baz_enum.SomeTupleKind((True, False, "some value")) +struct_enum = baz_enum.SomeStructKind({ + "field1": "...", + "field2": "...", +}) +disc_enum = baz_enum.SomeDiscriminantKind() + +print(tuple_enum.toJSON(), struct_enum.toJSON(), disc_enum.toJSON()) +``` + +```python +# types are used as arguments in instruction calls (where needed): +ix = some_instruction({ + "some_struct_field": bar_struct, + "some_enum_field": tuple_enum, + # ... +}, { + # accounts + # ... +}) + +# in case of struct fields, it's also possible to pass them as objects: +ix = some_instruction({ + "some_struct_field": { + "some_field": "...", + "other_field": "...", + }, + # ..., +}, { + # accounts + # ... +}) +``` + +### Errors + +```python +from solana.rpc.core import RPCException +from my_client.errors import from_tx_error +from my_client.errors.custom import SomeCustomError + +try: + await provider.send(tx, [payer]) +except RPCException as exc: + parsed = from_tx_error(exc) + raise parsed from exc +``` + +## Program ID + +The client generator pulls the program ID from: + +- the input IDL +- the `--program-id` flag + +If the IDL doesn't contain the program ID then you will need to pass it via the `--program-id` flag. + +This program ID is then written into the `program_id.py` file. + diff --git a/basics/anchorpy-main/docs/css/custom.css b/basics/anchorpy-main/docs/css/custom.css new file mode 100644 index 0000000..574fc63 --- /dev/null +++ b/basics/anchorpy-main/docs/css/custom.css @@ -0,0 +1,25 @@ +.termynal-comment { + color: #4a968f; + font-style: italic; + display: block; +} + +.termy [data-termynal] { + white-space: pre-wrap; + font-size: 14px; + overflow-wrap: break-word; +} + +a.external-link::after { + /* \00A0 is a non-breaking space + to make the mark be on the same line as the link + */ + content: "\00A0[↪]"; +} + +a.internal-link::after { + /* \00A0 is a non-breaking space + to make the mark be on the same line as the link + */ + content: "\00A0↪"; +} \ No newline at end of file diff --git a/basics/anchorpy-main/docs/css/mkdocstrings.css b/basics/anchorpy-main/docs/css/mkdocstrings.css new file mode 100644 index 0000000..024fe6e --- /dev/null +++ b/basics/anchorpy-main/docs/css/mkdocstrings.css @@ -0,0 +1,6 @@ +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: 4px solid rgba(230, 230, 230); + margin-bottom: 80px; + } diff --git a/basics/anchorpy-main/docs/css/termynal.css b/basics/anchorpy-main/docs/css/termynal.css new file mode 100644 index 0000000..dfe3caa --- /dev/null +++ b/basics/anchorpy-main/docs/css/termynal.css @@ -0,0 +1,108 @@ +/** + * termynal.js + * + * @author Ines Montani + * @version 0.0.1 + * @license MIT + */ + + :root { + --color-bg: #252a33; + --color-text: #eee; + --color-text-subtle: #a2a2a2; +} + +[data-termynal] { + width: 750px; + max-width: 100%; + background: var(--color-bg); + color: var(--color-text); + font-size: 18px; + /* font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; */ + font-family: 'Roboto Mono', 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; + border-radius: 4px; + padding: 75px 45px 35px; + position: relative; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +[data-termynal]:before { + content: ''; + position: absolute; + top: 15px; + left: 15px; + display: inline-block; + width: 15px; + height: 15px; + border-radius: 50%; + /* A little hack to display the window buttons in one pseudo element. */ + background: #d9515d; + -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; + box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; +} + +[data-termynal]:after { + content: 'bash'; + position: absolute; + color: var(--color-text-subtle); + top: 5px; + left: 0; + width: 100%; + text-align: center; +} + +a[data-terminal-control] { + text-align: right; + display: block; + color: #aebbff; +} + +[data-ty] { + display: block; + line-height: 2; +} + +[data-ty]:before { + /* Set up defaults and ensure empty lines are displayed. */ + content: ''; + display: inline-block; + vertical-align: middle; +} + +[data-ty="input"]:before, +[data-ty-prompt]:before { + margin-right: 0.75em; + color: var(--color-text-subtle); +} + +[data-ty="input"]:before { + content: '$'; +} + +[data-ty][data-ty-prompt]:before { + content: attr(data-ty-prompt); +} + +[data-ty-cursor]:after { + content: attr(data-ty-cursor); + font-family: monospace; + margin-left: 0.5em; + -webkit-animation: blink 1s infinite; + animation: blink 1s infinite; +} + + +/* Cursor animation */ + +@-webkit-keyframes blink { + 50% { + opacity: 0; + } +} + +@keyframes blink { + 50% { + opacity: 0; + } +} diff --git a/basics/anchorpy-main/docs/dynamic_client/api_reference.md b/basics/anchorpy-main/docs/dynamic_client/api_reference.md new file mode 100644 index 0000000..261b98d --- /dev/null +++ b/basics/anchorpy-main/docs/dynamic_client/api_reference.md @@ -0,0 +1,27 @@ +# API Reference + + +:::anchorpy.Program +:::anchorpy.Provider +:::anchorpy.Context +:::anchorpy.create_workspace +:::anchorpy.close_workspace +:::anchorpy.bankrun_fixture +:::anchorpy.workspace_fixture +:::anchorpy.localnet_fixture +:::anchorpy.Wallet +:::anchorpy.Coder +:::anchorpy.InstructionCoder +:::anchorpy.EventCoder +:::anchorpy.AccountsCoder +:::anchorpy.NamedInstruction +:::anchorpy.IdlProgramAccount +:::anchorpy.Event +:::anchorpy.translate_address +:::anchorpy.validate_accounts +:::anchorpy.AccountClient +:::anchorpy.ProgramAccount +:::anchorpy.EventParser +:::anchorpy.SimulateResponse +:::anchorpy.error +:::anchorpy.utils diff --git a/basics/anchorpy-main/docs/dynamic_client/comparison_with_anchor_ts.md b/basics/anchorpy-main/docs/dynamic_client/comparison_with_anchor_ts.md new file mode 100644 index 0000000..db3e220 --- /dev/null +++ b/basics/anchorpy-main/docs/dynamic_client/comparison_with_anchor_ts.md @@ -0,0 +1,36 @@ +# Comparison with Typescript + +While AnchorPy is quite similar to the Anchor Typescript client, +there are some differences: + +## Dictionaries instead of objects + +AnchorPy tends to use dictionaries, so it uses `[key]` in some places where +`anchor-ts` would use `.key`. +For example, AnchorPy uses `workspace["basic_1"]` instead of `workspace.basic_1`, +and `program.rpc["initialize"]()` instead of `program.rpc.initialize()` + +## Explicit `Context` object + +AnchorPy uses a `Context` dataclass and has a `ctx` keyword argument when +calling `.rpc` functions, whereas Typescript is a bit less structured. + +We call `program.rpc["my_func"](ctx=Context({"my_account": my_account}))` +instead of `program.rpc["my_func"]({"my_account": my_account})` + +## snake_case 🐍 instead of camelCase 🐪 + +AnchorPy uses more `snake_case` to match Rust and be Pythonic. +Specifically, the following names are snake-case in AnchorPy: + +- Workspaces: `workspace["puppet_master"]` instead of `workspace["puppetMaster"]` +- Instructions: `program.rpc["my_func"]` (and `program.instruction["my_func"]`) instead of +`program.rpc["myFunc"]`. +- Accounts in the `ctx` arg: `{"my_account": my_account}` instead of `{"myAccount": my_account}` +- Fields in user-defined types: `program.type["TransactionAccount"](is_writable=True)` instead of +`program.type["TransactionAccount"](isWritable=True)` + +## `program.type` namespace for user-defined types + +The AnchorPy `Program` object has a `.type` attribute for instantiating user-defined types. This is not present in +the Typescript client. See the [examples](examples.md) for more on this. diff --git a/basics/anchorpy-main/docs/dynamic_client/examples.md b/basics/anchorpy-main/docs/dynamic_client/examples.md new file mode 100644 index 0000000..b91b806 --- /dev/null +++ b/basics/anchorpy-main/docs/dynamic_client/examples.md @@ -0,0 +1,85 @@ +# Examples + +Here are some of the other things you can do with AnchorPy: + +## Loading a Program from an on-chain IDL + +If a program's IDL is stored on-chain, you can use it +to initialize a program object using `Program.at`. + +````python +import asyncio +from solana.rpc.async_api import AsyncClient +from solders.pubkey import Pubkey +from anchorpy import Program, Provider, Wallet + + +async def main(): + client = AsyncClient("https://api.mainnet-beta.solana.com/") + provider = Provider(client, Wallet.local()) + # load the Serum Swap Program (not the Serum dex itself). + program_id = Pubkey.from_string("22Y43yTVxuUkoRKdm9thyRhQ3SdgQS7c7kB6UNCiaczD") + program = await Program.at( + program_id, provider + ) + print(program.idl.name) # swap + await program.close() + + +asyncio.run(main()) + + +```` + +## Instantiating user-defined types with `program.type` + +### Enums + +Suppose we have an instruction that expects an Enum called `Side`, +with variants `Buy` and `Sell`. The `Program` object has a `.type` +namespace to make it easy to use this enum: + +````python +await program.rpc["my_func"](program.type["Side"].Buy()) + +```` +See [test_token_proxy.py](https://github.com/kevinheavey/anchorpy/blob/main/tests/test_token_proxy.py) +for a more concrete example. + +### Structs + +`.type` also allows us to build structs defined in the IDL. +See this snippet from [test_multisig.py](https://github.com/kevinheavey/anchorpy/blob/main/tests/test_multisig.py): + +````python +program.type["TransactionAccount"]( + pubkey=multisig.pubkey(), + is_writable=True, + is_signer=False, +) + +```` + +## Bulk-fetching data with `.fetch_multiple` + +You can use `.fetch_multiple` to get deserialized account data +for many accounts at once. Look at this example from `test_misc.py`: + +````python +n_accounts = 200 +pubkeys = [initialized_keypair.pubkey()] * n_accounts # noqa: WPS435 +data_accounts = await program.account["Data"].fetch_multiple( + pubkeys, batch_size=2 +) + +```` + +The above example fetches data for the same pubkey 200 times which is +not very interesting, but it could just as easily be fetching 200 +different accounts. The `.fetch_multiple` method uses async batch RPC requests +and `getMultipleAccounts` so it's quite efficient. + +!!! warning + Be mindful of your RPC provider when fetching data, and plan out how + many requests you'll end up sending to the RPC node. You can reliably + fetch around 300 public keys in one HTTP request. diff --git a/basics/anchorpy-main/docs/dynamic_client/index.md b/basics/anchorpy-main/docs/dynamic_client/index.md new file mode 100644 index 0000000..517022a --- /dev/null +++ b/basics/anchorpy-main/docs/dynamic_client/index.md @@ -0,0 +1,165 @@ +# Tutorial + + +!!! note + It is recommended to use the generated client instead of the dynamic client where possible, as it is easier to + work with and comes with proper type hints. + +This tutorial takes the JS snippets from the official Anchor tutorial +and shows how to achieve the same thing using AnchorPy. + +## [A Minimal Example](https://project-serum.github.io/anchor/tutorials/tutorial-0.html) +This section covers the `basic-0` tutorial: +### [Generating a Client](https://project-serum.github.io/anchor/tutorials/tutorial-0.html#generating-a-client) +Here is how we generate a client from an IDL and use it to interact with a smart contract. + + +=== "Python" + ````python + from pathlib import Path + import asyncio + import json + from solders.pubkey import Pubkey + from anchorpy import Idl, Program + + async def main(): + # Read the generated IDL. + with Path("target/idl/basic_0.json").open() as f: + raw_idl = f.read() + idl = Idl.from_json(raw_idl) + # Address of the deployed program. + program_id = Pubkey.from_string("") + # Generate the program client from IDL. + async with Program(idl, program_id) as program: + # Execute the RPC. + await program.rpc["initialize"]() + # If we don't use the context manager, we need to + # close the underlying http client, otherwise we get warnings. + # await program.close() + + asyncio.run(main()) + + ```` + +=== "JS" + ````javascript + // 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.Pubkey(''); + + // Generate the program client from IDL. + const program = new anchor.Program(idl, programId); + + // Execute the RPC. + await program.rpc.initialize(); + + ```` + +Note the differences between Python and JS here: + +- We call `program.rpc["initialize"]()` instead of `program.rpc.initialize()` +- We call `program.close()` to close the HTTP connection. + +### [Workspaces](https://project-serum.github.io/anchor/tutorials/tutorial-0.html#workspaces) + +Here is how workspaces look in AnchorPy: + + +=== "Python" + ````python + import asyncio + from anchorpy import create_workspace, close_workspace + + async def main(): + # Read the deployed program from the workspace. + workspace = create_workspace() + program = workspace["basic_0"] + # Execute the RPC. + await program.rpc["initialize"]() + # Close all HTTP clients in the workspace, otherwise we get warnings. + await close_workspace(workspace) + + asyncio.run(main()) + + ```` + +=== "JS" + ````javascript + // Read the deployed program from the workspace. + const program = anchor.workspace.Basic0; + + // Execute the RPC. + await program.rpc.initialize(); + + ```` + +Note the differences between Python and JS: + +- Workspace instantiation is explicit: we have to call the `create_workspace` function. + - Note however that AnchorPy provides the `workspace_fixture` factory for convenience. + See the [testing](../testing/index.md) section for more. +- We have a `close_workspace` function that calls `close_program` on all the programs +in the workspace. +- The workspace is called `basic_0` instead of `Basic0`. This is because AnchorPy uses snake case 🐍 +!!! Note + AnchorPy uses the same case convention as Rust, so names should look just like they do in `lib.rs`. + If you're unsure of a name, check `program.idl`: it shows how AnchorPy sees the IDL after parsing + it and converting some cases. + +## [Arguments and Accounts](https://project-serum.github.io/anchor/tutorials/tutorial-1.html) +### [Creating and Initializing Accounts](https://project-serum.github.io/anchor/tutorials/tutorial-1.html#creating-and-initializing-accounts) + +Here is how we call an RPC function with arguments. +As in the main Anchor tutorial, we will use `anchor/tutorial/examples/basic-1`: + +=== "Python" + ````python + import asyncio + from solders.keypair import Keypair + from solders.system_program import ID as SYS_PROGRAM_ID + from anchorpy import create_workspace, close_workspace, Context + + async def main(): + # Read the deployed program from the workspace. + workspace = create_workspace() + # The program to execute. + program = workspace["basic_1"] + # The Account to create. + my_account = Keypair() + # Execute the RPC. + accounts = { + "my_account": my_account.pubkey(), + "user": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID + } + await program.rpc["initialize"](1234, ctx=Context(accounts=accounts, signers=[my_account])) + # Close all HTTP clients in the workspace, otherwise we get warnings. + await close_workspace(workspace) + + asyncio.run(main()) + + ```` + +=== "JS" + ````javascript + // The program to execute. + const program = anchor.workspace.Basic1; + + // The Account to create. + const myAccount = anchor.web3.Keypair(); + + // Create the new account and initialize it with the program. + await program.rpc.initialize(new anchor.BN(1234), { + accounts: { + myAccount: myAccount.Pubkey, + user: provider.wallet.Pubkey, + systemProgram: SystemProgram.programId, + }, + signers: [myAccount], + }); + + ```` + +Note how AnchorPy uses an explicit `Context` object in contrast to TS/JS. diff --git a/basics/anchorpy-main/docs/img/anchor.svg b/basics/anchorpy-main/docs/img/anchor.svg new file mode 100644 index 0000000..aa184c5 --- /dev/null +++ b/basics/anchorpy-main/docs/img/anchor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/basics/anchorpy-main/docs/img/logo.png b/basics/anchorpy-main/docs/img/logo.png new file mode 100644 index 0000000..7ba560c Binary files /dev/null and b/basics/anchorpy-main/docs/img/logo.png differ diff --git a/basics/anchorpy-main/docs/index.md b/basics/anchorpy-main/docs/index.md new file mode 100644 index 0000000..bb8c424 --- /dev/null +++ b/basics/anchorpy-main/docs/index.md @@ -0,0 +1,23 @@ +# Introduction +
+ +
+ +--- +AnchorPy is the gateway to interacting with [Anchor](https://github.com/project-serum/anchor) programs in Python. +It provides: + +- A [static client generator](clientgen) +- A [dynamic client](dynamic_client) similar to `anchor-ts` +- A [Pytest plugin](testing/#1-pytest-plugin) +- A [CLI](cli) with various utilities for Anchor Python development. + +## Installation (requires Python >= 3.9) + +```shell +pip install anchorpy[cli] +``` + + +!!! note + These docs will assume you've read the [Anchor documentation](https://www.anchor-lang.com/) first. diff --git a/basics/anchorpy-main/docs/js/custom.js b/basics/anchorpy-main/docs/js/custom.js new file mode 100644 index 0000000..45243eb --- /dev/null +++ b/basics/anchorpy-main/docs/js/custom.js @@ -0,0 +1,105 @@ +document.querySelectorAll(".use-termynal").forEach(node => { + node.style.display = "block"; + new Termynal(node, { + lineDelay: 500 + }); +}); +const progressLiteralStart = "---> 100%"; +const promptLiteralStart = "$ "; +const customPromptLiteralStart = "# "; +const termynalActivateClass = "termy"; +let termynals = []; + +function createTermynals() { + document + .querySelectorAll(`.${termynalActivateClass} .highlight`) + .forEach(node => { + const text = node.textContent; + const lines = text.split("\n"); + const useLines = []; + let buffer = []; + function saveBuffer() { + if (buffer.length) { + let isBlankSpace = true; + buffer.forEach(line => { + if (line) { + isBlankSpace = false; + } + }); + dataValue = {}; + if (isBlankSpace) { + dataValue["delay"] = 0; + } + if (buffer[buffer.length - 1] === "") { + // A last single
won't have effect + // so put an additional one + buffer.push(""); + } + const bufferValue = buffer.join("
"); + dataValue["value"] = bufferValue; + useLines.push(dataValue); + buffer = []; + } + } + for (let line of lines) { + if (line === progressLiteralStart) { + saveBuffer(); + useLines.push({ + type: "progress" + }); + } else if (line.startsWith(promptLiteralStart)) { + saveBuffer(); + const value = line.replace(promptLiteralStart, "").trimEnd(); + useLines.push({ + type: "input", + value: value + }); + } else if (line.startsWith("// ")) { + saveBuffer(); + const value = "💬 " + line.replace("// ", "").trimEnd(); + useLines.push({ + value: value, + class: "termynal-comment", + delay: 0 + }); + } else if (line.startsWith(customPromptLiteralStart)) { + saveBuffer(); + const promptStart = line.indexOf(promptLiteralStart); + if (promptStart === -1) { + console.error("Custom prompt found but no end delimiter", line) + } + const prompt = line.slice(0, promptStart).replace(customPromptLiteralStart, "") + let value = line.slice(promptStart + promptLiteralStart.length); + useLines.push({ + type: "input", + value: value, + prompt: prompt + }); + } else { + buffer.push(line); + } + } + saveBuffer(); + const div = document.createElement("div"); + node.replaceWith(div); + const termynal = new Termynal(div, { + lineData: useLines, + noInit: true, + lineDelay: 500 + }); + termynals.push(termynal); + }); +} + +function loadVisibleTermynals() { + termynals = termynals.filter(termynal => { + if (termynal.container.getBoundingClientRect().top - innerHeight <= 0) { + termynal.init(); + return false; + } + return true; + }); +} +window.addEventListener("scroll", loadVisibleTermynals); +createTermynals(); +loadVisibleTermynals(); diff --git a/basics/anchorpy-main/docs/js/termynal.js b/basics/anchorpy-main/docs/js/termynal.js new file mode 100644 index 0000000..a26c870 --- /dev/null +++ b/basics/anchorpy-main/docs/js/termynal.js @@ -0,0 +1,264 @@ +/** + * termynal.js + * A lightweight, modern and extensible animated terminal window, using + * async/await. + * + * @author Ines Montani + * @version 0.0.1 + * @license MIT + */ + +'use strict'; + +/** Generate a terminal widget. */ +class Termynal { + /** + * Construct the widget's settings. + * @param {(string|Node)=} container - Query selector or container element. + * @param {Object=} options - Custom settings. + * @param {string} options.prefix - Prefix to use for data attributes. + * @param {number} options.startDelay - Delay before animation, in ms. + * @param {number} options.typeDelay - Delay between each typed character, in ms. + * @param {number} options.lineDelay - Delay between each line, in ms. + * @param {number} options.progressLength - Number of characters displayed as progress bar. + * @param {string} options.progressChar – Character to use for progress bar, defaults to █. + * @param {number} options.progressPercent - Max percent of progress. + * @param {string} options.cursor – Character to use for cursor, defaults to ▋. + * @param {Object[]} lineData - Dynamically loaded line data objects. + * @param {boolean} options.noInit - Don't initialise the animation. + */ + constructor(container = '#termynal', options = {}) { + this.container = (typeof container === 'string') ? document.querySelector(container) : container; + this.pfx = `data-${options.prefix || 'ty'}`; + this.originalStartDelay = this.startDelay = options.startDelay + || parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600; + this.originalTypeDelay = this.typeDelay = options.typeDelay + || parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90; + this.originalLineDelay = this.lineDelay = options.lineDelay + || parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500; + this.progressLength = options.progressLength + || parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40; + this.progressChar = options.progressChar + || this.container.getAttribute(`${this.pfx}-progressChar`) || '█'; + this.progressPercent = options.progressPercent + || parseFloat(this.container.getAttribute(`${this.pfx}-progressPercent`)) || 100; + this.cursor = options.cursor + || this.container.getAttribute(`${this.pfx}-cursor`) || '▋'; + this.lineData = this.lineDataToElements(options.lineData || []); + this.loadLines() + if (!options.noInit) this.init() + } + + loadLines() { + // Load all the lines and create the container so that the size is fixed + // Otherwise it would be changing and the user viewport would be constantly + // moving as she/he scrolls + const finish = this.generateFinish() + finish.style.visibility = 'hidden' + this.container.appendChild(finish) + // Appends dynamically loaded lines to existing line elements. + this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData); + for (let line of this.lines) { + line.style.visibility = 'hidden' + this.container.appendChild(line) + } + const restart = this.generateRestart() + restart.style.visibility = 'hidden' + this.container.appendChild(restart) + this.container.setAttribute('data-termynal', ''); + } + + /** + * Initialise the widget, get lines, clear container and start animation. + */ + init() { + /** + * Calculates width and height of Termynal container. + * If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS. + */ + const containerStyle = getComputedStyle(this.container); + this.container.style.width = containerStyle.width !== '0px' ? + containerStyle.width : undefined; + this.container.style.minHeight = containerStyle.height !== '0px' ? + containerStyle.height : undefined; + + this.container.setAttribute('data-termynal', ''); + this.container.innerHTML = ''; + for (let line of this.lines) { + line.style.visibility = 'visible' + } + this.start(); + } + + /** + * Start the animation and rener the lines depending on their data attributes. + */ + async start() { + this.addFinish() + await this._wait(this.startDelay); + + for (let line of this.lines) { + const type = line.getAttribute(this.pfx); + const delay = line.getAttribute(`${this.pfx}-delay`) || this.lineDelay; + + if (type == 'input') { + line.setAttribute(`${this.pfx}-cursor`, this.cursor); + await this.type(line); + await this._wait(delay); + } + + else if (type == 'progress') { + await this.progress(line); + await this._wait(delay); + } + + else { + this.container.appendChild(line); + await this._wait(delay); + } + + line.removeAttribute(`${this.pfx}-cursor`); + } + this.addRestart() + this.finishElement.style.visibility = 'hidden' + this.lineDelay = this.originalLineDelay + this.typeDelay = this.originalTypeDelay + this.startDelay = this.originalStartDelay + } + + generateRestart() { + const restart = document.createElement('a') + restart.onclick = (e) => { + e.preventDefault() + this.container.innerHTML = '' + this.init() + } + restart.href = '#' + restart.setAttribute('data-terminal-control', '') + restart.innerHTML = "restart ↻" + return restart + } + + generateFinish() { + const finish = document.createElement('a') + finish.onclick = (e) => { + e.preventDefault() + this.lineDelay = 0 + this.typeDelay = 0 + this.startDelay = 0 + } + finish.href = '#' + finish.setAttribute('data-terminal-control', '') + finish.innerHTML = "fast →" + this.finishElement = finish + return finish + } + + addRestart() { + const restart = this.generateRestart() + this.container.appendChild(restart) + } + + addFinish() { + const finish = this.generateFinish() + this.container.appendChild(finish) + } + + /** + * Animate a typed line. + * @param {Node} line - The line element to render. + */ + async type(line) { + const chars = [...line.textContent]; + line.textContent = ''; + this.container.appendChild(line); + + for (let char of chars) { + const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay; + await this._wait(delay); + line.textContent += char; + } + } + + /** + * Animate a progress bar. + * @param {Node} line - The line element to render. + */ + async progress(line) { + const progressLength = line.getAttribute(`${this.pfx}-progressLength`) + || this.progressLength; + const progressChar = line.getAttribute(`${this.pfx}-progressChar`) + || this.progressChar; + const chars = progressChar.repeat(progressLength); + const progressPercent = line.getAttribute(`${this.pfx}-progressPercent`) + || this.progressPercent; + line.textContent = ''; + this.container.appendChild(line); + + for (let i = 1; i < chars.length + 1; i++) { + await this._wait(this.typeDelay); + const percent = Math.round(i / chars.length * 100); + line.textContent = `${chars.slice(0, i)} ${percent}%`; + if (percent > progressPercent) { + break; + } + } + } + + /** + * Helper function for animation delays, called with `await`. + * @param {number} time - Timeout, in ms. + */ + _wait(time) { + return new Promise(resolve => setTimeout(resolve, time)); + } + + /** + * Converts line data objects into line elements. + * + * @param {Object[]} lineData - Dynamically loaded lines. + * @param {Object} line - Line data object. + * @returns {Element[]} - Array of line elements. + */ + lineDataToElements(lineData) { + return lineData.map(line => { + let div = document.createElement('div'); + div.innerHTML = `${line.value || ''}`; + + return div.firstElementChild; + }); + } + + /** + * Helper function for generating attributes string. + * + * @param {Object} line - Line data object. + * @returns {string} - String of attributes. + */ + _attributes(line) { + let attrs = ''; + for (let prop in line) { + // Custom add class + if (prop === 'class') { + attrs += ` class=${line[prop]} ` + continue + } + if (prop === 'type') { + attrs += `${this.pfx}="${line[prop]}" ` + } else if (prop !== 'value') { + attrs += `${this.pfx}-${prop}="${line[prop]}" ` + } + } + + return attrs; + } +} + +/** +* HTML API: If current script has container(s) specified, initialise Termynal. +*/ +if (document.currentScript.hasAttribute('data-termynal-container')) { + const containers = document.currentScript.getAttribute('data-termynal-container'); + containers.split('|') + .forEach(container => new Termynal(container)) +} diff --git a/basics/anchorpy-main/docs/testing/index.md b/basics/anchorpy-main/docs/testing/index.md new file mode 100644 index 0000000..8d516b5 --- /dev/null +++ b/basics/anchorpy-main/docs/testing/index.md @@ -0,0 +1,202 @@ +# Testing with AnchorPy + +## Approaches + +There are two ways to test Anchor programs using AnchorPy: + +1. Using the AnchorPy Pytest plugin. +2. Using `anchor test` and modifying `Anchor.toml`. + +## 1. Pytest plugin + +AnchorPy provides a `workspace_fixture` function that creates a Pytest fixture. +This fixture runs `anchor localnet` in the project root and shuts down the localnet +when the tests are done. + +With this approach you're just running regular Pytest tests. +This lets you do some things that you can't do with `anchor test`, +like integrating closely with your IDE or opening a debugger when a test fails (`pytest --pdb`). + +Here's how it looks with the `basic-1` tests: + +```python +from pytest import fixture, mark +from solders.keypair import Keypair +from solders.system_program import ID as SYS_PROGRAM_ID + +from anchorpy import Context, Program, workspace_fixture, WorkspaceType + +workspace = workspace_fixture("anchor/examples/tutorial/basic-1") + +# Since our other fixtures have module scope, we need to define +# this event_loop fixture and give it module scope otherwise +# pytest-asyncio will break. + +@fixture(scope="module") +def event_loop(): + """Create an instance of the default event loop for each test case.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + """Create a Program instance.""" + return workspace["basic_1"] + + +@fixture(scope="module") +async def initialized_account(program: Program) -> Keypair: + """Generate a keypair and initialize it.""" + my_account = Keypair() + await program.rpc["initialize"]( + 1234, + ctx=Context( + accounts={ + "my_account": my_account.pubkey(), + "user": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[my_account], + ), + ) + return my_account + + +@mark.asyncio +async def test_create_and_initialize_account( + program: Program, + initialized_account: Keypair, +) -> None: + """Test creating and initializing account in single tx.""" + account = await program.account["MyAccount"].fetch(initialized_account.pubkey()) + assert account.data == 1234 + + +@mark.asyncio +async def test_update_previously_created_account( + initialized_account: Keypair, + program: Program, +) -> None: + """Test updating a previously created account.""" + await program.rpc["update"]( + 4321, + ctx=Context(accounts={"my_account": initialized_account.pubkey()}), + ) + account = await program.account["MyAccount"].fetch(initialized_account.pubkey()) + assert account.data == 4321 + +``` + +You can just run these tests with `pytest` (or have your IDE run them). +!!! note + There is also a lower-level `localnet_fixture` function that sets up a localnet for a + particular project but doesn't return a workspace. + +## 2. Anchor test + + +Anchor lets you run whatever tests you want using the `[scripts]` section of `Anchor.toml`. +This means we can call Pytest inside the `anchor test` workflow. This is more limited +than the Pytest plugin but is more like the standard Anchor way of doing things. + +Here's how the `basic-1` tests look using `anchor test` and Pytest (but not the ): + +```python +# test_basic_1.py +import asyncio +from pathlib import Path +from pytest import fixture, mark +from anchorpy import create_workspace, close_workspace, Context, Program +from solders.keypair import Keypair +from solders.system_program import ID as SYS_PROGRAM_ID + + +# Since our other fixtures have module scope, we need to define +# this event_loop fixture and give it module scope otherwise +# pytest-asyncio will break. + +@fixture(scope="module") +def event_loop(): + """Create an instance of the default event loop for each test case.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + +@fixture(scope="module") +async def program() -> Program: + workspace = create_workspace() + yield workspace["basic_1"] + await close_workspace(workspace) + + +@fixture(scope="module") +async def initialized_account(program: Program) -> Keypair: + my_account = Keypair() + await program.rpc["initialize"]( + 1234, + ctx=Context( + accounts={ + "my_account": my_account.pubkey(), + "user": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[my_account], + ), + ) + return my_account + + +@mark.asyncio +async def test_create_and_initialize_account( + program: Program, initialized_account: Keypair +) -> None: + """Test creating and initializing account in single tx.""" + account = await program.account["MyAccount"].fetch(initialized_account.pubkey()) + assert account.data == 1234 + + +@mark.asyncio +async def test_update_previously_created_account( + initialized_account: Keypair, program: Program +) -> None: + """Test updating a previously created account.""" + await program.rpc["update"]( + 4321, ctx=Context(accounts={"myAccount": initialized_account.pubkey()}) + ) + account = await program.account["MyAccount"].fetch(initialized_account.pubkey()) + assert account.data == 4321 + +``` + +Just paste this code into a file called `test_basic_1.py` +in `anchor/examples/tutorial/basic-1/tests/`, and change the `scripts` section of `Anchor.toml` +to look like this: + +```toml +[scripts] +test = "pytest" + +``` + +Then run `anchor test` and voila!. + +!!! note + You must have `pytest-asyncio` installed for `test_basic_1.py` to work. + +## Bankrun Integration + +AnchorPy comes with a `bankrun_fixture` to help use +[`solders.bankrun`](https://kevinheavey.github.io/solders/examples/bankrun.html) in tests. + +If you haven't heard, `bankrun` is a much faster and more convenient alternative to +`solana-test-validator`. Long test suites are about 40 times faster with `bankrun`, +and for short test suites the difference is even bigger because `bankrun` has neglible +startup time. + +`bankrun_fixture` calls `bankrun.start()` and deploys all the programs in the current +Anchor workspace to the test envioronment. +Check out [this example](https://github.com/kevinheavey/anchorpy/blob/main/tests/test_basic_3_bankrun.py). + diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/__init__.py b/basics/anchorpy-main/examples/client-gen/basic_2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/accounts/__init__.py b/basics/anchorpy-main/examples/client-gen/basic_2/accounts/__init__.py new file mode 100644 index 0000000..4917931 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/accounts/__init__.py @@ -0,0 +1 @@ +from .counter import Counter, CounterJSON diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/accounts/counter.py b/basics/anchorpy-main/examples/client-gen/basic_2/accounts/counter.py new file mode 100644 index 0000000..c6712f4 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/accounts/counter.py @@ -0,0 +1,87 @@ +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from anchorpy.borsh_extension import BorshPubkey +from ..program_id import PROGRAM_ID + + +class CounterJSON(typing.TypedDict): + authority: str + count: int + + +@dataclass +class Counter: + discriminator: typing.ClassVar = b"\xff\xb0\x04\xf5\xbc\xfd|\x19" + layout: typing.ClassVar = borsh.CStruct( + "authority" / BorshPubkey, "count" / borsh.U64 + ) + authority: Pubkey + count: int + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["Counter"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["Counter"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["Counter"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "Counter": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = Counter.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + authority=dec.authority, + count=dec.count, + ) + + def to_json(self) -> CounterJSON: + return { + "authority": str(self.authority), + "count": self.count, + } + + @classmethod + def from_json(cls, obj: CounterJSON) -> "Counter": + return cls( + authority=Pubkey.from_string(obj["authority"]), + count=obj["count"], + ) diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/errors/__init__.py b/basics/anchorpy-main/examples/client-gen/basic_2/errors/__init__.py new file mode 100644 index 0000000..b453d3f --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/errors/__init__.py @@ -0,0 +1,26 @@ +import typing +import re +from solders.transaction_status import ( + InstructionErrorCustom, + TransactionErrorInstructionError, +) +from solana.rpc.core import RPCException +from solders.rpc.errors import SendTransactionPreflightFailureMessage +from anchorpy.error import extract_code_and_logs +from ..program_id import PROGRAM_ID +from . import anchor + + +def from_code(code: int) -> typing.Optional[anchor.AnchorError]: + return anchor.from_code(code) + + +error_re = re.compile(r"Program (\w+) failed: custom program error: (\w+)") + + +def from_tx_error(error: RPCException) -> typing.Optional[anchor.AnchorError]: + err_info = error.args[0] + extracted = extract_code_and_logs(err_info, PROGRAM_ID) + if extracted is None: + return None + return from_code(extracted[0]) diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/errors/anchor.py b/basics/anchorpy-main/examples/client-gen/basic_2/errors/anchor.py new file mode 100644 index 0000000..3f266ef --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/errors/anchor.py @@ -0,0 +1,590 @@ +import typing +from anchorpy.error import ProgramError + + +class InstructionMissing(ProgramError): + def __init__(self): + super().__init__(100, "8 byte instruction identifier not provided") + + code = 100 + name = "InstructionMissing" + msg = "8 byte instruction identifier not provided" + + +class InstructionFallbackNotFound(ProgramError): + def __init__(self): + super().__init__(101, "Fallback functions are not supported") + + code = 101 + name = "InstructionFallbackNotFound" + msg = "Fallback functions are not supported" + + +class InstructionDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(102, "The program could not deserialize the given instruction") + + code = 102 + name = "InstructionDidNotDeserialize" + msg = "The program could not deserialize the given instruction" + + +class InstructionDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(103, "The program could not serialize the given instruction") + + code = 103 + name = "InstructionDidNotSerialize" + msg = "The program could not serialize the given instruction" + + +class IdlInstructionStub(ProgramError): + def __init__(self): + super().__init__(1000, "The program was compiled without idl instructions") + + code = 1000 + name = "IdlInstructionStub" + msg = "The program was compiled without idl instructions" + + +class IdlInstructionInvalidProgram(ProgramError): + def __init__(self): + super().__init__( + 1001, "The transaction was given an invalid program for the IDL instruction" + ) + + code = 1001 + name = "IdlInstructionInvalidProgram" + msg = "The transaction was given an invalid program for the IDL instruction" + + +class ConstraintMut(ProgramError): + def __init__(self): + super().__init__(2000, "A mut constraint was violated") + + code = 2000 + name = "ConstraintMut" + msg = "A mut constraint was violated" + + +class ConstraintHasOne(ProgramError): + def __init__(self): + super().__init__(2001, "A has_one constraint was violated") + + code = 2001 + name = "ConstraintHasOne" + msg = "A has_one constraint was violated" + + +class ConstraintSigner(ProgramError): + def __init__(self): + super().__init__(2002, "A signer constraint was violated") + + code = 2002 + name = "ConstraintSigner" + msg = "A signer constraint was violated" + + +class ConstraintRaw(ProgramError): + def __init__(self): + super().__init__(2003, "A raw constraint was violated") + + code = 2003 + name = "ConstraintRaw" + msg = "A raw constraint was violated" + + +class ConstraintOwner(ProgramError): + def __init__(self): + super().__init__(2004, "An owner constraint was violated") + + code = 2004 + name = "ConstraintOwner" + msg = "An owner constraint was violated" + + +class ConstraintRentExempt(ProgramError): + def __init__(self): + super().__init__(2005, "A rent exempt constraint was violated") + + code = 2005 + name = "ConstraintRentExempt" + msg = "A rent exempt constraint was violated" + + +class ConstraintSeeds(ProgramError): + def __init__(self): + super().__init__(2006, "A seeds constraint was violated") + + code = 2006 + name = "ConstraintSeeds" + msg = "A seeds constraint was violated" + + +class ConstraintExecutable(ProgramError): + def __init__(self): + super().__init__(2007, "An executable constraint was violated") + + code = 2007 + name = "ConstraintExecutable" + msg = "An executable constraint was violated" + + +class ConstraintState(ProgramError): + def __init__(self): + super().__init__(2008, "A state constraint was violated") + + code = 2008 + name = "ConstraintState" + msg = "A state constraint was violated" + + +class ConstraintAssociated(ProgramError): + def __init__(self): + super().__init__(2009, "An associated constraint was violated") + + code = 2009 + name = "ConstraintAssociated" + msg = "An associated constraint was violated" + + +class ConstraintAssociatedInit(ProgramError): + def __init__(self): + super().__init__(2010, "An associated init constraint was violated") + + code = 2010 + name = "ConstraintAssociatedInit" + msg = "An associated init constraint was violated" + + +class ConstraintClose(ProgramError): + def __init__(self): + super().__init__(2011, "A close constraint was violated") + + code = 2011 + name = "ConstraintClose" + msg = "A close constraint was violated" + + +class ConstraintAddress(ProgramError): + def __init__(self): + super().__init__(2012, "An address constraint was violated") + + code = 2012 + name = "ConstraintAddress" + msg = "An address constraint was violated" + + +class ConstraintZero(ProgramError): + def __init__(self): + super().__init__(2013, "Expected zero account discriminant") + + code = 2013 + name = "ConstraintZero" + msg = "Expected zero account discriminant" + + +class ConstraintTokenMint(ProgramError): + def __init__(self): + super().__init__(2014, "A token mint constraint was violated") + + code = 2014 + name = "ConstraintTokenMint" + msg = "A token mint constraint was violated" + + +class ConstraintTokenOwner(ProgramError): + def __init__(self): + super().__init__(2015, "A token owner constraint was violated") + + code = 2015 + name = "ConstraintTokenOwner" + msg = "A token owner constraint was violated" + + +class ConstraintMintMintAuthority(ProgramError): + def __init__(self): + super().__init__(2016, "A mint mint authority constraint was violated") + + code = 2016 + name = "ConstraintMintMintAuthority" + msg = "A mint mint authority constraint was violated" + + +class ConstraintMintFreezeAuthority(ProgramError): + def __init__(self): + super().__init__(2017, "A mint freeze authority constraint was violated") + + code = 2017 + name = "ConstraintMintFreezeAuthority" + msg = "A mint freeze authority constraint was violated" + + +class ConstraintMintDecimals(ProgramError): + def __init__(self): + super().__init__(2018, "A mint decimals constraint was violated") + + code = 2018 + name = "ConstraintMintDecimals" + msg = "A mint decimals constraint was violated" + + +class ConstraintSpace(ProgramError): + def __init__(self): + super().__init__(2019, "A space constraint was violated") + + code = 2019 + name = "ConstraintSpace" + msg = "A space constraint was violated" + + +class RequireViolated(ProgramError): + def __init__(self): + super().__init__(2500, "A require expression was violated") + + code = 2500 + name = "RequireViolated" + msg = "A require expression was violated" + + +class RequireEqViolated(ProgramError): + def __init__(self): + super().__init__(2501, "A require_eq expression was violated") + + code = 2501 + name = "RequireEqViolated" + msg = "A require_eq expression was violated" + + +class RequireKeysEqViolated(ProgramError): + def __init__(self): + super().__init__(2502, "A require_keys_eq expression was violated") + + code = 2502 + name = "RequireKeysEqViolated" + msg = "A require_keys_eq expression was violated" + + +class RequireNeqViolated(ProgramError): + def __init__(self): + super().__init__(2503, "A require_neq expression was violated") + + code = 2503 + name = "RequireNeqViolated" + msg = "A require_neq expression was violated" + + +class RequireKeysNeqViolated(ProgramError): + def __init__(self): + super().__init__(2504, "A require_keys_neq expression was violated") + + code = 2504 + name = "RequireKeysNeqViolated" + msg = "A require_keys_neq expression was violated" + + +class RequireGtViolated(ProgramError): + def __init__(self): + super().__init__(2505, "A require_gt expression was violated") + + code = 2505 + name = "RequireGtViolated" + msg = "A require_gt expression was violated" + + +class RequireGteViolated(ProgramError): + def __init__(self): + super().__init__(2506, "A require_gte expression was violated") + + code = 2506 + name = "RequireGteViolated" + msg = "A require_gte expression was violated" + + +class AccountDiscriminatorAlreadySet(ProgramError): + def __init__(self): + super().__init__( + 3000, "The account discriminator was already set on this account" + ) + + code = 3000 + name = "AccountDiscriminatorAlreadySet" + msg = "The account discriminator was already set on this account" + + +class AccountDiscriminatorNotFound(ProgramError): + def __init__(self): + super().__init__(3001, "No 8 byte discriminator was found on the account") + + code = 3001 + name = "AccountDiscriminatorNotFound" + msg = "No 8 byte discriminator was found on the account" + + +class AccountDiscriminatorMismatch(ProgramError): + def __init__(self): + super().__init__(3002, "8 byte discriminator did not match what was expected") + + code = 3002 + name = "AccountDiscriminatorMismatch" + msg = "8 byte discriminator did not match what was expected" + + +class AccountDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(3003, "Failed to deserialize the account") + + code = 3003 + name = "AccountDidNotDeserialize" + msg = "Failed to deserialize the account" + + +class AccountDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(3004, "Failed to serialize the account") + + code = 3004 + name = "AccountDidNotSerialize" + msg = "Failed to serialize the account" + + +class AccountNotEnoughKeys(ProgramError): + def __init__(self): + super().__init__(3005, "Not enough account keys given to the instruction") + + code = 3005 + name = "AccountNotEnoughKeys" + msg = "Not enough account keys given to the instruction" + + +class AccountNotMutable(ProgramError): + def __init__(self): + super().__init__(3006, "The given account is not mutable") + + code = 3006 + name = "AccountNotMutable" + msg = "The given account is not mutable" + + +class AccountOwnedByWrongProgram(ProgramError): + def __init__(self): + super().__init__( + 3007, "The given account is owned by a different program than expected" + ) + + code = 3007 + name = "AccountOwnedByWrongProgram" + msg = "The given account is owned by a different program than expected" + + +class InvalidProgramId(ProgramError): + def __init__(self): + super().__init__(3008, "Program ID was not as expected") + + code = 3008 + name = "InvalidProgramId" + msg = "Program ID was not as expected" + + +class InvalidProgramExecutable(ProgramError): + def __init__(self): + super().__init__(3009, "Program account is not executable") + + code = 3009 + name = "InvalidProgramExecutable" + msg = "Program account is not executable" + + +class AccountNotSigner(ProgramError): + def __init__(self): + super().__init__(3010, "The given account did not sign") + + code = 3010 + name = "AccountNotSigner" + msg = "The given account did not sign" + + +class AccountNotSystemOwned(ProgramError): + def __init__(self): + super().__init__(3011, "The given account is not owned by the system program") + + code = 3011 + name = "AccountNotSystemOwned" + msg = "The given account is not owned by the system program" + + +class AccountNotInitialized(ProgramError): + def __init__(self): + super().__init__( + 3012, "The program expected this account to be already initialized" + ) + + code = 3012 + name = "AccountNotInitialized" + msg = "The program expected this account to be already initialized" + + +class AccountNotProgramData(ProgramError): + def __init__(self): + super().__init__(3013, "The given account is not a program data account") + + code = 3013 + name = "AccountNotProgramData" + msg = "The given account is not a program data account" + + +class AccountNotAssociatedTokenAccount(ProgramError): + def __init__(self): + super().__init__(3014, "The given account is not the associated token account") + + code = 3014 + name = "AccountNotAssociatedTokenAccount" + msg = "The given account is not the associated token account" + + +class AccountSysvarMismatch(ProgramError): + def __init__(self): + super().__init__( + 3015, "The given public key does not match the required sysvar" + ) + + code = 3015 + name = "AccountSysvarMismatch" + msg = "The given public key does not match the required sysvar" + + +class StateInvalidAddress(ProgramError): + def __init__(self): + super().__init__( + 4000, "The given state account does not have the correct address" + ) + + code = 4000 + name = "StateInvalidAddress" + msg = "The given state account does not have the correct address" + + +class Deprecated(ProgramError): + def __init__(self): + super().__init__( + 5000, "The API being used is deprecated and should no longer be used" + ) + + code = 5000 + name = "Deprecated" + msg = "The API being used is deprecated and should no longer be used" + + +AnchorError = typing.Union[ + InstructionMissing, + InstructionFallbackNotFound, + InstructionDidNotDeserialize, + InstructionDidNotSerialize, + IdlInstructionStub, + IdlInstructionInvalidProgram, + ConstraintMut, + ConstraintHasOne, + ConstraintSigner, + ConstraintRaw, + ConstraintOwner, + ConstraintRentExempt, + ConstraintSeeds, + ConstraintExecutable, + ConstraintState, + ConstraintAssociated, + ConstraintAssociatedInit, + ConstraintClose, + ConstraintAddress, + ConstraintZero, + ConstraintTokenMint, + ConstraintTokenOwner, + ConstraintMintMintAuthority, + ConstraintMintFreezeAuthority, + ConstraintMintDecimals, + ConstraintSpace, + RequireViolated, + RequireEqViolated, + RequireKeysEqViolated, + RequireNeqViolated, + RequireKeysNeqViolated, + RequireGtViolated, + RequireGteViolated, + AccountDiscriminatorAlreadySet, + AccountDiscriminatorNotFound, + AccountDiscriminatorMismatch, + AccountDidNotDeserialize, + AccountDidNotSerialize, + AccountNotEnoughKeys, + AccountNotMutable, + AccountOwnedByWrongProgram, + InvalidProgramId, + InvalidProgramExecutable, + AccountNotSigner, + AccountNotSystemOwned, + AccountNotInitialized, + AccountNotProgramData, + AccountNotAssociatedTokenAccount, + AccountSysvarMismatch, + StateInvalidAddress, + Deprecated, +] +ANCHOR_ERROR_MAP: dict[int, AnchorError] = { + 100: InstructionMissing(), + 101: InstructionFallbackNotFound(), + 102: InstructionDidNotDeserialize(), + 103: InstructionDidNotSerialize(), + 1000: IdlInstructionStub(), + 1001: IdlInstructionInvalidProgram(), + 2000: ConstraintMut(), + 2001: ConstraintHasOne(), + 2002: ConstraintSigner(), + 2003: ConstraintRaw(), + 2004: ConstraintOwner(), + 2005: ConstraintRentExempt(), + 2006: ConstraintSeeds(), + 2007: ConstraintExecutable(), + 2008: ConstraintState(), + 2009: ConstraintAssociated(), + 2010: ConstraintAssociatedInit(), + 2011: ConstraintClose(), + 2012: ConstraintAddress(), + 2013: ConstraintZero(), + 2014: ConstraintTokenMint(), + 2015: ConstraintTokenOwner(), + 2016: ConstraintMintMintAuthority(), + 2017: ConstraintMintFreezeAuthority(), + 2018: ConstraintMintDecimals(), + 2019: ConstraintSpace(), + 2500: RequireViolated(), + 2501: RequireEqViolated(), + 2502: RequireKeysEqViolated(), + 2503: RequireNeqViolated(), + 2504: RequireKeysNeqViolated(), + 2505: RequireGtViolated(), + 2506: RequireGteViolated(), + 3000: AccountDiscriminatorAlreadySet(), + 3001: AccountDiscriminatorNotFound(), + 3002: AccountDiscriminatorMismatch(), + 3003: AccountDidNotDeserialize(), + 3004: AccountDidNotSerialize(), + 3005: AccountNotEnoughKeys(), + 3006: AccountNotMutable(), + 3007: AccountOwnedByWrongProgram(), + 3008: InvalidProgramId(), + 3009: InvalidProgramExecutable(), + 3010: AccountNotSigner(), + 3011: AccountNotSystemOwned(), + 3012: AccountNotInitialized(), + 3013: AccountNotProgramData(), + 3014: AccountNotAssociatedTokenAccount(), + 3015: AccountSysvarMismatch(), + 4000: StateInvalidAddress(), + 5000: Deprecated(), +} + + +def from_code(code: int) -> typing.Optional[AnchorError]: + maybe_err = ANCHOR_ERROR_MAP.get(code) + if maybe_err is None: + return None + return maybe_err diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/instructions/__init__.py b/basics/anchorpy-main/examples/client-gen/basic_2/instructions/__init__.py new file mode 100644 index 0000000..5d579c6 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/instructions/__init__.py @@ -0,0 +1,2 @@ +from .create import create, CreateArgs, CreateAccounts +from .increment import increment, IncrementAccounts diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/instructions/create.py b/basics/anchorpy-main/examples/client-gen/basic_2/instructions/create.py new file mode 100644 index 0000000..ed2b3fc --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/instructions/create.py @@ -0,0 +1,41 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.sysvar import RENT +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class CreateArgs(typing.TypedDict): + authority: Pubkey + + +layout = borsh.CStruct("authority" / BorshPubkey) + + +class CreateAccounts(typing.TypedDict): + counter: Pubkey + + +def create( + args: CreateArgs, + accounts: CreateAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["counter"], is_signer=False, is_writable=True), + AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x18\x1e\xc8(\x05\x1c\x07w" + encoded_args = layout.build( + { + "authority": args["authority"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/instructions/increment.py b/basics/anchorpy-main/examples/client-gen/basic_2/instructions/increment.py new file mode 100644 index 0000000..4c5ea80 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/instructions/increment.py @@ -0,0 +1,27 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class IncrementAccounts(typing.TypedDict): + counter: Pubkey + authority: Pubkey + + +def increment( + accounts: IncrementAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["counter"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["authority"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x0b\x12h\th\xae;!" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/examples/client-gen/basic_2/program_id.py b/basics/anchorpy-main/examples/client-gen/basic_2/program_id.py new file mode 100644 index 0000000..649b93e --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/basic_2/program_id.py @@ -0,0 +1,3 @@ +from solders.pubkey import Pubkey + +PROGRAM_ID = Pubkey.from_string("3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8") diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/__init__.py b/basics/anchorpy-main/examples/client-gen/tictactoe/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/accounts/__init__.py b/basics/anchorpy-main/examples/client-gen/tictactoe/accounts/__init__.py new file mode 100644 index 0000000..fb255e9 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/accounts/__init__.py @@ -0,0 +1 @@ +from .game import Game, GameJSON diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/accounts/game.py b/basics/anchorpy-main/examples/client-gen/tictactoe/accounts/game.py new file mode 100644 index 0000000..3c26fb9 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/accounts/game.py @@ -0,0 +1,135 @@ +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from anchorpy.borsh_extension import BorshPubkey +from ..program_id import PROGRAM_ID +from .. import types + + +class GameJSON(typing.TypedDict): + players: list[str] + turn: int + board: list[list[typing.Optional[types.sign.SignJSON]]] + state: types.game_state.GameStateJSON + + +@dataclass +class Game: + discriminator: typing.ClassVar = b"\x1bZ\xa6}Jdy\x12" + layout: typing.ClassVar = borsh.CStruct( + "players" / BorshPubkey[2], + "turn" / borsh.U8, + "board" / borsh.Option(types.sign.layout)[3][3], + "state" / types.game_state.layout, + ) + players: list[Pubkey] + turn: int + board: list[list[typing.Optional[types.sign.SignKind]]] + state: types.game_state.GameStateKind + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["Game"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["Game"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["Game"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "Game": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = Game.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + players=dec.players, + turn=dec.turn, + board=list( + map( + lambda item: list( + map( + lambda item: ( + None if item is None else types.sign.from_decoded(item) + ), + item, + ) + ), + dec.board, + ) + ), + state=types.game_state.from_decoded(dec.state), + ) + + def to_json(self) -> GameJSON: + return { + "players": list(map(lambda item: str(item), self.players)), + "turn": self.turn, + "board": list( + map( + lambda item: list( + map( + lambda item: (None if item is None else item.to_json()), + item, + ) + ), + self.board, + ) + ), + "state": self.state.to_json(), + } + + @classmethod + def from_json(cls, obj: GameJSON) -> "Game": + return cls( + players=list(map(lambda item: Pubkey.from_string(item), obj["players"])), + turn=obj["turn"], + board=list( + map( + lambda item: list( + map( + lambda item: ( + None if item is None else types.sign.from_json(item) + ), + item, + ) + ), + obj["board"], + ) + ), + state=types.game_state.from_json(obj["state"]), + ) diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/errors/__init__.py b/basics/anchorpy-main/examples/client-gen/tictactoe/errors/__init__.py new file mode 100644 index 0000000..421993d --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/errors/__init__.py @@ -0,0 +1,29 @@ +import typing +import re +from solders.transaction_status import ( + InstructionErrorCustom, + TransactionErrorInstructionError, +) +from solana.rpc.core import RPCException +from solders.rpc.errors import SendTransactionPreflightFailureMessage +from anchorpy.error import extract_code_and_logs +from ..program_id import PROGRAM_ID +from . import anchor +from . import custom + + +def from_code(code: int) -> typing.Union[custom.CustomError, anchor.AnchorError, None]: + return custom.from_code(code) if code >= 6000 else anchor.from_code(code) + + +error_re = re.compile(r"Program (\w+) failed: custom program error: (\w+)") + + +def from_tx_error( + error: RPCException, +) -> typing.Union[anchor.AnchorError, custom.CustomError, None]: + err_info = error.args[0] + extracted = extract_code_and_logs(err_info, PROGRAM_ID) + if extracted is None: + return None + return from_code(extracted[0]) diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/errors/anchor.py b/basics/anchorpy-main/examples/client-gen/tictactoe/errors/anchor.py new file mode 100644 index 0000000..3f266ef --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/errors/anchor.py @@ -0,0 +1,590 @@ +import typing +from anchorpy.error import ProgramError + + +class InstructionMissing(ProgramError): + def __init__(self): + super().__init__(100, "8 byte instruction identifier not provided") + + code = 100 + name = "InstructionMissing" + msg = "8 byte instruction identifier not provided" + + +class InstructionFallbackNotFound(ProgramError): + def __init__(self): + super().__init__(101, "Fallback functions are not supported") + + code = 101 + name = "InstructionFallbackNotFound" + msg = "Fallback functions are not supported" + + +class InstructionDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(102, "The program could not deserialize the given instruction") + + code = 102 + name = "InstructionDidNotDeserialize" + msg = "The program could not deserialize the given instruction" + + +class InstructionDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(103, "The program could not serialize the given instruction") + + code = 103 + name = "InstructionDidNotSerialize" + msg = "The program could not serialize the given instruction" + + +class IdlInstructionStub(ProgramError): + def __init__(self): + super().__init__(1000, "The program was compiled without idl instructions") + + code = 1000 + name = "IdlInstructionStub" + msg = "The program was compiled without idl instructions" + + +class IdlInstructionInvalidProgram(ProgramError): + def __init__(self): + super().__init__( + 1001, "The transaction was given an invalid program for the IDL instruction" + ) + + code = 1001 + name = "IdlInstructionInvalidProgram" + msg = "The transaction was given an invalid program for the IDL instruction" + + +class ConstraintMut(ProgramError): + def __init__(self): + super().__init__(2000, "A mut constraint was violated") + + code = 2000 + name = "ConstraintMut" + msg = "A mut constraint was violated" + + +class ConstraintHasOne(ProgramError): + def __init__(self): + super().__init__(2001, "A has_one constraint was violated") + + code = 2001 + name = "ConstraintHasOne" + msg = "A has_one constraint was violated" + + +class ConstraintSigner(ProgramError): + def __init__(self): + super().__init__(2002, "A signer constraint was violated") + + code = 2002 + name = "ConstraintSigner" + msg = "A signer constraint was violated" + + +class ConstraintRaw(ProgramError): + def __init__(self): + super().__init__(2003, "A raw constraint was violated") + + code = 2003 + name = "ConstraintRaw" + msg = "A raw constraint was violated" + + +class ConstraintOwner(ProgramError): + def __init__(self): + super().__init__(2004, "An owner constraint was violated") + + code = 2004 + name = "ConstraintOwner" + msg = "An owner constraint was violated" + + +class ConstraintRentExempt(ProgramError): + def __init__(self): + super().__init__(2005, "A rent exempt constraint was violated") + + code = 2005 + name = "ConstraintRentExempt" + msg = "A rent exempt constraint was violated" + + +class ConstraintSeeds(ProgramError): + def __init__(self): + super().__init__(2006, "A seeds constraint was violated") + + code = 2006 + name = "ConstraintSeeds" + msg = "A seeds constraint was violated" + + +class ConstraintExecutable(ProgramError): + def __init__(self): + super().__init__(2007, "An executable constraint was violated") + + code = 2007 + name = "ConstraintExecutable" + msg = "An executable constraint was violated" + + +class ConstraintState(ProgramError): + def __init__(self): + super().__init__(2008, "A state constraint was violated") + + code = 2008 + name = "ConstraintState" + msg = "A state constraint was violated" + + +class ConstraintAssociated(ProgramError): + def __init__(self): + super().__init__(2009, "An associated constraint was violated") + + code = 2009 + name = "ConstraintAssociated" + msg = "An associated constraint was violated" + + +class ConstraintAssociatedInit(ProgramError): + def __init__(self): + super().__init__(2010, "An associated init constraint was violated") + + code = 2010 + name = "ConstraintAssociatedInit" + msg = "An associated init constraint was violated" + + +class ConstraintClose(ProgramError): + def __init__(self): + super().__init__(2011, "A close constraint was violated") + + code = 2011 + name = "ConstraintClose" + msg = "A close constraint was violated" + + +class ConstraintAddress(ProgramError): + def __init__(self): + super().__init__(2012, "An address constraint was violated") + + code = 2012 + name = "ConstraintAddress" + msg = "An address constraint was violated" + + +class ConstraintZero(ProgramError): + def __init__(self): + super().__init__(2013, "Expected zero account discriminant") + + code = 2013 + name = "ConstraintZero" + msg = "Expected zero account discriminant" + + +class ConstraintTokenMint(ProgramError): + def __init__(self): + super().__init__(2014, "A token mint constraint was violated") + + code = 2014 + name = "ConstraintTokenMint" + msg = "A token mint constraint was violated" + + +class ConstraintTokenOwner(ProgramError): + def __init__(self): + super().__init__(2015, "A token owner constraint was violated") + + code = 2015 + name = "ConstraintTokenOwner" + msg = "A token owner constraint was violated" + + +class ConstraintMintMintAuthority(ProgramError): + def __init__(self): + super().__init__(2016, "A mint mint authority constraint was violated") + + code = 2016 + name = "ConstraintMintMintAuthority" + msg = "A mint mint authority constraint was violated" + + +class ConstraintMintFreezeAuthority(ProgramError): + def __init__(self): + super().__init__(2017, "A mint freeze authority constraint was violated") + + code = 2017 + name = "ConstraintMintFreezeAuthority" + msg = "A mint freeze authority constraint was violated" + + +class ConstraintMintDecimals(ProgramError): + def __init__(self): + super().__init__(2018, "A mint decimals constraint was violated") + + code = 2018 + name = "ConstraintMintDecimals" + msg = "A mint decimals constraint was violated" + + +class ConstraintSpace(ProgramError): + def __init__(self): + super().__init__(2019, "A space constraint was violated") + + code = 2019 + name = "ConstraintSpace" + msg = "A space constraint was violated" + + +class RequireViolated(ProgramError): + def __init__(self): + super().__init__(2500, "A require expression was violated") + + code = 2500 + name = "RequireViolated" + msg = "A require expression was violated" + + +class RequireEqViolated(ProgramError): + def __init__(self): + super().__init__(2501, "A require_eq expression was violated") + + code = 2501 + name = "RequireEqViolated" + msg = "A require_eq expression was violated" + + +class RequireKeysEqViolated(ProgramError): + def __init__(self): + super().__init__(2502, "A require_keys_eq expression was violated") + + code = 2502 + name = "RequireKeysEqViolated" + msg = "A require_keys_eq expression was violated" + + +class RequireNeqViolated(ProgramError): + def __init__(self): + super().__init__(2503, "A require_neq expression was violated") + + code = 2503 + name = "RequireNeqViolated" + msg = "A require_neq expression was violated" + + +class RequireKeysNeqViolated(ProgramError): + def __init__(self): + super().__init__(2504, "A require_keys_neq expression was violated") + + code = 2504 + name = "RequireKeysNeqViolated" + msg = "A require_keys_neq expression was violated" + + +class RequireGtViolated(ProgramError): + def __init__(self): + super().__init__(2505, "A require_gt expression was violated") + + code = 2505 + name = "RequireGtViolated" + msg = "A require_gt expression was violated" + + +class RequireGteViolated(ProgramError): + def __init__(self): + super().__init__(2506, "A require_gte expression was violated") + + code = 2506 + name = "RequireGteViolated" + msg = "A require_gte expression was violated" + + +class AccountDiscriminatorAlreadySet(ProgramError): + def __init__(self): + super().__init__( + 3000, "The account discriminator was already set on this account" + ) + + code = 3000 + name = "AccountDiscriminatorAlreadySet" + msg = "The account discriminator was already set on this account" + + +class AccountDiscriminatorNotFound(ProgramError): + def __init__(self): + super().__init__(3001, "No 8 byte discriminator was found on the account") + + code = 3001 + name = "AccountDiscriminatorNotFound" + msg = "No 8 byte discriminator was found on the account" + + +class AccountDiscriminatorMismatch(ProgramError): + def __init__(self): + super().__init__(3002, "8 byte discriminator did not match what was expected") + + code = 3002 + name = "AccountDiscriminatorMismatch" + msg = "8 byte discriminator did not match what was expected" + + +class AccountDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(3003, "Failed to deserialize the account") + + code = 3003 + name = "AccountDidNotDeserialize" + msg = "Failed to deserialize the account" + + +class AccountDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(3004, "Failed to serialize the account") + + code = 3004 + name = "AccountDidNotSerialize" + msg = "Failed to serialize the account" + + +class AccountNotEnoughKeys(ProgramError): + def __init__(self): + super().__init__(3005, "Not enough account keys given to the instruction") + + code = 3005 + name = "AccountNotEnoughKeys" + msg = "Not enough account keys given to the instruction" + + +class AccountNotMutable(ProgramError): + def __init__(self): + super().__init__(3006, "The given account is not mutable") + + code = 3006 + name = "AccountNotMutable" + msg = "The given account is not mutable" + + +class AccountOwnedByWrongProgram(ProgramError): + def __init__(self): + super().__init__( + 3007, "The given account is owned by a different program than expected" + ) + + code = 3007 + name = "AccountOwnedByWrongProgram" + msg = "The given account is owned by a different program than expected" + + +class InvalidProgramId(ProgramError): + def __init__(self): + super().__init__(3008, "Program ID was not as expected") + + code = 3008 + name = "InvalidProgramId" + msg = "Program ID was not as expected" + + +class InvalidProgramExecutable(ProgramError): + def __init__(self): + super().__init__(3009, "Program account is not executable") + + code = 3009 + name = "InvalidProgramExecutable" + msg = "Program account is not executable" + + +class AccountNotSigner(ProgramError): + def __init__(self): + super().__init__(3010, "The given account did not sign") + + code = 3010 + name = "AccountNotSigner" + msg = "The given account did not sign" + + +class AccountNotSystemOwned(ProgramError): + def __init__(self): + super().__init__(3011, "The given account is not owned by the system program") + + code = 3011 + name = "AccountNotSystemOwned" + msg = "The given account is not owned by the system program" + + +class AccountNotInitialized(ProgramError): + def __init__(self): + super().__init__( + 3012, "The program expected this account to be already initialized" + ) + + code = 3012 + name = "AccountNotInitialized" + msg = "The program expected this account to be already initialized" + + +class AccountNotProgramData(ProgramError): + def __init__(self): + super().__init__(3013, "The given account is not a program data account") + + code = 3013 + name = "AccountNotProgramData" + msg = "The given account is not a program data account" + + +class AccountNotAssociatedTokenAccount(ProgramError): + def __init__(self): + super().__init__(3014, "The given account is not the associated token account") + + code = 3014 + name = "AccountNotAssociatedTokenAccount" + msg = "The given account is not the associated token account" + + +class AccountSysvarMismatch(ProgramError): + def __init__(self): + super().__init__( + 3015, "The given public key does not match the required sysvar" + ) + + code = 3015 + name = "AccountSysvarMismatch" + msg = "The given public key does not match the required sysvar" + + +class StateInvalidAddress(ProgramError): + def __init__(self): + super().__init__( + 4000, "The given state account does not have the correct address" + ) + + code = 4000 + name = "StateInvalidAddress" + msg = "The given state account does not have the correct address" + + +class Deprecated(ProgramError): + def __init__(self): + super().__init__( + 5000, "The API being used is deprecated and should no longer be used" + ) + + code = 5000 + name = "Deprecated" + msg = "The API being used is deprecated and should no longer be used" + + +AnchorError = typing.Union[ + InstructionMissing, + InstructionFallbackNotFound, + InstructionDidNotDeserialize, + InstructionDidNotSerialize, + IdlInstructionStub, + IdlInstructionInvalidProgram, + ConstraintMut, + ConstraintHasOne, + ConstraintSigner, + ConstraintRaw, + ConstraintOwner, + ConstraintRentExempt, + ConstraintSeeds, + ConstraintExecutable, + ConstraintState, + ConstraintAssociated, + ConstraintAssociatedInit, + ConstraintClose, + ConstraintAddress, + ConstraintZero, + ConstraintTokenMint, + ConstraintTokenOwner, + ConstraintMintMintAuthority, + ConstraintMintFreezeAuthority, + ConstraintMintDecimals, + ConstraintSpace, + RequireViolated, + RequireEqViolated, + RequireKeysEqViolated, + RequireNeqViolated, + RequireKeysNeqViolated, + RequireGtViolated, + RequireGteViolated, + AccountDiscriminatorAlreadySet, + AccountDiscriminatorNotFound, + AccountDiscriminatorMismatch, + AccountDidNotDeserialize, + AccountDidNotSerialize, + AccountNotEnoughKeys, + AccountNotMutable, + AccountOwnedByWrongProgram, + InvalidProgramId, + InvalidProgramExecutable, + AccountNotSigner, + AccountNotSystemOwned, + AccountNotInitialized, + AccountNotProgramData, + AccountNotAssociatedTokenAccount, + AccountSysvarMismatch, + StateInvalidAddress, + Deprecated, +] +ANCHOR_ERROR_MAP: dict[int, AnchorError] = { + 100: InstructionMissing(), + 101: InstructionFallbackNotFound(), + 102: InstructionDidNotDeserialize(), + 103: InstructionDidNotSerialize(), + 1000: IdlInstructionStub(), + 1001: IdlInstructionInvalidProgram(), + 2000: ConstraintMut(), + 2001: ConstraintHasOne(), + 2002: ConstraintSigner(), + 2003: ConstraintRaw(), + 2004: ConstraintOwner(), + 2005: ConstraintRentExempt(), + 2006: ConstraintSeeds(), + 2007: ConstraintExecutable(), + 2008: ConstraintState(), + 2009: ConstraintAssociated(), + 2010: ConstraintAssociatedInit(), + 2011: ConstraintClose(), + 2012: ConstraintAddress(), + 2013: ConstraintZero(), + 2014: ConstraintTokenMint(), + 2015: ConstraintTokenOwner(), + 2016: ConstraintMintMintAuthority(), + 2017: ConstraintMintFreezeAuthority(), + 2018: ConstraintMintDecimals(), + 2019: ConstraintSpace(), + 2500: RequireViolated(), + 2501: RequireEqViolated(), + 2502: RequireKeysEqViolated(), + 2503: RequireNeqViolated(), + 2504: RequireKeysNeqViolated(), + 2505: RequireGtViolated(), + 2506: RequireGteViolated(), + 3000: AccountDiscriminatorAlreadySet(), + 3001: AccountDiscriminatorNotFound(), + 3002: AccountDiscriminatorMismatch(), + 3003: AccountDidNotDeserialize(), + 3004: AccountDidNotSerialize(), + 3005: AccountNotEnoughKeys(), + 3006: AccountNotMutable(), + 3007: AccountOwnedByWrongProgram(), + 3008: InvalidProgramId(), + 3009: InvalidProgramExecutable(), + 3010: AccountNotSigner(), + 3011: AccountNotSystemOwned(), + 3012: AccountNotInitialized(), + 3013: AccountNotProgramData(), + 3014: AccountNotAssociatedTokenAccount(), + 3015: AccountSysvarMismatch(), + 4000: StateInvalidAddress(), + 5000: Deprecated(), +} + + +def from_code(code: int) -> typing.Optional[AnchorError]: + maybe_err = ANCHOR_ERROR_MAP.get(code) + if maybe_err is None: + return None + return maybe_err diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/errors/custom.py b/basics/anchorpy-main/examples/client-gen/tictactoe/errors/custom.py new file mode 100644 index 0000000..ea1923a --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/errors/custom.py @@ -0,0 +1,66 @@ +import typing +from anchorpy.error import ProgramError + + +class TileOutOfBounds(ProgramError): + def __init__(self) -> None: + super().__init__(6000, None) + + code = 6000 + name = "TileOutOfBounds" + msg = None + + +class TileAlreadySet(ProgramError): + def __init__(self) -> None: + super().__init__(6001, None) + + code = 6001 + name = "TileAlreadySet" + msg = None + + +class GameAlreadyOver(ProgramError): + def __init__(self) -> None: + super().__init__(6002, None) + + code = 6002 + name = "GameAlreadyOver" + msg = None + + +class NotPlayersTurn(ProgramError): + def __init__(self) -> None: + super().__init__(6003, None) + + code = 6003 + name = "NotPlayersTurn" + msg = None + + +class GameAlreadyStarted(ProgramError): + def __init__(self) -> None: + super().__init__(6004, None) + + code = 6004 + name = "GameAlreadyStarted" + msg = None + + +CustomError = typing.Union[ + TileOutOfBounds, TileAlreadySet, GameAlreadyOver, NotPlayersTurn, GameAlreadyStarted +] +CUSTOM_ERROR_MAP: dict[int, CustomError] = { + 6000: TileOutOfBounds(), + 6001: TileAlreadySet(), + 6002: GameAlreadyOver(), + 6003: NotPlayersTurn(), + 6004: GameAlreadyStarted(), +} + + +def from_code(code: int) -> typing.Optional[CustomError]: + maybe_err = CUSTOM_ERROR_MAP.get(code) + if maybe_err is None: + return None + return maybe_err diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/__init__.py b/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/__init__.py new file mode 100644 index 0000000..739e79e --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/__init__.py @@ -0,0 +1,2 @@ +from .setup_game import setup_game, SetupGameArgs, SetupGameAccounts +from .play import play, PlayArgs, PlayAccounts diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/play.py b/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/play.py new file mode 100644 index 0000000..ebd4f90 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/play.py @@ -0,0 +1,41 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from .. import types +from ..program_id import PROGRAM_ID + + +class PlayArgs(typing.TypedDict): + tile: types.tile.Tile + + +layout = borsh.CStruct("tile" / types.tile.Tile.layout) + + +class PlayAccounts(typing.TypedDict): + game: Pubkey + player: Pubkey + + +def play( + args: PlayArgs, + accounts: PlayAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["game"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["player"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xd5\x9d\xc1\x8e\xe48\xf8\x96" + encoded_args = layout.build( + { + "tile": args["tile"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/setup_game.py b/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/setup_game.py new file mode 100644 index 0000000..15aad50 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/instructions/setup_game.py @@ -0,0 +1,43 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class SetupGameArgs(typing.TypedDict): + player_two: Pubkey + + +layout = borsh.CStruct("player_two" / BorshPubkey) + + +class SetupGameAccounts(typing.TypedDict): + game: Pubkey + player_one: Pubkey + + +def setup_game( + args: SetupGameArgs, + accounts: SetupGameAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["game"], is_signer=True, is_writable=True), + AccountMeta(pubkey=accounts["player_one"], is_signer=True, is_writable=True), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xb4\xda\x80K:\xde#R" + encoded_args = layout.build( + { + "player_two": args["player_two"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/program_id.py b/basics/anchorpy-main/examples/client-gen/tictactoe/program_id.py new file mode 100644 index 0000000..649b93e --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/program_id.py @@ -0,0 +1,3 @@ +from solders.pubkey import Pubkey + +PROGRAM_ID = Pubkey.from_string("3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8") diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/types/__init__.py b/basics/anchorpy-main/examples/client-gen/tictactoe/types/__init__.py new file mode 100644 index 0000000..ee1a6a2 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/types/__init__.py @@ -0,0 +1,7 @@ +import typing +from . import tile +from .tile import Tile, TileJSON +from . import game_state +from .game_state import GameStateKind, GameStateJSON +from . import sign +from .sign import SignKind, SignJSON diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/types/game_state.py b/basics/anchorpy-main/examples/client-gen/tictactoe/types/game_state.py new file mode 100644 index 0000000..09643ca --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/types/game_state.py @@ -0,0 +1,129 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from anchorpy.borsh_extension import EnumForCodegen, BorshPubkey +import borsh_construct as borsh + + +class WonJSONValue(typing.TypedDict): + winner: str + + +class WonValue(typing.TypedDict): + winner: Pubkey + + +class ActiveJSON(typing.TypedDict): + kind: typing.Literal["Active"] + + +class TieJSON(typing.TypedDict): + kind: typing.Literal["Tie"] + + +class WonJSON(typing.TypedDict): + value: WonJSONValue + kind: typing.Literal["Won"] + + +@dataclass +class Active: + discriminator: typing.ClassVar = 0 + kind: typing.ClassVar = "Active" + + @classmethod + def to_json(cls) -> ActiveJSON: + return ActiveJSON( + kind="Active", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "Active": {}, + } + + +@dataclass +class Tie: + discriminator: typing.ClassVar = 1 + kind: typing.ClassVar = "Tie" + + @classmethod + def to_json(cls) -> TieJSON: + return TieJSON( + kind="Tie", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "Tie": {}, + } + + +@dataclass +class Won: + discriminator: typing.ClassVar = 2 + kind: typing.ClassVar = "Won" + value: WonValue + + def to_json(self) -> WonJSON: + return WonJSON( + kind="Won", + value={ + "winner": str(self.value["winner"]), + }, + ) + + def to_encodable(self) -> dict: + return { + "Won": { + "winner": self.value["winner"], + }, + } + + +GameStateKind = typing.Union[Active, Tie, Won] +GameStateJSON = typing.Union[ActiveJSON, TieJSON, WonJSON] + + +def from_decoded(obj: dict) -> GameStateKind: + if not isinstance(obj, dict): + raise ValueError("Invalid enum object") + if "Active" in obj: + return Active() + if "Tie" in obj: + return Tie() + if "Won" in obj: + val = obj["Won"] + return Won( + WonValue( + winner=val["winner"], + ) + ) + raise ValueError("Invalid enum object") + + +def from_json(obj: GameStateJSON) -> GameStateKind: + if obj["kind"] == "Active": + return Active() + if obj["kind"] == "Tie": + return Tie() + if obj["kind"] == "Won": + won_json_value = typing.cast(WonJSONValue, obj["value"]) + return Won( + WonValue( + winner=Pubkey.from_string(won_json_value["winner"]), + ) + ) + kind = obj["kind"] + raise ValueError(f"Unrecognized enum kind: {kind}") + + +layout = EnumForCodegen( + "Active" / borsh.CStruct(), + "Tie" / borsh.CStruct(), + "Won" / borsh.CStruct("winner" / BorshPubkey), +) diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/types/sign.py b/basics/anchorpy-main/examples/client-gen/tictactoe/types/sign.py new file mode 100644 index 0000000..0577e31 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/types/sign.py @@ -0,0 +1,75 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from anchorpy.borsh_extension import EnumForCodegen +import borsh_construct as borsh + + +class XJSON(typing.TypedDict): + kind: typing.Literal["X"] + + +class OJSON(typing.TypedDict): + kind: typing.Literal["O"] + + +@dataclass +class X: + discriminator: typing.ClassVar = 0 + kind: typing.ClassVar = "X" + + @classmethod + def to_json(cls) -> XJSON: + return XJSON( + kind="X", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "X": {}, + } + + +@dataclass +class O: + discriminator: typing.ClassVar = 1 + kind: typing.ClassVar = "O" + + @classmethod + def to_json(cls) -> OJSON: + return OJSON( + kind="O", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "O": {}, + } + + +SignKind = typing.Union[X, O] +SignJSON = typing.Union[XJSON, OJSON] + + +def from_decoded(obj: dict) -> SignKind: + if not isinstance(obj, dict): + raise ValueError("Invalid enum object") + if "X" in obj: + return X() + if "O" in obj: + return O() + raise ValueError("Invalid enum object") + + +def from_json(obj: SignJSON) -> SignKind: + if obj["kind"] == "X": + return X() + if obj["kind"] == "O": + return O() + kind = obj["kind"] + raise ValueError(f"Unrecognized enum kind: {kind}") + + +layout = EnumForCodegen("X" / borsh.CStruct(), "O" / borsh.CStruct()) diff --git a/basics/anchorpy-main/examples/client-gen/tictactoe/types/tile.py b/basics/anchorpy-main/examples/client-gen/tictactoe/types/tile.py new file mode 100644 index 0000000..dcd9142 --- /dev/null +++ b/basics/anchorpy-main/examples/client-gen/tictactoe/types/tile.py @@ -0,0 +1,31 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from construct import Container +import borsh_construct as borsh + + +class TileJSON(typing.TypedDict): + row: int + column: int + + +@dataclass +class Tile: + layout: typing.ClassVar = borsh.CStruct("row" / borsh.U8, "column" / borsh.U8) + row: int + column: int + + @classmethod + def from_decoded(cls, obj: Container) -> "Tile": + return cls(row=obj.row, column=obj.column) + + def to_encodable(self) -> dict[str, typing.Any]: + return {"row": self.row, "column": self.column} + + def to_json(self) -> TileJSON: + return {"row": self.row, "column": self.column} + + @classmethod + def from_json(cls, obj: TileJSON) -> "Tile": + return cls(row=obj["row"], column=obj["column"]) diff --git a/basics/anchorpy-main/mkdocs.yml b/basics/anchorpy-main/mkdocs.yml new file mode 100644 index 0000000..98b2c0a --- /dev/null +++ b/basics/anchorpy-main/mkdocs.yml @@ -0,0 +1,64 @@ +site_name: AnchorPy +theme: + name: material + icon: + logo: material/anchor + favicon: img/anchor.svg + features: + - navigation.tabs + - navigation.top + palette: + - scheme: default + primary: lime + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + - scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode + custom_dir: overrides +markdown_extensions: + - pymdownx.highlight + - pymdownx.superfences + - admonition + - pymdownx.snippets + - meta + - pymdownx.tabbed: + alternate_style: true +repo_url: https://github.com/kevinheavey/anchorpy +repo_name: kevinheavey/anchorpy +site_url: https://kevinheavey.github.io/anchorpy/ +plugins: + - mkdocstrings: + handlers: + python: + selection: + filters: + - "!^_" # exlude all members starting with _ + - "^__init__$" # but always include __init__ modules and methods + rendering: + show_root_heading: true + show_root_full_path: false + - search +nav: + - index.md + - Client Generator: + - clientgen/index.md + - Dynamic Client: + - dynamic_client/index.md + - dynamic_client/comparison_with_anchor_ts.md + - dynamic_client/examples.md + - dynamic_client/api_reference.md + - Testing: + - testing/index.md + - CLI Reference: + - cli/index.md +extra_css: + - css/mkdocstrings.css + - css/termynal.css + - css/custom.css +extra_javascript: + - 'https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js' + - 'js/termynal.js' + - 'js/custom.js' \ No newline at end of file diff --git a/basics/anchorpy-main/mypy.ini b/basics/anchorpy-main/mypy.ini new file mode 100644 index 0000000..ceaa6ec --- /dev/null +++ b/basics/anchorpy-main/mypy.ini @@ -0,0 +1,29 @@ +[mypy] +enable_recursive_aliases = True + +[mypy-pytest] +ignore_missing_imports = True + +[mypy-xprocess] +ignore_missing_imports = True + +[mypy-autoflake] +ignore_missing_imports = True + +[mypy-pytest_xprocess] +ignore_missing_imports = True + +[mypy-toolz] +ignore_missing_imports = True + +[mypy-IPython] +ignore_missing_imports = True + +[mypy-genpy] +ignore_missing_imports = True + +[mypy-typer.*] +ignore_missing_imports = True + +[mypy-black] +ignore_missing_imports = True diff --git a/basics/anchorpy-main/noxfile.py b/basics/anchorpy-main/noxfile.py new file mode 100644 index 0000000..c7f28c7 --- /dev/null +++ b/basics/anchorpy-main/noxfile.py @@ -0,0 +1,9 @@ +# noqa: D100 +from nox_poetry import session # type: ignore + + +@session +def tests(session): # noqa: D103,WPS442 + session.run_always("poetry", "install", "-E", "cli", external=True) + session.install(".") + session.run("pytest", "tests/unit", external=True) diff --git a/basics/anchorpy-main/overrides/main.html b/basics/anchorpy-main/overrides/main.html new file mode 100644 index 0000000..ad5b6ad --- /dev/null +++ b/basics/anchorpy-main/overrides/main.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} + +{% block extrahead %} + +{% endblock %} \ No newline at end of file diff --git a/basics/anchorpy-main/poetry.lock b/basics/anchorpy-main/poetry.lock new file mode 100644 index 0000000..6d4b53f --- /dev/null +++ b/basics/anchorpy-main/poetry.lock @@ -0,0 +1,1883 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "anchorpy-core" +version = "0.1.3" +description = "Python bindings for Anchor Rust code" +optional = false +python-versions = ">=3.9" +files = [ + {file = "anchorpy_core-0.1.3-cp37-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:c9af073115feaab9a7fd14bc9f0d19a87650042bd430e44e9c7714b18f5aeb3a"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4511a3a9a0425a84305e56087b81969d2929ac642b2c1d6fb2a500c8f987d8d3"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f5f37b3b75e891227beeb9f6ca35505317aa41e6f5a5ba92599aa3a4ecad9226"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3690504cd40e5ea62aa78d23de3e93a8e8929fe50a86412253f9705640ce8993"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8db7816180720041d7a756cd87e75fc9875c4e5b2c68faf8b440053d44d1a747"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41134b3c08ed405c92e247ba77e966edf6859e741ae20109bcc3d02dfd0d37fc"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:21a6cc01fb5932b9bbfcf3ab36e924c5a5f8897a4dfad73c96c2f6e934aeddf0"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:a6105025999e7270e0961e6c8a0436aa4218fc2d78ca056361d2aa2dffea46a3"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e9fe6f2e06dd0d3b27c079121a2bc0b495c7c1dc5026e81a2a0f947d7d840e5f"}, + {file = "anchorpy_core-0.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:c952fe786c126e3c8b902d10c6d423085654001478e9a77600b105b3c66ac8ec"}, + {file = "anchorpy_core-0.1.3.tar.gz", hash = "sha256:46a328ee5b6be730311ff673ad60e8e6e40e2eea7f8254c687ecff21416a2256"}, +] + +[package.dependencies] +jsonalias = "0.1.1" + +[[package]] +name = "anyio" +version = "3.7.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "anyio-3.7.0-py3-none-any.whl", hash = "sha256:eddca883c4175f14df8aedce21054bfca3adb70ffe76a9f607aef9d7fa2ea7f0"}, + {file = "anyio-3.7.0.tar.gz", hash = "sha256:275d9973793619a5374e1c89a4f4ad3f4b0a5510a2b5b939444bee8f4c4d37ce"}, +] + +[package.dependencies] +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=6.1.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme", "sphinxcontrib-jquery"] +test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (<0.22)"] + +[[package]] +name = "appnope" +version = "0.1.3" +description = "Disable App Nap on macOS >= 10.9" +optional = true +python-versions = "*" +files = [ + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, +] + +[[package]] +name = "asttokens" +version = "2.2.1" +description = "Annotate AST trees with source code positions" +optional = true +python-versions = "*" +files = [ + {file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"}, + {file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"}, +] + +[package.dependencies] +six = "*" + +[package.extras] +test = ["astroid", "pytest"] + +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + +[[package]] +name = "autoflake" +version = "1.7.8" +description = "Removes unused imports and unused variables" +optional = true +python-versions = ">=3.7" +files = [ + {file = "autoflake-1.7.8-py3-none-any.whl", hash = "sha256:46373ef69b6714f5064c923bb28bd797c4f8a9497f557d87fc36665c6d956b39"}, + {file = "autoflake-1.7.8.tar.gz", hash = "sha256:e7e46372dee46fa1c97acf310d99d922b63d369718a270809d7c278d34a194cf"}, +] + +[package.dependencies] +pyflakes = ">=1.1.0,<3" +tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} + +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +optional = true +python-versions = "*" +files = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] + +[[package]] +name = "based58" +version = "0.1.1" +description = "A fast Python library for Base58 and Base58Check" +optional = false +python-versions = ">=3.7" +files = [ + {file = "based58-0.1.1-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:745851792ce5fada615f05ec61d7f360d19c76950d1e86163b2293c63a5d43bc"}, + {file = "based58-0.1.1-cp37-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:f8448a71678bd1edc0a464033695686461ab9d6d0bc3282cb29b94f883583572"}, + {file = "based58-0.1.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:852c37206374a62c5d3ef7f6777746e2ad9106beec4551539e9538633385e613"}, + {file = "based58-0.1.1-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fb17f0aaaad0381c8b676623c870c1a56aca039e2a7c8416e65904d80a415f7"}, + {file = "based58-0.1.1-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:06f3c40b358b0c6fc6fc614c43bb11ef851b6d04e519ac1eda2833420cb43799"}, + {file = "based58-0.1.1-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a9db744be79c8087eebedbffced00c608b3ed780668ab3c59f1d16e72c84947"}, + {file = "based58-0.1.1-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0506435e98836cc16e095e0d6dc428810e0acfb44bc2f3ac3e23e051a69c0e3e"}, + {file = "based58-0.1.1-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8937e97fa8690164fd11a7c642f6d02df58facd2669ae7355e379ab77c48c924"}, + {file = "based58-0.1.1-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14b01d91ac250300ca7f634e5bf70fb2b1b9aaa90cc14357943c7da525a35aff"}, + {file = "based58-0.1.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6c03c7f0023981c7d52fc7aad23ed1f3342819358b9b11898d693c9ef4577305"}, + {file = "based58-0.1.1-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:621269732454875510230b85053f462dffe7d7babecc8c553fdb488fd15810ff"}, + {file = "based58-0.1.1-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:aba18f6c869fade1d1551fe398a376440771d6ce288c54cba71b7090cf08af02"}, + {file = "based58-0.1.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ae7f17b67bf0c209da859a6b833504aa3b19dbf423cbd2369aa17e89299dc972"}, + {file = "based58-0.1.1-cp37-abi3-win32.whl", hash = "sha256:d8dece575de525c1ad889d9ab239defb7a6ceffc48f044fe6e14a408fb05bef4"}, + {file = "based58-0.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:ab85804a401a7b5a7141fbb14ef5b5f7d85288357d1d3f0085d47e616cef8f5a"}, + {file = "based58-0.1.1.tar.gz", hash = "sha256:80804b346b34196c89dc7a3dc89b6021f910f4cd75aac41d433ca1880b1672dc"}, +] + +[[package]] +name = "black" +version = "22.12.0" +description = "The uncompromising code formatter." +optional = true +python-versions = ">=3.7" +files = [ + {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, + {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, + {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, + {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, + {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, + {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, + {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, + {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, + {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, + {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, + {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, + {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "borsh-construct" +version = "0.1.0" +description = "Python implementation of Borsh serialization, built on the Construct library." +optional = false +python-versions = ">=3.8.3,<4.0.0" +files = [ + {file = "borsh-construct-0.1.0.tar.gz", hash = "sha256:c916758ceba70085d8f456a1cc26991b88cb64233d347767766473b651b37263"}, + {file = "borsh_construct-0.1.0-py3-none-any.whl", hash = "sha256:f584c791e2a03f8fc36e6c13011a27bcaf028c9c54ba89cd70f485a7d1c687ed"}, +] + +[package.dependencies] +construct-typing = ">=0.5.1,<0.6.0" +sumtypes = ">=0.1a5,<0.2" + +[[package]] +name = "bump2version" +version = "1.0.1" +description = "Version-bump your software with a single command!" +optional = false +python-versions = ">=3.5" +files = [ + {file = "bump2version-1.0.1-py2.py3-none-any.whl", hash = "sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410"}, + {file = "bump2version-1.0.1.tar.gz", hash = "sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6"}, +] + +[[package]] +name = "cachetools" +version = "4.2.4" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = "~=3.5" +files = [ + {file = "cachetools-4.2.4-py3-none-any.whl", hash = "sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1"}, + {file = "cachetools-4.2.4.tar.gz", hash = "sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693"}, +] + +[[package]] +name = "certifi" +version = "2023.5.7" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, +] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.1.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, + {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, +] + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "construct" +version = "2.10.68" +description = "A powerful declarative symmetric parser/builder for binary data" +optional = false +python-versions = ">=3.6" +files = [ + {file = "construct-2.10.68.tar.gz", hash = "sha256:7b2a3fd8e5f597a5aa1d614c3bd516fa065db01704c72a1efaaeec6ef23d8b45"}, +] + +[package.extras] +extras = ["arrow", "cloudpickle", "enum34", "lz4", "numpy", "ruamel.yaml"] + +[[package]] +name = "construct-typing" +version = "0.5.6" +description = "Extension for the python package 'construct' that adds typing features" +optional = false +python-versions = ">=3.7" +files = [ + {file = "construct-typing-0.5.6.tar.gz", hash = "sha256:0dc501351cd6b308f15ec54e5fe7c0fbc07cc1530a1b77b4303062a0a93c1297"}, + {file = "construct_typing-0.5.6-py3-none-any.whl", hash = "sha256:39c948329e880564e33521cba497b21b07967c465b9c9037d6334e2cffa1ced9"}, +] + +[package.dependencies] +construct = "2.10.68" + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = true +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "executing" +version = "1.2.0" +description = "Get the currently executing AST node of a frame, and other information" +optional = true +python-versions = "*" +files = [ + {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, + {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, +] + +[package.extras] +tests = ["asttokens", "littleutils", "pytest", "rich"] + +[[package]] +name = "genpy" +version = "2021.1" +description = "AST-based generation of Python source code" +optional = true +python-versions = "~=3.6" +files = [ + {file = "genpy-2021.1.tar.gz", hash = "sha256:9bc062fa98c5c466ff464d8974be81a6bf67af9247b5e5176215ad1e81a6cdac"}, +] + +[package.dependencies] +numpy = ">=1.6" +pytools = ">=2015.1.2" + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "0.16.3" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.7" +files = [ + {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, + {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, +] + +[package.dependencies] +anyio = ">=3.0,<5.0" +certifi = "*" +h11 = ">=0.13,<0.15" +sniffio = "==1.*" + +[package.extras] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx" +version = "0.23.3" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.7" +files = [ + {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, + {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, +] + +[package.dependencies] +certifi = "*" +httpcore = ">=0.15.0,<0.17.0" +rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "importlib-metadata" +version = "6.6.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, + {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "ipython" +version = "8.14.0" +description = "IPython: Productive Interactive Computing" +optional = true +python-versions = ">=3.9" +files = [ + {file = "ipython-8.14.0-py3-none-any.whl", hash = "sha256:248aca623f5c99a6635bc3857677b7320b9b8039f99f070ee0d20a5ca5a8e6bf"}, + {file = "ipython-8.14.0.tar.gz", hash = "sha256:1d197b907b6ba441b692c48cf2a3a2de280dc0ac91a3405b39349a50272ca0a1"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} + +[package.extras] +all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] + +[[package]] +name = "jedi" +version = "0.18.2" +description = "An autocompletion tool for Python that can be used for text editors." +optional = true +python-versions = ">=3.6" +files = [ + {file = "jedi-0.18.2-py2.py3-none-any.whl", hash = "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e"}, + {file = "jedi-0.18.2.tar.gz", hash = "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"}, +] + +[package.dependencies] +parso = ">=0.8.0,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jinja2" +version = "3.0.3" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.6" +files = [ + {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, + {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jsonalias" +version = "0.1.1" +description = "A microlibrary that defines a Json type alias for Python." +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "jsonalias-0.1.1-py3-none-any.whl", hash = "sha256:a56d2888e6397812c606156504e861e8ec00e188005af149f003c787db3d3f18"}, + {file = "jsonalias-0.1.1.tar.gz", hash = "sha256:64f04d935397d579fc94509e1fcb6212f2d081235d9d6395bd10baedf760a769"}, +] + +[[package]] +name = "jsonrpcclient" +version = "4.0.3" +description = "Send JSON-RPC requests" +optional = false +python-versions = ">=3.6" +files = [ + {file = "jsonrpcclient-4.0.3-py3-none-any.whl", hash = "sha256:3cbb9e27e1be29821becf135ea183144a836215422727e1ffe5056a49a670f0d"}, +] + +[package.extras] +qa = ["pytest", "pytest-cov", "tox"] + +[[package]] +name = "markdown" +version = "3.3.7" +description = "Python implementation of Markdown." +optional = false +python-versions = ">=3.6" +files = [ + {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, + {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} + +[package.extras] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "2.1.2" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, + {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = true +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +optional = false +python-versions = ">=3.6" +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mkdocs" +version = "1.4.3" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.7" +files = [ + {file = "mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd"}, + {file = "mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} +jinja2 = ">=2.11.1" +markdown = ">=3.2.1,<3.4" +mergedeep = ">=1.3.4" +packaging = ">=20.5" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-autorefs" +version = "0.4.1" +description = "Automatically link across pages in MkDocs." +optional = false +python-versions = ">=3.7" +files = [ + {file = "mkdocs-autorefs-0.4.1.tar.gz", hash = "sha256:70748a7bd025f9ecd6d6feeba8ba63f8e891a1af55f48e366d6d6e78493aba84"}, + {file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"}, +] + +[package.dependencies] +Markdown = ">=3.3" +mkdocs = ">=1.1" + +[[package]] +name = "mkdocs-material" +version = "8.5.11" +description = "Documentation that simply works" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mkdocs_material-8.5.11-py3-none-any.whl", hash = "sha256:c907b4b052240a5778074a30a78f31a1f8ff82d7012356dc26898b97559f082e"}, + {file = "mkdocs_material-8.5.11.tar.gz", hash = "sha256:b0ea0513fd8cab323e8a825d6692ea07fa83e917bb5db042e523afecc7064ab7"}, +] + +[package.dependencies] +jinja2 = ">=3.0.2" +markdown = ">=3.2" +mkdocs = ">=1.4.0" +mkdocs-material-extensions = ">=1.1" +pygments = ">=2.12" +pymdown-extensions = ">=9.4" +requests = ">=2.26" + +[[package]] +name = "mkdocs-material-extensions" +version = "1.1.1" +description = "Extension pack for Python Markdown and MkDocs Material." +optional = false +python-versions = ">=3.7" +files = [ + {file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"}, + {file = "mkdocs_material_extensions-1.1.1.tar.gz", hash = "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93"}, +] + +[[package]] +name = "mkdocstrings" +version = "0.17.0" +description = "Automatic documentation from sources, for MkDocs." +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "mkdocstrings-0.17.0-py3-none-any.whl", hash = "sha256:103fc1dd58cb23b7e0a6da5292435f01b29dc6fa0ba829132537f3f556f985de"}, + {file = "mkdocstrings-0.17.0.tar.gz", hash = "sha256:75b5cfa2039aeaf3a5f5cf0aa438507b0330ce76c8478da149d692daa7213a98"}, +] + +[package.dependencies] +Jinja2 = ">=2.11.1" +Markdown = ">=3.3" +MarkupSafe = ">=1.1" +mkdocs = ">=1.2" +mkdocs-autorefs = ">=0.1" +pymdown-extensions = ">=6.3" +pytkdocs = ">=0.14.0" + +[[package]] +name = "more-itertools" +version = "8.14.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.5" +files = [ + {file = "more-itertools-8.14.0.tar.gz", hash = "sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750"}, + {file = "more_itertools-8.14.0-py3-none-any.whl", hash = "sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2"}, +] + +[[package]] +name = "mypy" +version = "0.982" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, + {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"}, + {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"}, + {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"}, + {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"}, + {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"}, + {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"}, + {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"}, + {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"}, + {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"}, + {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"}, + {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"}, + {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"}, + {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"}, + {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"}, + {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"}, + {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"}, + {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"}, + {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"}, + {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"}, + {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"}, + {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"}, + {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"}, + {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"}, +] + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numpy" +version = "1.24.3" +description = "Fundamental package for array computing in Python" +optional = true +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"}, + {file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"}, + {file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"}, + {file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"}, + {file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"}, + {file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"}, + {file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"}, + {file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"}, + {file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"}, + {file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"}, +] + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = true +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + +[[package]] +name = "pathspec" +version = "0.11.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = true +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, + {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, +] + +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +optional = true +python-versions = "*" +files = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +optional = true +python-versions = "*" +files = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] + +[[package]] +name = "platformdirs" +version = "3.5.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = true +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, + {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, +] + +[package.extras] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.38" +description = "Library for building powerful interactive command lines in Python" +optional = true +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.38-py3-none-any.whl", hash = "sha256:45ea77a2f7c60418850331366c81cf6b5b9cf4c7fd34616f733c5427e6abbb1f"}, + {file = "prompt_toolkit-3.0.38.tar.gz", hash = "sha256:23ac5d50538a9a38c8bde05fecb47d0b403ecd0662857a86f886f798563d5b9b"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psutil" +version = "5.9.5" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, + {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, + {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, + {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, + {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, + {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, + {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, + {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = true +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = true +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pyflakes" +version = "2.5.0" +description = "passive checker of Python programs" +optional = true +python-versions = ">=3.6" +files = [ + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, +] + +[[package]] +name = "pygments" +version = "2.15.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pyheck" +version = "0.1.5" +description = "Python bindings for heck, the Rust case conversion library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyheck-0.1.5-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:44caf2b7a49d71fdeb0469e9f35886987ad815a8638b3c5b5c83f351d6aed413"}, + {file = "pyheck-0.1.5-cp37-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:316a842b94beff6e59a97dbcc590e9be92a932e59126b0faa9ac750384f27eaf"}, + {file = "pyheck-0.1.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b6169397395ff041f056bfb36c1957a788a1cd7cb967a927fcae7917ff1b6aa"}, + {file = "pyheck-0.1.5-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e9d101e1c599227280e34eeccab0414246e70a91a1cabb4c4868dca284f2be7d"}, + {file = "pyheck-0.1.5-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:69d6509138909df92b2f2f837518dca118ef08ae3c804044ae511b81b7aecb4d"}, + {file = "pyheck-0.1.5-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ce4a2e1b4778051b8f31183e321a034603f3957b6e95cf03bf5f231c8ea3066"}, + {file = "pyheck-0.1.5-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69387b70d910637ab6dc8dc378c8e0b4037cee2c51a9c6f64ce5331b010f5de3"}, + {file = "pyheck-0.1.5-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0fb50b7d899d2a583ec2ac291b8ec2afb10f0e32c4ac290148d3da15927787f8"}, + {file = "pyheck-0.1.5-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:aa8dfd0883212f8495e0bae6eb6ea670c56f9b197b5fe6fb5cae9fd5ec56fb7c"}, + {file = "pyheck-0.1.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b7c07506b9591e27f8241bf7a72bc4d5c4ac30dedb332efb87e402e49029f233"}, + {file = "pyheck-0.1.5-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:9ee256cafbdab6c5fcca22d0910176d820bf1e1298773e64f4eea79f51218cc7"}, + {file = "pyheck-0.1.5-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:e9ba36060abc55127c3813de398b4013c05be6118cfae3cfa3d978f7b4c84dea"}, + {file = "pyheck-0.1.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:64201a6d213bec443aeb33f66c60cea61aaf6257e48a19159ac69a5afad4768e"}, + {file = "pyheck-0.1.5-cp37-abi3-win32.whl", hash = "sha256:1501fcfd15f7c05c6bfe38915f5e514ac95fc63e945f7d8b089d30c1b8fdb2c5"}, + {file = "pyheck-0.1.5-cp37-abi3-win_amd64.whl", hash = "sha256:e519f80a0ef87a8f880bfdf239e396e238dcaed34bec1ea7ef526c4873220e82"}, + {file = "pyheck-0.1.5.tar.gz", hash = "sha256:5c9fe372d540c5dbcb76bf062f951d998d0e14c906c842a52f1cd5de208e183a"}, +] + +[[package]] +name = "pymdown-extensions" +version = "10.0.1" +description = "Extension pack for Python Markdown." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pymdown_extensions-10.0.1-py3-none-any.whl", hash = "sha256:ae66d84013c5d027ce055693e09a4628b67e9dec5bce05727e45b0918e36f274"}, + {file = "pymdown_extensions-10.0.1.tar.gz", hash = "sha256:b44e1093a43b8a975eae17b03c3a77aad4681b3b56fce60ce746dbef1944c8cb"}, +] + +[package.dependencies] +markdown = ">=3.2" +pyyaml = "*" + +[[package]] +name = "pytest" +version = "7.3.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.0" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, + {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-xprocess" +version = "0.18.1" +description = "A pytest plugin for managing processes across test runs." +optional = false +python-versions = ">=3.5" +files = [ + {file = "pytest-xprocess-0.18.1.tar.gz", hash = "sha256:fd9f30ed1584b5833bc34494748adf0fb9de3ca7bacc4e88ad71989c21cba266"}, + {file = "pytest_xprocess-0.18.1-py3-none-any.whl", hash = "sha256:6f2aba817d842518d9d9dfb7e9adfe2a6e354a4359f4166bef0822ef4be1c9db"}, +] + +[package.dependencies] +psutil = "*" +pytest = ">=2.8" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytkdocs" +version = "0.16.1" +description = "Load Python objects documentation." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytkdocs-0.16.1-py3-none-any.whl", hash = "sha256:a8c3f46ecef0b92864cc598e9101e9c4cf832ebbf228f50c84aa5dd850aac379"}, + {file = "pytkdocs-0.16.1.tar.gz", hash = "sha256:e2ccf6dfe9dbbceb09818673f040f1a7c32ed0bffb2d709b06be6453c4026045"}, +] + +[package.extras] +numpy-style = ["docstring_parser (>=0.7)"] + +[[package]] +name = "pytools" +version = "2022.1.14" +description = "A collection of tools for Python" +optional = true +python-versions = "~=3.8" +files = [ + {file = "pytools-2022.1.14.tar.gz", hash = "sha256:41017371610bb2a03685597c5285205e6597c7f177383d95c8b871244b12c14e"}, +] + +[package.dependencies] +platformdirs = ">=2.2.0" +typing_extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +numpy = ["numpy (>=1.6.0)"] + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rfc3986" +version = "1.5.0" +description = "Validating URI References per RFC 3986" +optional = false +python-versions = "*" +files = [ + {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, +] + +[package.dependencies] +idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "ruff" +version = "0.0.220" +description = "An extremely fast Python linter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.0.220-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:152e6697aca6aea991cdd37922c34a3e4db4828822c4663122326e6051e0f68a"}, + {file = "ruff-0.0.220-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:127887a00d53beb7c0c78a8b4bbdda2f14f07db7b3571feb6855cb32862cb88d"}, + {file = "ruff-0.0.220-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91235ff448786f8f3b856c104fd6c4fe11e835b0db75da5fdf337e1ed5d454da"}, + {file = "ruff-0.0.220-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f0a104afc32012048627317ae8b0940e3f11a717905aed3fc26931a873e3b29"}, + {file = "ruff-0.0.220-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eee1deddf1671860e056a78938176600108857a527c078038627b284a554723c"}, + {file = "ruff-0.0.220-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:071082d09c953924eccfd88ffd0d71119ddd6fc7767f3c31549a1cd0651ba586"}, + {file = "ruff-0.0.220-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5ddfc945a9076c9779b52c1f7296cf8d8e6919e619c4522617bc37b60eddd2e"}, + {file = "ruff-0.0.220-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15f387fd156430353fb61d2b609f1c38d2e9096e2fce31149da5cf08b73f04a8"}, + {file = "ruff-0.0.220-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5688983f21ac64bbcca8d84f4107733cc2d62c1354ea1a6b85eb9ead32328cc"}, + {file = "ruff-0.0.220-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e2b0c9dbff13649ded5ee92d6a47d720e8471461e0a4eba01bf3474f851cb2f0"}, + {file = "ruff-0.0.220-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9b540fa9f90f46f656b34fb73b738613562974599903a1f0d40bdd1a8180bfab"}, + {file = "ruff-0.0.220-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a061c17c2b0f81193fca5e53829b6c0569c5c7d393cc4fc1c192ce0a64d3b9ca"}, + {file = "ruff-0.0.220-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:42677089abd7db6f8aefa3dbe7a82fea4e2a43a08bc7bf6d3f58ec3d76c63712"}, + {file = "ruff-0.0.220-py3-none-win32.whl", hash = "sha256:f8821cfc204b38140afe870bcd4cc6c836bbd2f820b92df66b8fe8b8d71a3772"}, + {file = "ruff-0.0.220-py3-none-win_amd64.whl", hash = "sha256:8a1d678a224afd7149afbe497c97c3ccdc6c42632ee84fb0e3f68d190c1ccec1"}, + {file = "ruff-0.0.220.tar.gz", hash = "sha256:621f7f063c0d13570b709fb9904a329ddb9a614fdafc786718afd43e97440c34"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "solana" +version = "0.30.2" +description = "Solana Python API" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "solana-0.30.2-py3-none-any.whl", hash = "sha256:d7e8295a1f86982ba51e78a65c16ce55f4a9e9caa8938564922a209ddfb2a01f"}, + {file = "solana-0.30.2.tar.gz", hash = "sha256:7b16e76cdd1d3024219679cdb73c20324d6d79e3c9766fe0ca52be79ef5ff691"}, +] + +[package.dependencies] +cachetools = ">=4.2.2,<5.0.0" +construct-typing = ">=0.5.2,<0.6.0" +httpx = ">=0.23.0,<0.24.0" +solders = ">=0.18.0,<0.19.0" +types-cachetools = ">=4.2.4,<5.0.0" +typing-extensions = ">=4.2.0" +websockets = ">=9.0,<12.0" + +[[package]] +name = "solders" +version = "0.18.0" +description = "Python bindings for Solana Rust tools" +optional = false +python-versions = ">=3.7" +files = [ + {file = "solders-0.18.0-cp37-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:cd30c9a2b1967975b2d05895cc4a3ef701c9e686a1d156e131a6c97d4b1decd5"}, + {file = "solders-0.18.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0b7c9cafffa570652aaabf5d3ccc987ea18c9470718631e4881ca679823b18ae"}, + {file = "solders-0.18.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90be96a432d8580ff52eed6098b4be12c064829588304f8f2a79d9adfd2b789d"}, + {file = "solders-0.18.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07c700ad784754609cffe2fd4177124c359d5353ba1d2d8b6d4e8ae59957aa7d"}, + {file = "solders-0.18.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a29449f6827d2a220bed2873f4a485f000e01ddc9f58ba19771c5d53fa4fe28d"}, + {file = "solders-0.18.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:3260b9d3c469818d9229a667621b4714863fa35ca2709a1c6e224efc21e516cc"}, + {file = "solders-0.18.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:632ba10040d3fac819363abb3cbbd3a5974e8c9800b897ca9641efe9b36b4975"}, + {file = "solders-0.18.0-cp37-abi3-win_amd64.whl", hash = "sha256:40cc86dccee766c05ccd594a66761b44248907bfbfa85956bbbc9fb504dde7cd"}, + {file = "solders-0.18.0.tar.gz", hash = "sha256:8c32aa7c3a0fa87a2f4589279ce70b17261096bae09316ca4a4e1052f471c629"}, +] + +[package.dependencies] +jsonalias = "0.1.1" +typing-extensions = ">=4.2.0" + +[[package]] +name = "stack-data" +version = "0.6.2" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = true +python-versions = "*" +files = [ + {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, + {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "sumtypes" +version = "0.1a6" +description = "Algebraic types for Python (notably providing Sum Types, aka Tagged Unions)" +optional = false +python-versions = "*" +files = [ + {file = "sumtypes-0.1a6-py2.py3-none-any.whl", hash = "sha256:3e9d71322dd927d25d935072f8be7daec655ea292fd392359a5bb2c1e53dfdc3"}, + {file = "sumtypes-0.1a6.tar.gz", hash = "sha256:1a6ff095e06a1885f340ddab803e0f38e3f9bed81f9090164ca9682e04e96b43"}, +] + +[package.dependencies] +attrs = "*" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "toolz" +version = "0.11.2" +description = "List processing tools and functional utilities" +optional = false +python-versions = ">=3.5" +files = [ + {file = "toolz-0.11.2-py3-none-any.whl", hash = "sha256:a5700ce83414c64514d82d60bcda8aabfde092d1c1a8663f9200c07fdcc6da8f"}, + {file = "toolz-0.11.2.tar.gz", hash = "sha256:6b312d5e15138552f1bda8a4e66c30e236c831b612b2bf0005f8a1df10a4bc33"}, +] + +[[package]] +name = "traitlets" +version = "5.9.0" +description = "Traitlets Python configuration system" +optional = true +python-versions = ">=3.7" +files = [ + {file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"}, + {file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] + +[[package]] +name = "typer" +version = "0.4.1" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = true +python-versions = ">=3.6" +files = [ + {file = "typer-0.4.1-py3-none-any.whl", hash = "sha256:e8467f0ebac0c81366c2168d6ad9f888efdfb6d4e1d3d5b4a004f46fa444b5c3"}, + {file = "typer-0.4.1.tar.gz", hash = "sha256:5646aef0d936b2c761a10393f0384ee6b5c7fe0bb3e5cd710b17134ca1d99cff"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=5.2,<6.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "types-cachetools" +version = "4.2.10" +description = "Typing stubs for cachetools" +optional = false +python-versions = "*" +files = [ + {file = "types-cachetools-4.2.10.tar.gz", hash = "sha256:b1cb18aaff25d2ad47a060413c660c39fadddb01f72012dd1134584b1fdaada5"}, + {file = "types_cachetools-4.2.10-py3-none-any.whl", hash = "sha256:48301115189d4879d0960baac5a8a2b2d31ce6129b2ce3b915000ed337284898"}, +] + +[[package]] +name = "typing-extensions" +version = "4.6.3" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, + {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, +] + +[[package]] +name = "urllib3" +version = "2.0.2" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, + {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "watchdog" +version = "3.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.7" +files = [ + {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"}, + {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"}, + {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"}, + {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"}, + {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"}, + {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, + {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"}, + {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"}, + {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"}, + {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"}, + {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[[package]] +name = "wcwidth" +version = "0.2.6" +description = "Measures the displayed width of unicode strings in a terminal" +optional = true +python-versions = "*" +files = [ + {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, + {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, +] + +[[package]] +name = "websockets" +version = "10.4" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "websockets-10.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48"}, + {file = "websockets-10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab"}, + {file = "websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331"}, + {file = "websockets-10.4-cp310-cp310-win32.whl", hash = "sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a"}, + {file = "websockets-10.4-cp310-cp310-win_amd64.whl", hash = "sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089"}, + {file = "websockets-10.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4"}, + {file = "websockets-10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f"}, + {file = "websockets-10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9"}, + {file = "websockets-10.4-cp311-cp311-win32.whl", hash = "sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8"}, + {file = "websockets-10.4-cp311-cp311-win_amd64.whl", hash = "sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882"}, + {file = "websockets-10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c"}, + {file = "websockets-10.4-cp37-cp37m-win32.whl", hash = "sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038"}, + {file = "websockets-10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28"}, + {file = "websockets-10.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94"}, + {file = "websockets-10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63"}, + {file = "websockets-10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56"}, + {file = "websockets-10.4-cp38-cp38-win32.whl", hash = "sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a"}, + {file = "websockets-10.4-cp38-cp38-win_amd64.whl", hash = "sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6"}, + {file = "websockets-10.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f"}, + {file = "websockets-10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112"}, + {file = "websockets-10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b"}, + {file = "websockets-10.4-cp39-cp39-win32.whl", hash = "sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588"}, + {file = "websockets-10.4-cp39-cp39-win_amd64.whl", hash = "sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74"}, + {file = "websockets-10.4-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485"}, + {file = "websockets-10.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631"}, + {file = "websockets-10.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f"}, + {file = "websockets-10.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1"}, + {file = "websockets-10.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13"}, + {file = "websockets-10.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72"}, + {file = "websockets-10.4.tar.gz", hash = "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3"}, +] + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[[package]] +name = "zstandard" +version = "0.18.0" +description = "Zstandard bindings for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "zstandard-0.18.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef7e8a200e4c8ac9102ed3c90ed2aa379f6b880f63032200909c1be21951f556"}, + {file = "zstandard-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2dc466207016564805e56d28375f4f533b525ff50d6776946980dff5465566ac"}, + {file = "zstandard-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a2ee1d4f98447f3e5183ecfce5626f983504a4a0c005fbe92e60fa8e5d547ec"}, + {file = "zstandard-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d956e2f03c7200d7e61345e0880c292783ec26618d0d921dcad470cb195bbce2"}, + {file = "zstandard-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ce6f59cba9854fd14da5bfe34217a1501143057313966637b7291d1b0267bd1e"}, + {file = "zstandard-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fa67cba473623848b6e88acf8d799b1906178fd883fb3a1da24561c779593b"}, + {file = "zstandard-0.18.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cdb44d7284c8c5dd1b66dfb86dda7f4560fa94bfbbc1d2da749ba44831335e32"}, + {file = "zstandard-0.18.0-cp310-cp310-win32.whl", hash = "sha256:63694a376cde0aa8b1971d06ca28e8f8b5f492779cb6ee1cc46bbc3f019a42a5"}, + {file = "zstandard-0.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:702a8324cd90c74d9c8780d02bf55e79da3193c870c9665ad3a11647e3ad1435"}, + {file = "zstandard-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46f679bc5dfd938db4fb058218d9dc4db1336ffaf1ea774ff152ecadabd40805"}, + {file = "zstandard-0.18.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc2a4de9f363b3247d472362a65041fe4c0f59e01a2846b15d13046be866a885"}, + {file = "zstandard-0.18.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd3220d7627fd4d26397211cb3b560ec7cc4a94b75cfce89e847e8ce7fabe32d"}, + {file = "zstandard-0.18.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:39e98cf4773234bd9cebf9f9db730e451dfcfe435e220f8921242afda8321887"}, + {file = "zstandard-0.18.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5228e596eb1554598c872a337bbe4e5afe41cd1f8b1b15f2e35b50d061e35244"}, + {file = "zstandard-0.18.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d4a8fd45746a6c31e729f35196e80b8f1e9987c59f5ccb8859d7c6a6fbeb9c63"}, + {file = "zstandard-0.18.0-cp36-cp36m-win32.whl", hash = "sha256:4cbb85f29a990c2fdbf7bc63246567061a362ddca886d7fae6f780267c0a9e67"}, + {file = "zstandard-0.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bfa6c8549fa18e6497a738b7033c49f94a8e2e30c5fbe2d14d0b5aa8bbc1695d"}, + {file = "zstandard-0.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e02043297c1832f2666cd2204f381bef43b10d56929e13c42c10c732c6e3b4ed"}, + {file = "zstandard-0.18.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7231543d38d2b7e02ef7cc78ef7ffd86419437e1114ff08709fe25a160e24bd6"}, + {file = "zstandard-0.18.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c86befac87445927488f5c8f205d11566f64c11519db223e9d282b945fa60dab"}, + {file = "zstandard-0.18.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:999a4e1768f219826ba3fa2064fab1c86dd72fdd47a42536235478c3bb3ca3e2"}, + {file = "zstandard-0.18.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df59cd1cf3c62075ee2a4da767089d19d874ac3ad42b04a71a167e91b384722"}, + {file = "zstandard-0.18.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1be31e9e3f7607ee0cdd60915410a5968b205d3e7aa83b7fcf3dd76dbbdb39e0"}, + {file = "zstandard-0.18.0-cp37-cp37m-win32.whl", hash = "sha256:490d11b705b8ae9dc845431bacc8dd1cef2408aede176620a5cd0cd411027936"}, + {file = "zstandard-0.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:266aba27fa9cc5e9091d3d325ebab1fa260f64e83e42516d5e73947c70216a5b"}, + {file = "zstandard-0.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b2260c4e07dd0723eadb586de7718b61acca4083a490dda69c5719d79bc715c"}, + {file = "zstandard-0.18.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3af8c2383d02feb6650e9255491ec7d0824f6e6dd2bbe3e521c469c985f31fb1"}, + {file = "zstandard-0.18.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28723a1d2e4df778573b76b321ebe9f3469ac98988104c2af116dd344802c3f8"}, + {file = "zstandard-0.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19cac7108ff2c342317fad6dc97604b47a41f403c8f19d0bfc396dfadc3638b8"}, + {file = "zstandard-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:76725d1ee83a8915100a310bbad5d9c1fc6397410259c94033b8318d548d9990"}, + {file = "zstandard-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d716a7694ce1fa60b20bc10f35c4a22be446ef7f514c8dbc8f858b61976de2fb"}, + {file = "zstandard-0.18.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:49685bf9a55d1ab34bd8423ea22db836ba43a181ac6b045ac4272093d5cb874e"}, + {file = "zstandard-0.18.0-cp38-cp38-win32.whl", hash = "sha256:1af1268a7dc870eb27515fb8db1f3e6c5a555d2b7bcc476fc3bab8886c7265ab"}, + {file = "zstandard-0.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:1dc2d3809e763055a1a6c1a73f2b677320cc9a5aa1a7c6cfb35aee59bddc42d9"}, + {file = "zstandard-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eea18c1e7442f2aa9aff1bb84550dbb6a1f711faf6e48e7319de8f2b2e923c2a"}, + {file = "zstandard-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8677ffc6a6096cccbd892e558471c901fd821aba12b7fbc63833c7346f549224"}, + {file = "zstandard-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:083dc08abf03807af9beeb2b6a91c23ad78add2499f828176a3c7b742c44df02"}, + {file = "zstandard-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c990063664c08169c84474acecc9251ee035871589025cac47c060ff4ec4bc1a"}, + {file = "zstandard-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:533db8a6fac6248b2cb2c935e7b92f994efbdeb72e1ffa0b354432e087bb5a3e"}, + {file = "zstandard-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbb3cb8a082d62b8a73af42291569d266b05605e017a3d8a06a0e5c30b5f10f0"}, + {file = "zstandard-0.18.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d6c85ca5162049ede475b7ec98e87f9390501d44a3d6776ddd504e872464ec25"}, + {file = "zstandard-0.18.0-cp39-cp39-win32.whl", hash = "sha256:75479e7c2b3eebf402c59fbe57d21bc400cefa145ca356ee053b0a08908c5784"}, + {file = "zstandard-0.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:d85bfabad444812133a92fc6fbe463e1d07581dba72f041f07a360e63808b23c"}, + {file = "zstandard-0.18.0.tar.gz", hash = "sha256:0ac0357a0d985b4ff31a854744040d7b5754385d1f98f7145c30e02c6865cb6f"}, +] + +[package.dependencies] +cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""} + +[package.extras] +cffi = ["cffi (>=1.11)"] + +[extras] +cli = ["autoflake", "black", "genpy", "ipython", "typer"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9" +content-hash = "1ef0fbc00af0df7e4455594d7934825823269276e8bc9efd2af9e2fc8ddd50f2" diff --git a/basics/anchorpy-main/poetry.toml b/basics/anchorpy-main/poetry.toml new file mode 100644 index 0000000..ab1033b --- /dev/null +++ b/basics/anchorpy-main/poetry.toml @@ -0,0 +1,2 @@ +[virtualenvs] +in-project = true diff --git a/basics/anchorpy-main/pyproject.toml b/basics/anchorpy-main/pyproject.toml new file mode 100644 index 0000000..5b20620 --- /dev/null +++ b/basics/anchorpy-main/pyproject.toml @@ -0,0 +1,118 @@ +[tool.poetry] +name = "anchorpy" +version = "0.18.0" +description = "The Python Anchor client." +readme = "README.md" +repository = "https://github.com/kevinheavey/anchorpy" +documentation = "https://kevinheavey.github.io/anchorpy/" +authors = ["kevinheavey "] + +[tool.poetry.dependencies] +python = "^3.9" +construct-typing = "^0.5.1" +solana = "^0.30.2" +solders = "^0.18.0" +borsh-construct = "^0.1.0" +websockets = ">=9.0,<11.0" +toolz = "^0.11.2" +jsonrpcclient = "^4.0.1" +zstandard = "^0.18.0" +pytest = "^7.2.0" +pytest-xprocess = "^0.18.1" +pytest-asyncio = "^0.21.0" +more-itertools = "^8.11.0" +pyheck = "^0.1.4" +typer = { version = "0.4.1", optional = true } +ipython = { version = "^8.0.1", optional = true } +genpy = { version = "^2021.1", optional = true } +black = { version = "^22.3.0", optional = true } +autoflake = { version = "^1.4", optional = true } +based58 = "^0.1.1" +anchorpy-core = "^0.1.3" +py = "^1.11.0" +toml = "^0.10.2" + +[tool.poetry.extras] +cli = ["typer", "ipython", "genpy", "black", "autoflake"] + + +[tool.poetry.scripts] +anchorpy = "anchorpy.cli:app" + +[tool.poetry.dev-dependencies] +mypy = "^0.982" +jinja2 = "3.0.3" +mkdocs-material = "^8.1.7" +bump2version = "^1.0.1" +mkdocstrings = "^0.17.0" +ruff = "^0.0.220" + +[tool.poetry.plugins.pytest11] +pytest_anchorpy = "anchorpy.pytest_plugin" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +select = [ + "A", + "B", + "D", + "E", + "F", + "I", + "ARG", + "BLE", + "C4", + "SIM", + "PLC", + "PLE", + "PLR", + "PLW", + "RUF", +] +ignore = ["B023", "D100", "D101", "D102", "D103", "D104", "D107", "D203"] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# Assume Python 3.10. +target-version = "py310" + +[tool.ruff.pydocstyle] +convention = "google" + +[tool.ruff.per-file-ignores] +"src/anchorpy/coder/*.py" = ["ARG002"] +"src/anchorpy/borsh_extension.py" = ["ARG002"] +"tests/**/*.py" = ["ARG001", "E501"] +"tests/client_gen/example_program_gen/**/*.py" = ["C417", "I001", "F401"] +"tests/client_gen/token/**/*.py" = ["C417", "I001", "F401"] +"src/anchorpy/cli.py" = ["B008"] + +[tool.pyright] +reportMissingModuleSource = false diff --git a/basics/anchorpy-main/pytest.ini b/basics/anchorpy-main/pytest.ini new file mode 100644 index 0000000..b8aa1e9 --- /dev/null +++ b/basics/anchorpy-main/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +markers = + unit: mark a test as a unit test. +addopts = -x +asyncio_mode=strict diff --git a/basics/anchorpy-main/src/anchorpy/__init__.py b/basics/anchorpy-main/src/anchorpy/__init__.py new file mode 100644 index 0000000..9f4a059 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/__init__.py @@ -0,0 +1,52 @@ +"""The Python Anchor client.""" +from anchorpy_core.idl import Idl + +from anchorpy import error, utils +from anchorpy.coder.coder import AccountsCoder, Coder, EventCoder, InstructionCoder +from anchorpy.idl import IdlProgramAccount +from anchorpy.program.common import ( + Event, + NamedInstruction, + translate_address, + validate_accounts, +) +from anchorpy.program.context import Context +from anchorpy.program.core import Program +from anchorpy.program.event import EventParser +from anchorpy.program.namespace.account import AccountClient, ProgramAccount +from anchorpy.program.namespace.simulate import SimulateResponse +from anchorpy.provider import Provider, Wallet +from anchorpy.pytest_plugin import bankrun_fixture, localnet_fixture, workspace_fixture +from anchorpy.workspace import WorkspaceType, close_workspace, create_workspace + +__all__ = [ + "Program", + "Provider", + "Context", + "bankrun_fixture", + "create_workspace", + "close_workspace", + "Idl", + "workspace_fixture", + "WorkspaceType", + "localnet_fixture", + "Wallet", + "Coder", + "InstructionCoder", + "EventCoder", + "AccountsCoder", + "NamedInstruction", + "IdlProgramAccount", + "Event", + "translate_address", + "validate_accounts", + "AccountClient", + "ProgramAccount", + "EventParser", + "SimulateResponse", + "error", + "utils", +] + + +__version__ = "0.18.0" diff --git a/basics/anchorpy-main/src/anchorpy/borsh_extension.py b/basics/anchorpy-main/src/anchorpy/borsh_extension.py new file mode 100644 index 0000000..bd7f058 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/borsh_extension.py @@ -0,0 +1,121 @@ +"""Extensions to the Borsh spec for Solana-specific types.""" +from dataclasses import asdict +from keyword import kwlist +from typing import Any, Dict, Type, TypeVar, cast + +from borsh_construct import U8, CStruct +from construct import ( + Adapter, + Bytes, + Construct, + Container, + IfThenElse, + Padding, + Renamed, + Switch, +) +from solders import pubkey + + +class BorshPubkeyAdapter(Adapter): + def __init__(self) -> None: + super().__init__(Bytes(32)) # type: ignore + + def _decode(self, obj: bytes, context, path) -> pubkey.Pubkey: + return pubkey.Pubkey(obj) + + def _encode(self, obj: pubkey.Pubkey, context, path) -> bytes: + return bytes(obj) + + +class EnumForCodegen(Adapter): + _index_key = "index" + _value_key = "value" + + def __init__(self, *variants: "Renamed[CStruct, CStruct]") -> None: + """Init enum.""" + switch_cases: dict[int, "Renamed[CStruct, CStruct]"] = {} + variant_name_to_index: dict[str, int] = {} + index_to_variant_name: dict[int, str] = {} + for idx, parser in enumerate(variants): + switch_cases[idx] = parser + name = cast(str, parser.name) + variant_name_to_index[name] = idx + index_to_variant_name[idx] = name + enum_struct = CStruct( + self._index_key / U8, + self._value_key + / Switch(lambda this: this.index, cast(dict[int, Construct], switch_cases)), + ) + super().__init__(enum_struct) # type: ignore + self.variant_name_to_index = variant_name_to_index + self.index_to_variant_name = index_to_variant_name + + def _decode(self, obj: CStruct, context, path) -> dict[str, Any]: + index = obj.index + variant_name = self.index_to_variant_name[index] + return {variant_name: obj.value} + + def _encode(self, obj: dict[str, Any], context, path) -> dict[str, Any]: + variant_name = list(obj.keys())[0] + index = self.variant_name_to_index[variant_name] + return {self._index_key: index, self._value_key: obj[variant_name]} + + +class COption(Adapter): + _discriminator_key = "discriminator" + _value_key = "value" + + def __init__(self, subcon: Construct) -> None: + option_struct = CStruct( + self._discriminator_key / U8, + self._value_key + / IfThenElse( + lambda this: this[self._discriminator_key] == 0, + Padding(subcon.sizeof()), + subcon, + ), + ) + super().__init__(option_struct) # type: ignore + + def _decode(self, obj, context, path) -> Any: + discriminator = obj[self._discriminator_key] + return None if discriminator == 0 else obj[self._value_key] + + def _encode(self, obj, context, path) -> dict: + discriminator = 0 if obj is None else 1 + return {self._discriminator_key: discriminator, self._value_key: obj} + + +T = TypeVar("T") + + +class _DataclassStruct(Adapter): + """Converts dataclasses to/from `borsh_construct.CStruct`.""" + + def __init__(self, cstruct: CStruct, datacls: Type[T]) -> None: + """Init. + + Args: + cstruct: The underlying `CStruct`. + datacls: The dataclass type. + """ + super().__init__(cstruct) # type: ignore + self.datacls = datacls + + def _decode(self, obj: Container, context, path) -> T: # type: ignore + kwargs = {} + for key, value in obj.items(): + if key[0] != "_": + key_to_use = f"{key}_" if key in kwlist else key + kwargs[key_to_use] = value + return self.datacls(**kwargs) # type: ignore + + def _encode(self, obj: T, context, path) -> Dict[str, Any]: + if isinstance(obj, dict): + return obj + return asdict(obj) + + +BorshPubkey = BorshPubkeyAdapter() +"""Adapter for (de)serializing a public key.""" diff --git a/basics/anchorpy-main/src/anchorpy/cli.py b/basics/anchorpy-main/src/anchorpy/cli.py new file mode 100644 index 0000000..d9f069a --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/cli.py @@ -0,0 +1,142 @@ +import os +from contextlib import contextmanager +from pathlib import Path +from typing import Optional, cast + +import typer +from anchorpy_core.idl import Idl +from IPython import embed + +from anchorpy import create_workspace +from anchorpy.clientgen.accounts import gen_accounts +from anchorpy.clientgen.errors import gen_errors +from anchorpy.clientgen.instructions import gen_instructions +from anchorpy.clientgen.program_id import gen_program_id +from anchorpy.clientgen.types import gen_types +from anchorpy.template import INIT_TESTS + +app = typer.Typer() + + +@contextmanager +def _set_directory(path: Path): + """Set the cwd within the context. + + Args: + path (Path): The path to the cwd + + Yields: + None + """ # noqa: D202 + + origin = Path().absolute() + try: + os.chdir(path) + yield + finally: + os.chdir(origin) + + +def _search_upwards_for_project_root() -> Path: + """Search in the current dir and all directories above it for an Anchor.toml file. + + Returns: + The location of the first Anchor.toml file found + """ + search_dir = Path.cwd() + root = Path(search_dir.root) + + while search_dir != root: + attempt = search_dir / "Anchor.toml" + if attempt.exists(): + return search_dir + search_dir = search_dir.parent + + raise FileNotFoundError("Not in Anchor workspace.") + + +@app.callback() +def callback(): + """AnchorPy CLI.""" + + +@app.command() +def shell(): + """Start IPython shell with AnchorPy workspace object initialized. + + Note that you should run `anchor localnet` before `anchorpy shell`. + """ + path = _search_upwards_for_project_root() + workspace = create_workspace(path) # noqa: F841 + embed( + colors="neutral", + using="asyncio", + banner2="Hint: type `workspace` to see the Anchor workspace object.\n", + ) + + +@app.command() +def init( + program_name: str = typer.Argument(..., help="The name of the Anchor program.") +): + """Create a basic Python test file for an Anchor program. + + This does not replace `anchor init`, but rather should be + run after it. + + The test file will live at `tests/test_$PROGRAM_NAME.py`. + """ + file_contents = INIT_TESTS.format(program_name) + project_root = _search_upwards_for_project_root() + file_path = project_root / "tests" / f"test_{program_name}.py" + if file_path.exists(): + raise FileExistsError(file_path) + file_path.write_text(file_contents) + + +@app.command() +def client_gen( + idl: Path = typer.Argument(..., help="Anchor IDL file path"), + out: Path = typer.Argument(..., help="Output directory."), + program_id: Optional[str] = typer.Option( + None, help="Optional program ID to be included in the code" + ), + pdas: bool = typer.Option( + False, "--pdas", help="Auto-generate PDAs where possible." + ), +): + """Generate Python client code from the specified anchor IDL.""" + idl_obj = Idl.from_json(idl.read_text()) + if program_id is None: + idl_metadata = idl_obj.metadata + address_from_idl = ( + idl_metadata["address"] if isinstance(idl_metadata, dict) else None + ) + if address_from_idl is None: + typer.echo( + "No program ID found in IDL. Use the --program-id " + "option to set it manually." + ) + raise typer.Exit(code=1) + else: + program_id_to_use = cast(str, address_from_idl) + else: + program_id_to_use = program_id + + typer.echo("generating package...") + out.mkdir(exist_ok=True) + (out / "__init__.py").touch() + typer.echo("generating program_id.py...") + gen_program_id(program_id_to_use, out) + typer.echo("generating errors.py...") + gen_errors(idl_obj, out) + typer.echo("generating instructions...") + gen_instructions(idl_obj, out, pdas) + typer.echo("generating types...") + gen_types(idl_obj, out) + typer.echo("generating accounts...") + gen_accounts(idl_obj, out) + + +if __name__ == "__main__": + app() diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/__init__.py b/basics/anchorpy-main/src/anchorpy/clientgen/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/accounts.py b/basics/anchorpy-main/src/anchorpy/clientgen/accounts.py new file mode 100644 index 0000000..3629989 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/clientgen/accounts.py @@ -0,0 +1,303 @@ +from pathlib import Path +from typing import cast + +from anchorpy_core.idl import ( + Idl, + IdlField, + IdlTypeDefinition, + IdlTypeDefinitionTyStruct, +) +from autoflake import fix_code +from black import FileMode, format_str +from genpy import ( + Assign, + Collection, + For, + FromImport, + If, + Import, + ImportAs, + Raise, + Return, + Statement, + Suite, +) +from pyheck import snake + +from anchorpy.clientgen.common import ( + _field_from_decoded, + _field_from_json, + _field_to_json, + _idl_type_to_json_type, + _json_interface_name, + _layout_for_type, + _py_type_from_idl, + _sanitize, +) +from anchorpy.clientgen.genpy_extension import ( + Call, + ClassMethod, + Continue, + Dataclass, + Method, + NamedArg, + StrDict, + StrDictEntry, + TypedDict, + TypedParam, +) +from anchorpy.coder.accounts import _account_discriminator + + +def gen_accounts(idl: Idl, root: Path) -> None: + accounts = idl.accounts + if accounts is None or not accounts: + return + accounts_dir = root / "accounts" + accounts_dir.mkdir(exist_ok=True) + gen_index_file(idl, accounts_dir) + accounts_dict = gen_accounts_code(idl, accounts_dir) + for path, code in accounts_dict.items(): + formatted = format_str(code, mode=FileMode()) + fixed = fix_code(formatted, remove_all_unused_imports=True) + path.write_text(fixed) + + +def gen_index_file(idl: Idl, accounts_dir: Path) -> None: + code = gen_index_code(idl) + formatted = format_str(code, mode=FileMode()) + (accounts_dir / "__init__.py").write_text(formatted) + + +def gen_index_code(idl: Idl) -> str: + imports: list[FromImport] = [] + for acc in idl.accounts: + acc_name = _sanitize(acc.name) + members = [ + acc_name, + _json_interface_name(acc_name), + ] + module_name = _sanitize(snake(acc.name)) + imports.append(FromImport(f".{module_name}", members)) + return str(Collection(imports)) + + +def gen_accounts_code(idl: Idl, accounts_dir: Path) -> dict[Path, str]: + res = {} + for acc in idl.accounts: + filename = f"{_sanitize(snake(acc.name))}.py" + path = accounts_dir / filename + code = gen_account_code(acc, idl) + res[path] = code + return res + + +def gen_account_code(acc: IdlTypeDefinition, idl: Idl) -> str: + base_imports = [ + Import("typing"), + FromImport("dataclasses", ["dataclass"]), + FromImport("construct", ["Construct"]), + FromImport("solders.pubkey", ["Pubkey"]), + FromImport("solana.rpc.async_api", ["AsyncClient"]), + FromImport("solana.rpc.commitment", ["Commitment"]), + ImportAs("borsh_construct", "borsh"), + FromImport("anchorpy.coder.accounts", ["ACCOUNT_DISCRIMINATOR_SIZE"]), + FromImport("anchorpy.error", ["AccountInvalidDiscriminator"]), + FromImport("anchorpy.utils.rpc", ["get_multiple_accounts"]), + FromImport( + "anchorpy.borsh_extension", ["BorshPubkey", "EnumForCodegen", "COption"] + ), + FromImport("..program_id", ["PROGRAM_ID"]), + ] + imports = ( + [*base_imports, FromImport("..", ["types"])] if idl.types else base_imports + ) + fields_interface_params: list[TypedParam] = [] + json_interface_params: list[TypedParam] = [] + ty = cast(IdlTypeDefinitionTyStruct, acc.ty) + fields = ty.fields + name = _sanitize(acc.name) + json_interface_name = _json_interface_name(name) + layout_items: list[str] = [] + init_body_assignments: list[Assign] = [] + decode_body_entries: list[NamedArg] = [] + to_json_entries: list[StrDictEntry] = [] + from_json_entries: list[NamedArg] = [] + for field in fields: + field_name = _sanitize(snake(field.name)) + fields_interface_params.append( + TypedParam( + field_name, + _py_type_from_idl( + idl=idl, + ty=field.ty, + types_relative_imports=False, + use_fields_interface_for_struct=False, + ), + ) + ) + json_interface_params.append( + TypedParam( + field_name, + _idl_type_to_json_type(ty=field.ty, types_relative_imports=False), + ) + ) + layout_items.append( + _layout_for_type( + idl=idl, ty=field.ty, name=field_name, types_relative_imports=False + ) + ) + init_body_assignments.append( + Assign(f"self.{field_name}", f'fields["{field_name}"]') + ) + decode_body_entries.append( + NamedArg( + field_name, + _field_from_decoded( + idl=idl, + ty=IdlField(name=snake(field.name), docs=None, ty=field.ty), + types_relative_imports=False, + val_prefix="dec.", + ), + ) + ) + to_json_entries.append( + StrDictEntry(field_name, _field_to_json(idl, field, "self.")) + ) + from_json_entries.append( + NamedArg( + field_name, + _field_from_json(idl=idl, ty=field, types_relative_imports=False), + ) + ) + json_interface = TypedDict(json_interface_name, json_interface_params) + discriminator_assignment = Assign( + "discriminator: typing.ClassVar", _account_discriminator(name) + ) + layout_assignment = Assign( + "layout: typing.ClassVar", f"borsh.CStruct({','.join(layout_items)})" + ) + fetch_method = ClassMethod( + "fetch", + [ + TypedParam("conn", "AsyncClient"), + TypedParam("address", "Pubkey"), + TypedParam("commitment", "typing.Optional[Commitment] = None"), + TypedParam("program_id", "Pubkey = PROGRAM_ID"), + ], + Suite( + [ + Assign( + "resp", + "await conn.get_account_info(address, commitment=commitment)", + ), + Assign("info", "resp.value"), + If("info is None", Return("None")), + If( + "info.owner != program_id", + Raise('ValueError("Account does not belong to this program")'), + ), + Assign("bytes_data", "info.data"), + Return("cls.decode(bytes_data)"), + ] + ), + f'typing.Optional["{name}"]', + is_async=True, + ) + account_does_not_belong_raise = Raise( + 'ValueError("Account does not belong to this program")' + ) + fetch_multiple_return_type = f'typing.List[typing.Optional["{name}"]]' + fetch_multiple_method = ClassMethod( + "fetch_multiple", + [ + TypedParam("conn", "AsyncClient"), + TypedParam("addresses", "list[Pubkey]"), + TypedParam("commitment", "typing.Optional[Commitment] = None"), + TypedParam("program_id", "Pubkey = PROGRAM_ID"), + ], + Suite( + [ + Assign( + "infos", + ( + "await get_multiple_accounts" + "(conn, addresses,commitment=commitment)" + ), + ), + Assign(f"res: {fetch_multiple_return_type}", "[]"), + For( + "info", + "infos", + Suite( + [ + If( + "info is None", + Suite([Statement("res.append(None)"), Continue()]), + ), + If( + "info.account.owner != program_id", + account_does_not_belong_raise, + ), + Statement("res.append(cls.decode(info.account.data))"), + ] + ), + ), + Return("res"), + ] + ), + f'typing.List[typing.Optional["{name}"]]', + is_async=True, + ) + decode_body_end = Call("cls", decode_body_entries) + account_invalid_raise = Raise( + 'AccountInvalidDiscriminator("The discriminator for this account is invalid")' + ) + decode_method = ClassMethod( + "decode", + [TypedParam("data", "bytes")], + Suite( + [ + If( + "data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator", + account_invalid_raise, + ), + Assign( + "dec", f"{name}.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])" + ), + Return(decode_body_end), + ] + ), + f'"{name}"', + ) + to_json_body = StrDict(to_json_entries) + to_json_method = Method("to_json", [], Return(to_json_body), json_interface_name) + from_json_body = Call("cls", from_json_entries) + from_json_method = ClassMethod( + "from_json", + [TypedParam("obj", json_interface_name)], + Return(from_json_body), + f'"{name}"', + ) + klass = Dataclass( + name, + [ + discriminator_assignment, + layout_assignment, + *fields_interface_params, + fetch_method, + fetch_multiple_method, + decode_method, + to_json_method, + from_json_method, + ], + ) + return str( + Collection( + [ + *imports, + json_interface, + klass, + ] + ) + ) diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/common.py b/basics/anchorpy-main/src/anchorpy/clientgen/common.py new file mode 100644 index 0000000..f12b268 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/clientgen/common.py @@ -0,0 +1,636 @@ +"""Code generation utilities.""" +import keyword +from typing import Optional + +from anchorpy_core.idl import ( + Idl, + IdlField, + IdlType, + IdlTypeArray, + IdlTypeDefined, + IdlTypeDefinitionTyStruct, + IdlTypeOption, + IdlTypeSimple, + IdlTypeVec, +) +from pyheck import snake + +_DEFAULT_DEFINED_TYPES_PREFIX = "types." + +INT_TYPES = { + IdlTypeSimple.U8, + IdlTypeSimple.I8, + IdlTypeSimple.U16, + IdlTypeSimple.I16, + IdlTypeSimple.U32, + IdlTypeSimple.I32, + IdlTypeSimple.U64, + IdlTypeSimple.I64, + IdlTypeSimple.U128, + IdlTypeSimple.I128, +} +FLOAT_TYPES = {IdlTypeSimple.F32, IdlTypeSimple.F64} +NUMBER_TYPES = INT_TYPES | FLOAT_TYPES + + +def _fields_interface_name(type_name: str) -> str: + return f"{type_name}Fields" + + +def _value_interface_name(type_name: str) -> str: + return f"{type_name}Value" + + +def _kind_interface_name(type_name: str) -> str: + return f"{type_name}Kind" + + +def _json_interface_name(type_name: str) -> str: + return f"{type_name}JSON" + + +def _sanitize(name: str) -> str: + return f"{name}_" if keyword.iskeyword(name) else name + + +def _py_type_from_idl( + idl: Idl, + ty: IdlType, + types_relative_imports: bool, + use_fields_interface_for_struct: bool, +) -> str: + if isinstance(ty, IdlTypeVec): + inner_type = _py_type_from_idl( + idl=idl, + ty=ty.vec, + types_relative_imports=types_relative_imports, + use_fields_interface_for_struct=use_fields_interface_for_struct, + ) + return f"list[{inner_type}]" + if isinstance(ty, IdlTypeOption): + inner_type = _py_type_from_idl( + idl=idl, + ty=ty.option, + types_relative_imports=types_relative_imports, + use_fields_interface_for_struct=use_fields_interface_for_struct, + ) + return f"typing.Optional[{inner_type}]" + if isinstance(ty, IdlTypeDefined): + defined = _sanitize(ty.defined) + filtered = [t for t in idl.types if _sanitize(t.name) == defined] + maybe_coption_split = defined.split("COption<") + if len(maybe_coption_split) == 2: + inner_type = {"u64": "int", "Pubkey": "Pubkey"}[maybe_coption_split[1][:-1]] + return f"typing.Optional[{inner_type}]" + if defined == "&'astr": + return "str" + defined_types_prefix = ( + "" if types_relative_imports else _DEFAULT_DEFINED_TYPES_PREFIX + ) + if len(filtered) != 1: + raise ValueError(f"Type not found {defined}") + typedef_type = filtered[0].ty + module = _sanitize(snake(ty.defined)) + if isinstance(typedef_type, IdlTypeDefinitionTyStruct): + name = ( + _fields_interface_name(ty.defined) + if use_fields_interface_for_struct + else defined + ) + else: + # enum + name = _kind_interface_name(ty.defined) + return f"{defined_types_prefix}{module}.{name}" + if isinstance(ty, IdlTypeArray): + inner_type = _py_type_from_idl( + idl=idl, + ty=ty.array[0], + types_relative_imports=types_relative_imports, + use_fields_interface_for_struct=use_fields_interface_for_struct, + ) + return f"list[{inner_type}]" + if ty in {IdlTypeSimple.Bool, IdlTypeSimple.Bytes}: + return str(ty).replace("IdlTypeSimple.", "").lower() + if ty in INT_TYPES: + return "int" + if ty in FLOAT_TYPES: + return "float" + if ty == IdlTypeSimple.String: + return "str" + if ty == IdlTypeSimple.PublicKey: + return "Pubkey" + raise ValueError(f"Unrecognized type: {ty}") + + +def _layout_for_type( + idl: Idl, + ty: IdlType, + types_relative_imports: bool, + name: Optional[str] = None, +) -> str: + if ty == IdlTypeSimple.PublicKey: + inner = "BorshPubkey" + elif isinstance(ty, IdlTypeSimple): + inner = str(ty).replace("IdlTypeSimple", "borsh") + elif isinstance(ty, IdlTypeVec): + layout = _layout_for_type( + idl=idl, ty=ty.vec, types_relative_imports=types_relative_imports + ) + cast_layout = f"typing.cast(Construct, {layout})" + inner = f"borsh.Vec({cast_layout})" + elif isinstance(ty, IdlTypeOption): + layout = _layout_for_type( + idl=idl, ty=ty.option, types_relative_imports=types_relative_imports + ) + inner = f"borsh.Option({layout})" + elif isinstance(ty, IdlTypeDefined): + defined = _sanitize(ty.defined) + maybe_coption_split = defined.split("COption<") + if len(maybe_coption_split) == 2: + layout_str = maybe_coption_split[1][:-1] + layout = {"u64": "borsh.U64", "Pubkey": "BorshPubkey"}[layout_str] + inner = f"COption({layout})" + elif defined == "&'astr": + return "borsh.String" + else: + filtered = [t for t in idl.types if _sanitize(t.name) == defined] + typedef_type = filtered[0].ty + defined_types_prefix = ( + "" if types_relative_imports else _DEFAULT_DEFINED_TYPES_PREFIX + ) + module = snake(defined) + inner = ( + f"{defined_types_prefix}{module}.{defined}.layout" + if isinstance(typedef_type, IdlTypeDefinitionTyStruct) + else f"{defined_types_prefix}{module}.layout" + ) + elif isinstance(ty, IdlTypeArray): + layout = _layout_for_type( + idl=idl, ty=ty.array[0], types_relative_imports=types_relative_imports + ) + inner = f"{layout}[{ty.array[1]}]" + else: + raise ValueError(f"Unrecognized type: {ty}") + + if name is None: + return inner + return f'"{name}" / {inner}' + + +def _maybe_none(to_check: str, if_not_none: str) -> str: + return f"(None if {to_check} is None else {if_not_none})" + + +def _field_to_encodable( + idl: Idl, + ty: IdlField, + types_relative_imports: bool, + val_prefix: str = "", + val_suffix: str = "", + convert_case: bool = True, +) -> str: + ty_type = ty.ty + maybe_converted = snake(ty.name) if convert_case else ty.name + ty_name = _sanitize(maybe_converted) + if isinstance(ty_type, IdlTypeVec): + map_body = _field_to_encodable( + idl=idl, + ty=IdlField("item", docs=None, ty=ty_type.vec), + val_prefix="", + types_relative_imports=types_relative_imports, + val_suffix="", + ) + # skip mapping when not needed + if map_body == "item": + return f"{val_prefix}{ty_name}{val_suffix}" + return f"list(map(lambda item: {map_body}, {val_prefix}{ty_name}{val_suffix}))" + if isinstance(ty_type, IdlTypeOption): + encodable = _field_to_encodable( + idl=idl, + ty=IdlField(ty_name, docs=None, ty=ty_type.option), + val_prefix=val_prefix, + types_relative_imports=types_relative_imports, + val_suffix=val_suffix, + convert_case=convert_case, + ) + if encodable == f"{val_prefix}{ty_name}{val_suffix}": + return encodable + return _maybe_none(f"{val_prefix}{ty_name}{val_suffix}", encodable) + if isinstance(ty_type, IdlTypeDefined): + defined = _sanitize(ty_type.defined) + maybe_coption_split = defined.split("COption<") + if len(maybe_coption_split) == 2: + inner_type = maybe_coption_split[1][:-1] + encodable = _field_to_encodable( + idl=idl, + ty=IdlField( + ty_name, + docs=None, + ty={"u64": IdlTypeSimple.U64, "Pubkey": IdlTypeSimple.PublicKey}[ + inner_type + ], + ), + val_prefix=val_prefix, + types_relative_imports=types_relative_imports, + val_suffix=val_suffix, + convert_case=convert_case, + ) + if encodable == f"{val_prefix}{ty_name}{val_suffix}": + return encodable + return _maybe_none(f"{val_prefix}{ty_name}{val_suffix}", encodable) + elif defined == "&'astr": + return f"{val_prefix}{ty_name}{val_suffix}" + filtered = [t for t in idl.types if _sanitize(t.name) == defined] + + if len(filtered) != 1: + raise ValueError(f"Type not found {defined}") + typedef_type = filtered[0].ty + if isinstance(typedef_type, IdlTypeDefinitionTyStruct): + val_full_name = f"{val_prefix}{ty_name}{val_suffix}" + return f"{val_full_name}.to_encodable()" + return f"{val_prefix}{ty_name}{val_suffix}.to_encodable()" + if isinstance(ty_type, IdlTypeArray): + map_body = _field_to_encodable( + idl=idl, + ty=IdlField("item", docs=None, ty=ty_type.array[0]), + val_prefix="", + types_relative_imports=types_relative_imports, + val_suffix="", + ) + # skip mapping when not needed + if map_body == "item": + return f"{val_prefix}{ty_name}{val_suffix}" + return f"list(map(lambda item: {map_body}, {val_prefix}{ty_name}{val_suffix}))" + if ty_type in { + IdlTypeSimple.Bool, + *NUMBER_TYPES, + IdlTypeSimple.String, + IdlTypeSimple.PublicKey, + IdlTypeSimple.Bytes, + }: + return f"{val_prefix}{ty_name}{val_suffix}" + raise ValueError(f"Unrecognized type: {ty_type}") + + +def _field_from_decoded( + idl: Idl, ty: IdlField, types_relative_imports: bool, val_prefix: str = "" +) -> str: + ty_type = ty.ty + ty_name = _sanitize(ty.name) + if isinstance(ty_type, IdlTypeVec): + map_body = _field_from_decoded( + idl=idl, + ty=IdlField("item", docs=None, ty=ty_type.vec), + val_prefix="", + types_relative_imports=types_relative_imports, + ) + # skip mapping when not needed + if map_body == "item": + return f"{val_prefix}{ty_name}" + return f"list(map(lambda item: {map_body}, {val_prefix}{ty_name}))" + if isinstance(ty_type, IdlTypeOption): + decoded = _field_from_decoded( + idl=idl, + ty=IdlField(ty_name, docs=None, ty=ty_type.option), + types_relative_imports=types_relative_imports, + val_prefix=val_prefix, + ) + # skip coercion when not needed + if decoded == f"{val_prefix}{ty_name}": + return decoded + return _maybe_none(f"{val_prefix}{ty_name}", decoded) + if isinstance(ty_type, IdlTypeDefined): + defined = _sanitize(ty_type.defined) + maybe_coption_split = defined.split("COption<") + if len(maybe_coption_split) == 2: + inner_type = maybe_coption_split[1][:-1] + decoded = _field_from_decoded( + idl=idl, + ty=IdlField( + ty_name, + docs=None, + ty={"u64": IdlTypeSimple.U64, "Pubkey": IdlTypeSimple.PublicKey}[ + inner_type + ], + ), + types_relative_imports=types_relative_imports, + val_prefix=val_prefix, + ) + # skip coercion when not needed + if decoded == f"{val_prefix}{ty_name}": + return decoded + return _maybe_none(f"{val_prefix}{ty_name}", decoded) + filtered = [t for t in idl.types if _sanitize(t.name) == defined] + if len(filtered) != 1: + raise ValueError(f"Type not found {defined}") + typedef_type = filtered[0].ty + from_decoded_func_path = ( + f"{snake(defined)}.{defined}" + if isinstance(typedef_type, IdlTypeDefinitionTyStruct) + else f"{snake(defined)}" + ) + defined_types_prefix = ( + "" if types_relative_imports else _DEFAULT_DEFINED_TYPES_PREFIX + ) + full_func_path = f"{defined_types_prefix}{from_decoded_func_path}" + from_decoded_arg = f"{val_prefix}{ty_name}" + return f"{full_func_path}.from_decoded({from_decoded_arg})" + if isinstance(ty_type, IdlTypeArray): + map_body = _field_from_decoded( + idl=idl, + ty=IdlField("item", docs=None, ty=ty_type.array[0]), + val_prefix="", + types_relative_imports=types_relative_imports, + ) + # skip mapping when not needed + if map_body == "item": + return f"{val_prefix}{ty_name}" + return f"list(map(lambda item: {map_body}, {val_prefix}{ty_name}))" + if ty_type in { + IdlTypeSimple.Bool, + *NUMBER_TYPES, + IdlTypeSimple.String, + IdlTypeSimple.PublicKey, + IdlTypeSimple.Bytes, + }: + return f"{val_prefix}{ty_name}" + raise ValueError(f"Unrecognized type: {ty_type}") + + +def _struct_field_initializer( + idl: Idl, + field: IdlField, + types_relative_imports: bool, + prefix: str = 'fields["', + suffix: str = '"]', +) -> str: + field_type = field.ty + field_name = _sanitize(snake(field.name)) + if isinstance(field_type, IdlTypeDefined): + defined = _sanitize(field_type.defined) + filtered = [t for t in idl.types if _sanitize(t.name) == defined] + if len(filtered) != 1: + raise ValueError(f"Type not found {defined}") + typedef_type = filtered[0].ty + if isinstance(typedef_type, IdlTypeDefinitionTyStruct): + module = snake(defined) + defined_types_prefix = ( + "" if types_relative_imports else _DEFAULT_DEFINED_TYPES_PREFIX + ) + obj_name = f"{defined_types_prefix}{module}.{defined}" + return f"{obj_name}(**{prefix}{field_name}{suffix})" + return f"{prefix}{field_name}{suffix}" + if isinstance(field_type, IdlTypeOption): + initializer = _struct_field_initializer( + idl=idl, + field=IdlField(field_name, docs=None, ty=field_type.option), + prefix=prefix, + suffix=suffix, + types_relative_imports=types_relative_imports, + ) + # skip coercion when not needed + if initializer == f"{prefix}{field_name}{suffix}": + return initializer + return _maybe_none(f"{prefix}{field_name}{suffix}", initializer) + if isinstance(field_type, IdlTypeArray): + map_body = _struct_field_initializer( + idl=idl, + field=IdlField("item", docs=None, ty=field_type.array[0]), + prefix="", + suffix="", + types_relative_imports=types_relative_imports, + ) + # skip mapping when not needed + if map_body == "item": + return f"{prefix}{field_name}{suffix}" + return f"list(map(lambda item: {map_body}, {prefix}{field_name}{suffix}))" + if isinstance(field_type, IdlTypeVec): + map_body = _struct_field_initializer( + idl=idl, + field=IdlField("item", docs=None, ty=field_type.vec), + prefix="", + suffix="", + types_relative_imports=types_relative_imports, + ) + # skip mapping when not needed + if map_body == "item": + return f"{prefix}{field_name}{suffix}" + return f"list(map(lambda item: {map_body}, {prefix}{field_name}{suffix}))" + if field_type in { + IdlTypeSimple.Bool, + *NUMBER_TYPES, + IdlTypeSimple.String, + IdlTypeSimple.PublicKey, + IdlTypeSimple.Bytes, + }: + return f"{prefix}{field_name}{suffix}" + raise ValueError(f"Unrecognized type: {field_type}") + + +def _field_to_json( + idl: Idl, + ty: IdlField, + val_prefix: str = "", + val_suffix: str = "", + convert_case: bool = True, +) -> str: + ty_type = ty.ty + maybe_converted = _sanitize(snake(ty.name)) if convert_case else _sanitize(ty.name) + var_name = f"{val_prefix}{maybe_converted}{val_suffix}" + if ty_type == IdlTypeSimple.PublicKey: + return f"str({var_name})" + if isinstance(ty_type, IdlTypeVec): + map_body = _field_to_json(idl, IdlField("item", docs=None, ty=ty_type.vec)) + # skip mapping when not needed + if map_body == "item": + return var_name + return f"list(map(lambda item: {map_body}, {var_name}))" + if isinstance(ty_type, IdlTypeArray): + map_body = _field_to_json(idl, IdlField("item", docs=None, ty=ty_type.array[0])) + # skip mapping when not needed + if map_body == "item": + return var_name + return f"list(map(lambda item: {map_body}, {var_name}))" + if isinstance(ty_type, IdlTypeOption): + value = _field_to_json( + idl, + IdlField(ty.name, docs=None, ty=ty_type.option), + val_prefix, + val_suffix, + convert_case=convert_case, + ) + # skip coercion when not needed + if value == var_name: + return value + return _maybe_none(var_name, value) + if isinstance(ty_type, IdlTypeDefined): + defined = ty_type.defined + filtered = [t for t in idl.types if t.name == defined] + maybe_coption_split = defined.split("COption<") + if len(maybe_coption_split) == 2: + inner_type = maybe_coption_split[1][:-1] + value = _field_to_json( + idl, + IdlField( + ty.name, + docs=None, + ty={"u64": IdlTypeSimple.U64, "Pubkey": IdlTypeSimple.PublicKey}[ + inner_type + ], + ), + val_prefix, + val_suffix, + convert_case=convert_case, + ) + # skip coercion when not needed + if value == var_name: + return value + return _maybe_none(var_name, value) + if len(filtered) != 1: + raise ValueError(f"Type not found {defined}") + return f"{var_name}.to_json()" + if ty_type == IdlTypeSimple.Bytes: + return f"list({var_name})" + if ty_type in { + IdlTypeSimple.Bool, + *NUMBER_TYPES, + IdlTypeSimple.String, + }: + return var_name + raise ValueError(f"Unrecognized type: {ty_type}") + + +def _idl_type_to_json_type(ty: IdlType, types_relative_imports: bool) -> str: + if isinstance(ty, IdlTypeVec): + inner = _idl_type_to_json_type( + ty=ty.vec, types_relative_imports=types_relative_imports + ) + return f"list[{inner}]" + if isinstance(ty, IdlTypeArray): + inner = _idl_type_to_json_type( + ty=ty.array[0], types_relative_imports=types_relative_imports + ) + return f"list[{inner}]" + if isinstance(ty, IdlTypeOption): + inner = _idl_type_to_json_type( + ty=ty.option, types_relative_imports=types_relative_imports + ) + return f"typing.Optional[{inner}]" + if isinstance(ty, IdlTypeDefined): + defined = ty.defined + maybe_coption_split = defined.split("COption<") + if len(maybe_coption_split) == 2: + inner_type = {"u64": "int", "Pubkey": "str"}[maybe_coption_split[1][:-1]] + return f"typing.Optional[{inner_type}]" + defined_types_prefix = ( + "" if types_relative_imports else _DEFAULT_DEFINED_TYPES_PREFIX + ) + module = _sanitize(snake(defined)) + return f"{defined_types_prefix}{module}.{_json_interface_name(defined)}" + if ty == IdlTypeSimple.Bool: + return "bool" + if ty in INT_TYPES: + return "int" + if ty in FLOAT_TYPES: + return "float" + if ty == IdlTypeSimple.Bytes: + return "list[int]" + if ty in {IdlTypeSimple.String, IdlTypeSimple.PublicKey}: + return "str" + raise ValueError(f"Unrecognized type: {ty}") + + +def _field_from_json( + idl: Idl, + ty: IdlField, + types_relative_imports: bool, + param_prefix: str = 'obj["', + param_suffix: str = '"]', +) -> str: + ty_type = ty.ty + ty_name_snake_unsanitized = snake(ty.name) + ty_name = _sanitize(ty_name_snake_unsanitized) + var_name = f"{param_prefix}{ty_name_snake_unsanitized}{param_suffix}" + if ty_type == IdlTypeSimple.PublicKey: + return f"Pubkey.from_string({var_name})" + if isinstance(ty_type, IdlTypeVec): + map_body = _field_from_json( + idl=idl, + ty=IdlField("item", docs=None, ty=ty_type.vec), + param_prefix="", + param_suffix="", + types_relative_imports=types_relative_imports, + ) + # skip mapping when not needed + if map_body == "item": + return var_name + return f"list(map(lambda item: {map_body}, {var_name}))" + if isinstance(ty_type, IdlTypeArray): + map_body = _field_from_json( + idl=idl, + ty=IdlField("item", docs=None, ty=ty_type.array[0]), + param_prefix="", + param_suffix="", + types_relative_imports=types_relative_imports, + ) + # skip mapping when not needed + if map_body == "item": + return var_name + return f"list(map(lambda item: {map_body}, {var_name}))" + if isinstance(ty_type, IdlTypeOption): + inner = _field_from_json( + idl=idl, + ty=IdlField(ty_name, docs=None, ty=ty_type.option), + param_prefix=param_prefix, + param_suffix=param_suffix, + types_relative_imports=types_relative_imports, + ) + # skip coercion when not needed + if inner == var_name: + return inner + return _maybe_none(var_name, inner) + if isinstance(ty_type, IdlTypeDefined): + from_json_arg = var_name + defined = _sanitize(ty_type.defined) + maybe_coption_split = defined.split("COption<") + if len(maybe_coption_split) == 2: + inner_type = maybe_coption_split[1][:-1] + inner = _field_from_json( + idl=idl, + ty=IdlField( + ty_name, + docs=None, + ty={"u64": IdlTypeSimple.U64, "Pubkey": IdlTypeSimple.PublicKey}[ + inner_type + ], + ), + param_prefix=param_prefix, + param_suffix=param_suffix, + types_relative_imports=types_relative_imports, + ) + # skip coercion when not needed + if inner == var_name: + return inner + return _maybe_none(var_name, inner) + defined_snake = _sanitize(snake(ty_type.defined)) + filtered = [t for t in idl.types if _sanitize(t.name) == defined] + typedef_type = filtered[0].ty + from_json_func_path = ( + f"{defined_snake}.{defined}" + if isinstance(typedef_type, IdlTypeDefinitionTyStruct) + else f"{defined_snake}" + ) + defined_types_prefix = ( + "" if types_relative_imports else _DEFAULT_DEFINED_TYPES_PREFIX + ) + full_func_path = f"{defined_types_prefix}{from_json_func_path}" + return f"{full_func_path}.from_json({from_json_arg})" + if ty_type == IdlTypeSimple.Bytes: + return f"bytes({var_name})" + if ty_type in { + IdlTypeSimple.Bool, + *NUMBER_TYPES, + IdlTypeSimple.String, + }: + return var_name + raise ValueError(f"Unrecognized type: {ty_type}") diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/errors.py b/basics/anchorpy-main/src/anchorpy/clientgen/errors.py new file mode 100644 index 0000000..a16accf --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/clientgen/errors.py @@ -0,0 +1,245 @@ +from pathlib import Path + +from anchorpy_core.idl import Idl, IdlErrorCode +from autoflake import fix_code +from black import FileMode, format_str +from genpy import ( + Assign, + Collection, + FromImport, + If, + Import, + Return, + Statement, + Suite, +) +from genpy import Function as UntypedFunction + +from anchorpy.clientgen.common import _sanitize +from anchorpy.clientgen.genpy_extension import ( + Class, + Function, + InitMethod, + IntDict, + IntDictEntry, + TypedParam, + Union, +) +from anchorpy.error import LangErrorMessage, _LangErrorCode + + +def gen_from_code_fn(has_custom_errors: bool) -> Function: + from_code_body = Return( + "custom.from_code(code) if code >= 6000 else anchor.from_code(code)" + if has_custom_errors + else "anchor.from_code(code)" + ) + from_code_return_type = ( + Union(["custom.CustomError", "anchor.AnchorError", "None"]) + if has_custom_errors + else "typing.Optional[anchor.AnchorError]" + ) + return Function( + "from_code", + [TypedParam("code", "int")], + from_code_body, + str(from_code_return_type), + ) + + +def gen_from_tx_error_fn(has_custom_errors: bool) -> Function: + err_info_assign = Assign("err_info", "error.args[0]") + err_code_assign = Assign("extracted", "extract_code_and_logs(err_info, PROGRAM_ID)") + null_code_check = If("extracted is None", Return(None)) + final_return = Return("from_code(extracted[0])") + fn_body = Suite( + [ + err_info_assign, + err_code_assign, + null_code_check, + final_return, + ] + ) + return_type = ( + "typing.Union[anchor.AnchorError, custom.CustomError, None]" + if has_custom_errors + else "typing.Optional[anchor.AnchorError]" + ) + return Function( + "from_tx_error", + [TypedParam("error", "RPCException")], + fn_body, + return_type, + ) + + +def gen_custom_errors_code(errors: list[IdlErrorCode]) -> str: + typing_import = Import("typing") + error_import = FromImport( + "anchorpy.error", ["ProgramError", "extract_code_and_logs"] + ) + error_names: list[str] = [] + classes: list[Class] = [] + error_map_entries: list[IntDictEntry] = [] + for error in errors: + code = error.code + name = _sanitize(error.name) + maybe_msg = error.msg + msg = None if maybe_msg is None else f'"{maybe_msg}"' + init_body = Statement(f"super().__init__({code}, {msg})") + attrs = [ + InitMethod([], init_body), + Assign("code", code), + Assign("name", f'"{name}"'), + Assign("msg", msg), + ] + klass = Class(name=name, bases=["ProgramError"], attributes=attrs) + classes.append(klass) + error_names.append(name) + error_map_entries.append(IntDictEntry(code, f"{name}()")) + type_alias = Assign("CustomError", Union(error_names)) + error_map = Assign( + "CUSTOM_ERROR_MAP: dict[int, CustomError]", IntDict(error_map_entries) + ) + from_code_body = Suite( + [ + Assign("maybe_err", "CUSTOM_ERROR_MAP.get(code)"), + If("maybe_err is None", Return("None")), + Return("maybe_err"), + ] + ) + from_code_fn = Function( + "from_code", + [TypedParam("code", "int")], + from_code_body, + "typing.Optional[CustomError]", + ) + return str( + Collection( + [typing_import, error_import, *classes, type_alias, error_map, from_code_fn] + ) + ) + + +def gen_custom_errors(idl: Idl, errors_dir: Path) -> None: + errors = idl.errors + if errors is None or not errors: + return + code = gen_custom_errors_code(errors) + formatted = format_str(code, mode=FileMode()) + fixed = fix_code(formatted, remove_all_unused_imports=True) + (errors_dir / "custom.py").with_suffix(".py").write_text(fixed) + + +def gen_anchor_errors_code() -> str: + typing_import = Import("typing") + error_import = FromImport("anchorpy.error", ["ProgramError"]) + error_names: list[str] = [] + classes: list[Class] = [] + error_map_entries: list[IntDictEntry] = [] + for variant in _LangErrorCode: + name = _sanitize(variant.name) + code = variant.value + maybe_msg = LangErrorMessage.get(variant) + msg = None if maybe_msg is None else f'"{maybe_msg}"' + init_body = Statement(f"super().__init__({code}, {msg})") + attrs = [ + UntypedFunction("__init__", ["self"], init_body), + Assign("code", code), + Assign("name", f'"{name}"'), + Assign("msg", msg), + ] + klass = Class(name=name, bases=["ProgramError"], attributes=attrs) + classes.append(klass) + error_names.append(name) + error_map_entries.append(IntDictEntry(code, f"{name}()")) + type_alias = Assign("AnchorError", Union(error_names)) + error_map = Assign( + "ANCHOR_ERROR_MAP: dict[int, AnchorError]", + IntDict(error_map_entries), + ) + from_code_body = Suite( + [ + Assign("maybe_err", "ANCHOR_ERROR_MAP.get(code)"), + If("maybe_err is None", Return("None")), + Return("maybe_err"), + ] + ) + from_code_fn = Function( + "from_code", + [TypedParam("code", "int")], + from_code_body, + "typing.Optional[AnchorError]", + ) + return str( + Collection( + [typing_import, error_import, *classes, type_alias, error_map, from_code_fn] + ) + ) + + +def gen_anchor_errors(errors_dir: Path) -> None: + code = gen_anchor_errors_code() + formatted = format_str(code, mode=FileMode()) + (errors_dir / "anchor").with_suffix(".py").write_text(formatted) + + +def gen_index_code(idl: Idl) -> str: + has_custom_errors = bool(idl.errors) + typing_import = Import("typing") + rpc_exception_import = FromImport("solana.rpc.core", ["RPCException"]) + tx_status_import = FromImport( + "solders.transaction_status", + ["InstructionErrorCustom", "TransactionErrorInstructionError"], + ) + preflight_error_import = FromImport( + "solders.rpc.errors", ["SendTransactionPreflightFailureMessage"] + ) + extract_code_and_logs_import = FromImport( + "anchorpy.error", ["extract_code_and_logs"] + ) + program_id_import = FromImport("..program_id", ["PROGRAM_ID"]) + anchor_import = FromImport(".", ["anchor"]) + re_import = Import("re") + base_import_lines = [ + typing_import, + re_import, + tx_status_import, + rpc_exception_import, + preflight_error_import, + extract_code_and_logs_import, + program_id_import, + anchor_import, + ] + custom_import_lines = [FromImport(".", ["custom"])] if has_custom_errors else [] + import_lines = base_import_lines + custom_import_lines + from_code_fn = gen_from_code_fn(has_custom_errors) + error_re_line = Assign( + "error_re", r're.compile(r"Program (\w+) failed: custom program error: (\w+)")' + ) + from_tx_error_fn = gen_from_tx_error_fn(has_custom_errors) + return str( + Collection( + [ + *import_lines, + from_code_fn, + error_re_line, + from_tx_error_fn, + ] + ) + ) + + +def gen_index_file(idl: Idl, errors_dir: Path) -> None: + code = gen_index_code(idl) + path = errors_dir / "__init__.py" + formatted = format_str(code, mode=FileMode()) + path.write_text(formatted) + + +def gen_errors(idl: Idl, root: Path) -> None: + errors_dir = root / "errors" + errors_dir.mkdir(exist_ok=True) + gen_index_file(idl, errors_dir) + gen_custom_errors(idl, errors_dir) + gen_anchor_errors(errors_dir) diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/genpy_extension.py b/basics/anchorpy-main/src/anchorpy/clientgen/genpy_extension.py new file mode 100644 index 0000000..40c140a --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/clientgen/genpy_extension.py @@ -0,0 +1,239 @@ +from typing import Iterator, Optional +from typing import Union as TypingUnion + +from genpy import ( + Assign, + FromImport, + Generable, + Suite, +) +from genpy import Class as BrokenClass +from genpy import Function as FunctionOriginal + + +class Class(BrokenClass): + def generate(self) -> Iterator[str]: + bases = self.bases + if not bases: + bases = [] + + yield "class {}({}):".format(self.name, ", ".join(bases)) + if self.attributes: + for f in self.attributes: + yield from (" " + f_line for f_line in f.generate()) + else: + yield " pass" + + +class TypedParam(Generable): + def __init__(self, name: str, type_: Optional[str]) -> None: + self.name = name + self.type = type_ + + def generate(self) -> Iterator[str]: + if self.type is None: + yield self.name + else: + yield f"{self.name}: {self.type}" + + +class Break(Generable): + def generate(self): + yield "break" + + +class Continue(Generable): + def generate(self): + yield "continue" + + +class Union(Generable): + def __init__(self, members: list[str]) -> None: + self.members = members + + def generate(self) -> Iterator[str]: + joined = ",".join(self.members) + yield f"typing.Union[{joined}]" + + +class Tuple(Generable): + def __init__(self, members: list[str]) -> None: + self.members = members + + def generate(self) -> Iterator[str]: + joined = ",".join(self.members) + yield f"({joined},)" + + +class List(Generable): + def __init__(self, members: list[str]) -> None: + self.members = members + + def generate(self) -> Iterator[str]: + joined = ",".join(self.members) + yield f"[{joined}]" + + +class TupleTypeAlias(Generable): + def __init__(self, name: str, members: list[str]) -> None: + self.name = name + self.members = members + + def generate(self) -> Iterator[str]: + yield str(Assign(self.name, f"tuple{List(self.members)}")) + + +class StrDictEntry(Generable): + def __init__(self, key: str, val: TypingUnion[str, "StrDict"]) -> None: + self.key = key + self.val = val + + def generate(self) -> Iterator[str]: + yield f'"{self.key}": {self.val},' + + +class NamedArg(Generable): + def __init__(self, key: str, val: str) -> None: + self.key = key + self.val = val + + def generate(self) -> Iterator[str]: + yield f"{self.key}={self.val}," + + +class Call(Generable): + def __init__(self, func: str, args: list[NamedArg]) -> None: + self.func = func + self.args = args + + def generate(self) -> Iterator[str]: + formatted_args = "".join(str(arg) for arg in self.args) + yield f"{self.func}({formatted_args})" + + +class StrDict(Generable): + def __init__(self, items: list[StrDictEntry]) -> None: + self.items = items + + def generate(self) -> Iterator[str]: + formatted_items = "".join(str(item) for item in self.items) + yield "{" + formatted_items + "}" + + +class IntDictEntry(Generable): + def __init__(self, key: int, val: str) -> None: + self.key = key + self.val = val + + def generate(self) -> Iterator[str]: + yield f"{self.key}: {self.val}," + + +class IntDict(Generable): + def __init__(self, items: list[IntDictEntry]) -> None: + self.items = items + + def generate(self) -> Iterator[str]: + formatted_items = "".join(str(item) for item in self.items) + yield "{" + formatted_items + "}" + + +class Function(FunctionOriginal): + def __init__( + self, + name: str, + args: list[TypedParam], + body: Generable, + return_type: str, + decorators: tuple[str, ...] = (), + is_async: bool = False, + ) -> None: + super().__init__(name, args, body, decorators) + self.return_type = return_type + self.is_async = is_async + + def generate(self) -> Iterator[str]: + yield from self.decorators + arg_strings = [] + for arg in self.args: + annotation = "" if arg.type is None else f": {arg.type}" + arg_strings.append(f"{arg.name}{annotation}") + def_base = "async def" if self.is_async else "def" + yield "{} {}({}) -> {}:".format( + def_base, self.name, ", ".join(arg_strings), self.return_type + ) + yield from self.body.generate() + + +class StaticMethod(Function): + def __init__( + self, name: str, args: list[TypedParam], body: Generable, return_type: str + ) -> None: + super().__init__(name, args, body, return_type, ("@staticmethod",)) + + +class ClassMethod(Function): + def __init__( + self, + name: str, + extra_args: list[TypedParam], + body: Generable, + return_type: str, + is_async: bool = False, + ) -> None: + args = [TypedParam("cls", None), *extra_args] + super().__init__(name, args, body, return_type, ("@classmethod",), is_async) + + +class Method(Function): + def __init__( + self, name: str, extra_args: list[TypedParam], body: Generable, return_type: str + ) -> None: + args = [TypedParam("self", None), *extra_args] + super().__init__(name, args, body, return_type) + + +class InitMethod(Method): + def __init__(self, extra_args: list[TypedParam], body: Generable) -> None: + super().__init__("__init__", extra_args, body, "None") + + +class Dataclass(Class): + def __init__( + self, + name, + attributes: list[TypingUnion[TypedParam, Assign, ClassMethod, Method]], + ) -> None: + super().__init__(name, None, attributes) + + def generate(self) -> Iterator[str]: + yield "@dataclass" + yield from super().generate() + + +class TypedDict(Class): + def __init__(self, name, params: list[TypedParam]) -> None: + super().__init__(name, ["typing.TypedDict"], params) + + def generate(self) -> Iterator[str]: + yield from super().generate() + + +class Try(Generable): + def __init__(self, try_body, to_catch, except_body): + if not isinstance(try_body, Suite): + try_body = Suite(try_body) + if not isinstance(except_body, Suite): + except_body = Suite(except_body) + self.try_body = try_body + self.to_catch = to_catch + self.except_body = except_body + + def generate(self): + yield "try:" + yield from self.try_body.generate() + yield f"except {self.to_catch}:" + yield from self.except_body.generate() + + +ANNOTATIONS_IMPORT = FromImport("__future__", ["annotations"]) diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/instructions.py b/basics/anchorpy-main/src/anchorpy/clientgen/instructions.py new file mode 100644 index 0000000..7c47eea --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/clientgen/instructions.py @@ -0,0 +1,363 @@ +from pathlib import Path +from typing import Optional, Union, cast + +from anchorpy_core.idl import ( + Idl, + IdlAccountItem, + IdlAccounts, + IdlSeedConst, + IdlTypeArray, + IdlTypeSimple, +) +from autoflake import fix_code +from black import FileMode, format_str +from genpy import ( + Assign, + Collection, + FromImport, + If, + Import, + ImportAs, + Line, + Return, + Suite, +) +from pyheck import shouty_snake, snake, upper_camel + +from anchorpy.clientgen.common import ( + _field_to_encodable, + _layout_for_type, + _py_type_from_idl, + _sanitize, +) +from anchorpy.clientgen.genpy_extension import ( + ANNOTATIONS_IMPORT, + Call, + Function, + List, + NamedArg, + StrDict, + StrDictEntry, + TypedDict, + TypedParam, +) +from anchorpy.coder.common import _sighash +from anchorpy.coder.idl import FIELD_TYPE_MAP + +CONST_ACCOUNTS = { + "associated_token_program": "ASSOCIATED_TOKEN_PROGRAM_ID", + "rent": "RENT", + "system_program": "SYS_PROGRAM_ID", + "token_program": "TOKEN_PROGRAM_ID", + "clock": "CLOCK", +} + + +def gen_instructions(idl: Idl, root: Path, gen_pdas: bool) -> None: + instructions_dir = root / "instructions" + instructions_dir.mkdir(exist_ok=True) + gen_index_file(idl, instructions_dir) + instructions = gen_instructions_code(idl, instructions_dir, gen_pdas) + for path, code in instructions.items(): + formatted = format_str(code, mode=FileMode()) + fixed = fix_code(formatted, remove_all_unused_imports=True) + path.write_text(fixed) + + +def gen_index_file(idl: Idl, instructions_dir: Path) -> None: + code = gen_index_code(idl) + path = instructions_dir / "__init__.py" + formatted = format_str(code, mode=FileMode()) + path.write_text(formatted) + + +def gen_index_code(idl: Idl) -> str: + imports: list[FromImport] = [] + for ix in idl.instructions: + ix_name_snake_unsanitized = snake(ix.name) + ix_name = _sanitize(ix_name_snake_unsanitized) + import_members: list[str] = [ix_name] + if ix.args: + import_members.append(_args_interface_name(ix_name_snake_unsanitized)) + if ix.accounts: + import_members.append(_accounts_interface_name(ix_name_snake_unsanitized)) + if import_members: + imports.append(FromImport(f".{ix_name}", import_members)) + return str(Collection(imports)) + + +def _args_interface_name(ix_name: str) -> str: + return f"{upper_camel(ix_name)}Args" + + +def _accounts_interface_name(ix_name: str) -> str: + return f"{upper_camel(ix_name)}Accounts" + + +def recurse_accounts( + accs: list[IdlAccountItem], + nested_names: list[str], + const_accs: dict[int, str], + acc_idx: int = 0, +) -> tuple[list[str], int]: + elements: list[str] = [] + for acc in accs: + names = [*nested_names, _sanitize(snake(acc.name))] + if isinstance(acc, IdlAccounts): + nested_accs = cast(IdlAccounts, acc) + new_elements, acc_idx = recurse_accounts( + nested_accs.accounts, names, const_accs, acc_idx + ) + elements.extend(new_elements) + else: + acc_idx += 1 + try: + pubkey_var = const_accs[acc_idx] + except KeyError: + try: + pubkey_var = CONST_ACCOUNTS[names[-1]] + except KeyError: + nested_keys = [f'["{key}"]' for key in names] + dict_accessor = "".join(nested_keys) + pubkey_var = f"accounts{dict_accessor}" + if acc.is_optional: + elements.append( + f"AccountMeta(pubkey={pubkey_var}, " + f"is_signer={acc.is_signer}, " + f"is_writable={acc.is_mut}) " + f"if {pubkey_var} else " + f"AccountMeta(pubkey=program_id, " + f"is_signer=False, is_writable=False)" + ) + else: + elements.append( + f"AccountMeta(pubkey={pubkey_var}, " + f"is_signer={acc.is_signer}, " + f"is_writable={acc.is_mut})" + ) + return elements, acc_idx + + +def to_buffer_value( + ty: Union[IdlTypeSimple, IdlTypeArray], value: Union[str, int, list[int]] +) -> bytes: + if isinstance(value, int): + encoder = FIELD_TYPE_MAP[cast(IdlTypeSimple, ty)] + return encoder.build(value) + if isinstance(value, str): + return value.encode() + if isinstance(value, list): + return bytes(value) + raise ValueError(f"Unexpected type. ty: {ty}; value: {value}") + + +GenAccountsRes = tuple[list[TypedDict], list[Assign], dict[int, str], int] + + +def gen_accounts( + name, + idl_accs: list[IdlAccountItem], + gen_pdas: bool, + accum: Optional[GenAccountsRes] = None, +) -> GenAccountsRes: + if accum is None: + extra_typeddicts_to_use: list[TypedDict] = [] + accum_const_pdas: list[Assign] = [] + const_acc_indices: dict[int, str] = {} + acc_count = 0 + else: + extra_typeddicts_to_use, accum_const_pdas, const_acc_indices, acc_count = accum + params: list[TypedParam] = [] + const_pdas: list[Assign] = [] + for acc in idl_accs: + acc_name = _sanitize(snake(acc.name)) + if isinstance(acc, IdlAccounts): + nested_accs = cast(IdlAccounts, acc) + nested_acc_name = f"{upper_camel(nested_accs.name)}Nested" + nested_res = gen_accounts( + nested_acc_name, + nested_accs.accounts, + gen_pdas, + ( + extra_typeddicts_to_use, + accum_const_pdas, + const_acc_indices, + acc_count, + ), + ) + if nested_res[0]: + params.append(TypedParam(acc_name, f"{nested_acc_name}")) + extra_typeddicts_to_use = extra_typeddicts_to_use + nested_res[0] + accum_const_pdas = accum_const_pdas + nested_res[1] + const_acc_indices = const_acc_indices | nested_res[2] + acc_count = nested_res[3] + 1 + else: + acc_count += 1 + pda_generated = False + if gen_pdas: + maybe_pda = acc.pda + if maybe_pda is not None and all( + isinstance(seed, IdlSeedConst) for seed in maybe_pda.seeds + ): + seeds = cast(list[IdlSeedConst], maybe_pda.seeds) + const_pda_name = shouty_snake(f"{name}_{acc_name}") + const_pda_body_items = [ + str( + to_buffer_value( + cast(Union[IdlTypeSimple, IdlTypeArray], seed.ty), + cast(Union[str, int, list[int]], seed.value), + ) + ) + for seed in seeds + ] + seeds_arg = List(const_pda_body_items) + seeds_named_arg = NamedArg("seeds", seeds_arg) + const_pda_body = Call( + "Pubkey.find_program_address", + [seeds_named_arg, NamedArg("program_id", "PROGRAM_ID")], + ) + const_pdas.append(Assign(const_pda_name, f"{const_pda_body}[0]")) + const_acc_indices = { + **const_acc_indices, + acc_count: const_pda_name, + } + pda_generated = True + if not pda_generated: + try: + CONST_ACCOUNTS[acc_name] + except KeyError: + if acc.is_optional: + params.append(TypedParam(acc_name, "typing.Optional[Pubkey]")) + else: + params.append(TypedParam(acc_name, "Pubkey")) + maybe_typed_dict_container = [TypedDict(name, params)] if params else [] + accounts = maybe_typed_dict_container + extra_typeddicts_to_use + return accounts, accum_const_pdas + const_pdas, const_acc_indices, acc_count + + +def gen_instructions_code(idl: Idl, out: Path, gen_pdas: bool) -> dict[Path, str]: + types_import = [FromImport("..", ["types"])] if idl.types else [] + imports = [ + ANNOTATIONS_IMPORT, + Import("typing"), + FromImport("solders.pubkey", ["Pubkey"]), + FromImport("solders.system_program", ["ID as SYS_PROGRAM_ID"]), + FromImport("solders.sysvar", ["RENT", "CLOCK"]), + FromImport( + "spl.token.constants", ["TOKEN_PROGRAM_ID", "ASSOCIATED_TOKEN_PROGRAM_ID"] + ), + FromImport("solders.instruction", ["Instruction", "AccountMeta"]), + FromImport( + "anchorpy.borsh_extension", ["BorshPubkey", "EnumForCodegen", "COption"] + ), + FromImport("construct", ["Pass", "Construct"]), + ImportAs("borsh_construct", "borsh"), + *types_import, + FromImport("..program_id", ["PROGRAM_ID"]), + ] + result = {} + for ix in idl.instructions: + ix_name_snake_unsanitized = snake(ix.name) + ix_name = _sanitize(ix_name_snake_unsanitized) + filename = (out / ix_name).with_suffix(".py") + args_interface_params: list[TypedParam] = [] + layout_items: list[str] = [] + encoded_args_entries: list[StrDictEntry] = [] + accounts_interface_name = _accounts_interface_name(ix_name_snake_unsanitized) + for arg in ix.args: + arg_name = _sanitize(snake(arg.name)) + args_interface_params.append( + TypedParam( + arg_name, + _py_type_from_idl( + idl=idl, + ty=arg.ty, + types_relative_imports=False, + use_fields_interface_for_struct=False, + ), + ) + ) + layout_items.append( + _layout_for_type( + idl=idl, ty=arg.ty, name=arg_name, types_relative_imports=False + ) + ) + encoded_args_entries.append( + StrDictEntry( + arg_name, + _field_to_encodable( + idl=idl, + ty=arg, + types_relative_imports=False, + val_prefix='args["', + val_suffix='"]', + ), + ) + ) + if ix.args: + args_interface_name = _args_interface_name(ix_name) + args_interface_container = [ + TypedDict(args_interface_name, args_interface_params) + ] + layout_val = f"borsh.CStruct({','.join(layout_items)})" + layout_assignment_container = [Assign("layout", layout_val)] + args_container = [TypedParam("args", args_interface_name)] + encoded_args_val = f"layout.build({StrDict(encoded_args_entries)})" + else: + args_interface_container = [] + layout_val = "Pass" + args_container = [] + layout_assignment_container = [] + encoded_args_val = 'b""' + accounts_container = ( + [TypedParam("accounts", accounts_interface_name)] if ix.accounts else [] + ) + accounts, const_pdas, const_acc_indices, _ = gen_accounts( + accounts_interface_name, ix.accounts, gen_pdas + ) + recursed = recurse_accounts(ix.accounts, [], const_acc_indices)[0] + keys_assignment = Assign("keys: list[AccountMeta]", f"{List(recursed)}") + remaining_accounts_concatenation = If( + "remaining_accounts is not None", Line("keys += remaining_accounts") + ) + identifier_assignment = Assign( + "identifier", _sighash(ix_name_snake_unsanitized) + ) + encoded_args_assignment = Assign("encoded_args", encoded_args_val) + data_assignment = Assign("data", "identifier + encoded_args") + returning = Return("Instruction(program_id, data, keys)") + ix_fn = Function( + ix_name, + [ + *args_container, + *accounts_container, + TypedParam("program_id", "Pubkey = PROGRAM_ID"), + TypedParam( + "remaining_accounts", + "typing.Optional[typing.List[AccountMeta]] = None", + ), + ], + Suite( + [ + keys_assignment, + remaining_accounts_concatenation, + identifier_assignment, + encoded_args_assignment, + data_assignment, + returning, + ] + ), + "Instruction", + ) + contents = Collection( + [ + *imports, + *args_interface_container, + *layout_assignment_container, + *const_pdas, + *accounts, + ix_fn, + ] + ) + result[filename] = str(contents) + return result diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/program_id.py b/basics/anchorpy-main/src/anchorpy/clientgen/program_id.py new file mode 100644 index 0000000..770aafe --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/clientgen/program_id.py @@ -0,0 +1,16 @@ +from pathlib import Path + +from black import FileMode, format_str +from genpy import Assign, Collection, FromImport + + +def gen_program_id_code(program_id: str) -> str: + import_line = FromImport("solders.pubkey", ["Pubkey"]) + assignment_line = Assign("PROGRAM_ID", f'Pubkey.from_string("{program_id}")') + return str(Collection([import_line, assignment_line])) + + +def gen_program_id(program_id: str, root: Path) -> None: + code = gen_program_id_code(program_id) + formatted = format_str(code, mode=FileMode()) + (root / "program_id.py").write_text(formatted) diff --git a/basics/anchorpy-main/src/anchorpy/clientgen/types.py b/basics/anchorpy-main/src/anchorpy/clientgen/types.py new file mode 100644 index 0000000..fa70033 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/clientgen/types.py @@ -0,0 +1,623 @@ +from dataclasses import dataclass +from pathlib import Path +from typing import Union as TypingUnion +from typing import cast + +from anchorpy_core.idl import ( + Idl, + IdlEnumVariant, + IdlField, + IdlType, + IdlTypeDefinitionTyStruct, +) +from autoflake import fix_code +from black import FileMode, format_str +from genpy import ( + Assign, + Collection, + FromImport, + Generable, + If, + Import, + ImportAs, + Raise, + Return, + Suite, +) +from pyheck import snake + +from anchorpy.clientgen.common import ( + _field_from_decoded, + _field_from_json, + _field_to_encodable, + _field_to_json, + _idl_type_to_json_type, + _json_interface_name, + _kind_interface_name, + _layout_for_type, + _py_type_from_idl, + _sanitize, + _value_interface_name, +) +from anchorpy.clientgen.genpy_extension import ( + ANNOTATIONS_IMPORT, + Call, + ClassMethod, + Dataclass, + Function, + Method, + NamedArg, + StrDict, + StrDictEntry, + Tuple, + TupleTypeAlias, + TypedDict, + TypedParam, + Union, +) + + +def gen_types(idl: Idl, root: Path) -> None: + types = idl.types + if types is None or not types: + return + types_dir = root / "types" + types_dir.mkdir(exist_ok=True) + gen_index_file(idl, types_dir) + gen_type_files(idl, types_dir) + + +def gen_index_file(idl: Idl, types_dir: Path) -> None: + code = gen_index_code(idl) + path = types_dir / "__init__.py" + formatted = format_str(code, mode=FileMode()) + path.write_text(formatted) + + +def gen_index_code(idl: Idl) -> str: + imports: list[TypingUnion[Import, FromImport]] = [Import("typing")] + for ty in idl.types: + ty_type = ty.ty + module_name = _sanitize(snake(ty.name)) + imports.append(FromImport(".", [module_name])) + import_members = ( + [_sanitize(ty.name), _json_interface_name(ty.name)] + if isinstance(ty_type, IdlTypeDefinitionTyStruct) + else [_kind_interface_name(ty.name), _json_interface_name(ty.name)] + ) + imports.append( + FromImport( + f".{module_name}", + import_members, + ) + ) + return str(Collection(imports)) + + +def gen_type_files(idl: Idl, types_dir: Path) -> None: + types_code = gen_types_code(idl, types_dir) + for path, code in types_code.items(): + formatted = format_str(code, mode=FileMode()) + fixed = fix_code(formatted, remove_all_unused_imports=True) + path.write_text(fixed) + + +def gen_types_code(idl: Idl, out: Path) -> dict[Path, str]: + res = {} + types_module_names = [_sanitize(snake(ty.name)) for ty in idl.types] + for ty in idl.types: + ty_name = _sanitize(ty.name) + module_name = _sanitize(snake(ty.name)) + relative_import_items = [ + mod for mod in types_module_names if mod != module_name + ] + relative_import_container = ( + [FromImport(".", relative_import_items)] if relative_import_items else [] + ) + ty_type = ty.ty + body = ( + gen_struct(idl, ty_name, ty_type.fields) + if isinstance(ty_type, IdlTypeDefinitionTyStruct) + else gen_enum(idl, ty_name, ty_type.variants) + ) + code = str(Collection([ANNOTATIONS_IMPORT, *relative_import_container, body])) + path = (out / module_name).with_suffix(".py") + res[path] = code + return res + + +def gen_struct(idl: Idl, name: str, fields: list[IdlField]) -> Collection: + imports = [ + Import("typing"), + FromImport("dataclasses", ["dataclass"]), + FromImport("construct", ["Container", "Construct"]), + FromImport("solders.pubkey", ["Pubkey"]), + FromImport("anchorpy.borsh_extension", ["BorshPubkey"]), + ImportAs("borsh_construct", "borsh"), + ] + json_interface_name = _json_interface_name(name) + field_params: list[TypedParam] = [] + json_interface_params: list[TypedParam] = [] + layout_items: list[str] = [] + from_decoded_items: list[str] = [] + to_encodable_items: list[str] = [] + to_json_items: list[str] = [] + from_json_items: list[str] = [] + for field in fields: + field_name = _sanitize(snake(field.name)) + field_params.append( + TypedParam( + field_name, + _py_type_from_idl( + idl=idl, + ty=field.ty, + types_relative_imports=True, + use_fields_interface_for_struct=False, + ), + ) + ) + json_interface_params.append( + TypedParam( + field_name, + _idl_type_to_json_type(ty=field.ty, types_relative_imports=True), + ) + ) + layout_items.append( + _layout_for_type( + idl=idl, ty=field.ty, name=field_name, types_relative_imports=True + ) + ) + from_decoded_item_val = _field_from_decoded( + idl=idl, + ty=IdlField(name=snake(field.name), docs=None, ty=field.ty), + val_prefix="obj.", + types_relative_imports=True, + ) + from_decoded_items.append(f"{field_name}={from_decoded_item_val}") + as_encodable = _field_to_encodable( + idl=idl, + ty=field, + val_prefix="self.", + val_suffix="", + types_relative_imports=True, + ) + to_encodable_items.append(f'"{field_name}": {as_encodable}') + to_json_items.append(f'"{field_name}": {_field_to_json(idl, field, "self.")}') + field_from_json = _field_from_json( + idl=idl, ty=field, types_relative_imports=True + ) + from_json_items.append(f"{field_name}={field_from_json}") + json_interface = TypedDict(json_interface_name, json_interface_params) + layout = f"borsh.CStruct({','.join(layout_items)})" + args_for_from_decoded = ",".join(from_decoded_items) + to_encodable_body = "{" + ",".join(to_encodable_items) + "}" + to_json_body = "{" + ",".join(to_json_items) + "}" + args_for_from_json = ",".join(from_json_items) + struct_cls = Dataclass( + name, + [ + Assign("layout: typing.ClassVar", layout), + *field_params, + ClassMethod( + "from_decoded", + [TypedParam("obj", "Container")], + Return(f"cls({args_for_from_decoded})"), + f'"{name}"', + ), + Method( + "to_encodable", + [], + Return(to_encodable_body), + "dict[str, typing.Any]", + ), + Method("to_json", [], Return(to_json_body), json_interface_name), + ClassMethod( + "from_json", + [TypedParam("obj", json_interface_name)], + Return(f"cls({args_for_from_json})"), + f'"{name}"', + ), + ], + ) + return Collection([*imports, json_interface, struct_cls]) + + +def _make_cstruct(fields: dict[str, str]) -> str: + formatted_fields = ",".join([f'"{key}" / {val}' for key, val in fields.items()]) + return f"borsh.CStruct({formatted_fields})" + + +@dataclass +class _NamedFieldRecord: + field_type_alias_entry: TypedParam + value_type_alias_entry: TypedParam + json_interface_value_type_entry: TypedParam + json_value_item: StrDictEntry + encodable_value_item: StrDictEntry + init_entry_for_from_decoded: NamedArg + init_entry_for_from_json: NamedArg + + +def _make_named_field_record( + named_field: IdlField, idl: Idl, cast_obj_var_name: str +) -> _NamedFieldRecord: + named_field_name = _sanitize(snake(named_field.name)) + return _NamedFieldRecord( + field_type_alias_entry=TypedParam( + named_field_name, + _py_type_from_idl( + idl=idl, + ty=named_field.ty, + types_relative_imports=True, + use_fields_interface_for_struct=False, + ), + ), + value_type_alias_entry=TypedParam( + named_field_name, + _py_type_from_idl( + idl=idl, + ty=named_field.ty, + types_relative_imports=True, + use_fields_interface_for_struct=False, + ), + ), + json_interface_value_type_entry=TypedParam( + named_field_name, + _idl_type_to_json_type(ty=named_field.ty, types_relative_imports=True), + ), + json_value_item=StrDictEntry( + named_field_name, + _field_to_json(idl, named_field, 'self.value["', val_suffix='"]'), + ), + encodable_value_item=StrDictEntry( + named_field_name, + _field_to_encodable( + idl=idl, + ty=named_field, + val_prefix='self.value["', + val_suffix='"]', + types_relative_imports=True, + ), + ), + init_entry_for_from_decoded=NamedArg( + named_field_name, + _field_from_decoded( + idl=idl, + ty=IdlField(f'val["{named_field_name}"]', docs=None, ty=named_field.ty), + types_relative_imports=True, + val_prefix="", + ), + ), + init_entry_for_from_json=NamedArg( + named_field_name, + _field_from_json( + idl=idl, + ty=named_field, + param_prefix=f'{cast_obj_var_name}["', + param_suffix='"]', + types_relative_imports=True, + ), + ), + ) + + +@dataclass +class _UnnamedFieldRecord: + field_type_alias_element: str + value_type_alias_element: str + json_interface_value_element: str + json_value_element: str + encodable_value_item: StrDictEntry + init_element_for_from_decoded: str + init_element_for_from_json: str + + +def _make_unnamed_field_record( + index: int, unnamed_field: IdlType, idl: Idl, cast_obj_var_name: str +) -> _UnnamedFieldRecord: + elem_name = f"value[{index}]" + encodable = _field_to_encodable( + idl=idl, + ty=IdlField(f"[{index}]", docs=None, ty=unnamed_field), + val_prefix="self.value", + types_relative_imports=True, + convert_case=False, + ) + return _UnnamedFieldRecord( + field_type_alias_element=_py_type_from_idl( + idl=idl, + ty=unnamed_field, + types_relative_imports=True, + use_fields_interface_for_struct=False, + ), + value_type_alias_element=_py_type_from_idl( + idl=idl, + ty=unnamed_field, + types_relative_imports=True, + use_fields_interface_for_struct=False, + ), + json_interface_value_element=_idl_type_to_json_type( + ty=unnamed_field, types_relative_imports=True + ), + json_value_element=_field_to_json( + idl, + IdlField(elem_name, docs=None, ty=unnamed_field), + "self.", + convert_case=False, + ), + encodable_value_item=StrDictEntry(f"item_{index}", encodable), + init_element_for_from_decoded=_field_from_decoded( + idl=idl, + ty=IdlField(f'val["item_{index}"]', docs=None, ty=unnamed_field), + val_prefix="", + types_relative_imports=True, + ), + init_element_for_from_json=_field_from_json( + idl=idl, + ty=IdlField(str(index), docs=None, ty=unnamed_field), + param_prefix=f"{cast_obj_var_name}[", + param_suffix="]", + types_relative_imports=True, + ), + ) + + +def gen_enum(idl: Idl, name: str, variants: list[IdlEnumVariant]) -> Collection: + imports = [ + Import("typing"), + FromImport("dataclasses", ["dataclass"]), + FromImport("solders.pubkey", ["Pubkey"]), + FromImport("construct", ["Construct"]), + FromImport("anchorpy.borsh_extension", ["EnumForCodegen", "BorshPubkey"]), + ImportAs("borsh_construct", "borsh"), + ] + invalid_enum_raise = Raise('ValueError("Invalid enum object")') + from_decoded_dict_check = If("not isinstance(obj, dict)", invalid_enum_raise) + variant_name_in_obj_checks: list[Generable] = [] + obj_kind_checks: list[Generable] = [] + json_interfaces: list[TypedDict] = [] + classes: list[Dataclass] = [] + cstructs: list[str] = [] + type_variants_members: list[str] = [] + json_variants_members: list[str] = [] + json_interface_value_field_types: list[TypingUnion[TypedDict, TupleTypeAlias]] = [] + value_type_aliases: list[TypingUnion[TypedDict, TupleTypeAlias]] = [] + for idx, variant in enumerate(variants): + discriminator = idx + fields = variant.fields + variant_name = _sanitize(variant.name) + value_interface_name = _value_interface_name(variant.name) + json_interface_name = _json_interface_name(variant.name) + json_interface_value_type_name = f"{json_interface_name}Value" + cast_obj_var_name = snake(json_interface_value_type_name) + encodable_value_items: list[StrDictEntry] = [] + cstruct_fields: dict[str, str] = {} + to_json_params_base = NamedArg("kind", f'"{variant.name}"') + json_interface_kind_field = TypedParam( + "kind", f'typing.Literal["{variant.name}"]' + ) + type_variants_members.append(variant_name) + json_variants_members.append(_json_interface_name(variant.name)) + + def make_variant_name_in_obj_check(then: Generable) -> Generable: + return If(f'"{variant.name}" in obj', then) + + def make_obj_kind_check(return_val: str) -> Generable: + accessed = 'obj["kind"]' + lhs = f"{accessed} == " + cast_obj_assignment_container = ( + [ + Assign( + cast_obj_var_name, + f'typing.cast({json_interface_value_type_name}, obj["value"])', + ) + ] + if fields + else [] + ) + return If( + f'{lhs}"{variant.name}"', + Suite([*cast_obj_assignment_container, Return(return_val)]), + ) + + if fields is not None: + flds = fields.fields + val_line_for_from_decoded = Assign("val", f'obj["{variant.name}"]') + if isinstance(flds[0], IdlField): + named_enum_fields = cast(list[IdlField], flds) + value_type_alias_entries: list[TypedParam] = [] + json_interface_value_type_entries: list[TypedParam] = [] + json_value_items: list[StrDictEntry] = [] + init_entries_for_from_decoded: list[NamedArg] = [] + init_entries_for_from_json: list[NamedArg] = [] + for named_field in named_enum_fields: + rec = _make_named_field_record(named_field, idl, cast_obj_var_name) + value_type_alias_entries.append(rec.value_type_alias_entry) + json_interface_value_type_entries.append( + rec.json_interface_value_type_entry + ) + json_value_items.append(rec.json_value_item) + encodable_value_items.append(rec.encodable_value_item) + init_entries_for_from_decoded.append( + rec.init_entry_for_from_decoded + ) + init_entries_for_from_json.append(rec.init_entry_for_from_json) + + cstruct_fields[snake(named_field.name)] = _layout_for_type( + idl=idl, ty=named_field.ty, types_relative_imports=True + ) + value_type_aliases.append( + TypedDict(value_interface_name, value_type_alias_entries) + ) + json_interface_value_field_type = TypedDict( + json_interface_value_type_name, json_interface_value_type_entries + ) + json_value_entry = StrDict(json_value_items) + to_json_body = Return( + Call( + json_interface_name, + [to_json_params_base, NamedArg("value", str(json_value_entry))], + ) + ) + init_arg_for_from_decoded = Call( + value_interface_name, init_entries_for_from_decoded + ) + init_arg_for_from_json = Call( + value_interface_name, init_entries_for_from_json + ) + else: + tuple_enum_fields = cast(list[IdlType], flds) + field_type_alias_elements: list[str] = [] + value_type_alias_elements: list[str] = [] + json_interface_value_elements: list[str] = [] + json_value_elements: list[str] = [] + init_elements_for_from_decoded: list[str] = [] + init_elements_for_from_json: list[str] = [] + for i, unnamed_field in enumerate(tuple_enum_fields): + rec_unnamed = _make_unnamed_field_record( + i, unnamed_field, idl, cast_obj_var_name + ) + field_type_alias_elements.append( + rec_unnamed.field_type_alias_element + ) + value_type_alias_elements.append( + rec_unnamed.value_type_alias_element + ) + json_interface_value_elements.append( + rec_unnamed.json_interface_value_element + ) + json_value_elements.append(rec_unnamed.json_value_element) + encodable_value_items.append(rec_unnamed.encodable_value_item) + init_elements_for_from_decoded.append( + rec_unnamed.init_element_for_from_decoded + ) + init_elements_for_from_json.append( + rec_unnamed.init_element_for_from_json + ) + cstruct_fields[f"item_{i}"] = _layout_for_type( + idl=idl, ty=unnamed_field, types_relative_imports=True + ) + value_type_aliases.append( + TupleTypeAlias( + value_interface_name, + value_type_alias_elements, + ) + ) + json_interface_value_field_type = TupleTypeAlias( + json_interface_value_type_name, json_interface_value_elements + ) + to_json_body = Return( + Call( + json_interface_name, + [ + to_json_params_base, + NamedArg("value", str(Tuple(json_value_elements))), + ], + ) + ) + init_arg_for_from_decoded = Tuple(init_elements_for_from_decoded) + init_arg_for_from_json = Tuple(init_elements_for_from_json) + value_field_container = [TypedParam("value", value_interface_name)] + to_json_method = Method("to_json", [], to_json_body, json_interface_name) + encodable_value_entry = StrDict(encodable_value_items) + to_encodable_body = Return( + StrDict([StrDictEntry(variant.name, encodable_value_entry)]) + ) + to_encodable_method = Method("to_encodable", [], to_encodable_body, "dict") + json_interface_params = [ + TypedParam("value", json_interface_value_type_name), + json_interface_kind_field, + ] + json_interface_value_field_types.append(json_interface_value_field_type) + variant_name_in_obj_check = make_variant_name_in_obj_check( + Suite( + [ + val_line_for_from_decoded, + Return( + f"{_sanitize(variant.name)}" + f"({init_arg_for_from_decoded})" + ), + ] + ) + ) + obj_kind_check = make_obj_kind_check( + f"{_sanitize(variant.name)}({init_arg_for_from_json})", + ) + else: + to_json_method = ClassMethod( + "to_json", + [], + Return(Call(json_interface_name, [to_json_params_base])), + json_interface_name, + ) + to_encodable_method = ClassMethod( + "to_encodable", + [], + Return(StrDict([StrDictEntry(variant.name, StrDict([]))])), + "dict", + ) + value_field_container = [] + json_interface_params = [json_interface_kind_field] + variant_name_in_obj_check = make_variant_name_in_obj_check( + Return(f"{_sanitize(variant.name)}()") + ) + obj_kind_check = make_obj_kind_check(f"{_sanitize(variant.name)}()") + json_interfaces.append(TypedDict(json_interface_name, json_interface_params)) + class_common_attrs = [ + Assign("discriminator: typing.ClassVar", discriminator), + Assign("kind: typing.ClassVar", f'"{variant.name}"'), + ] + + attrs = [ + *class_common_attrs, + *value_field_container, + to_json_method, + to_encodable_method, + ] + classes.append(Dataclass(_sanitize(variant.name), attrs)) + variant_name_in_obj_checks.append(variant_name_in_obj_check) + obj_kind_checks.append(obj_kind_check) + cstructs.append(f'"{variant.name}" / {_make_cstruct(cstruct_fields)}') + from_decoded_fn = Function( + "from_decoded", + [TypedParam("obj", "dict")], + Suite( + [from_decoded_dict_check, *variant_name_in_obj_checks, invalid_enum_raise] + ), + _kind_interface_name(name), + ) + from_json_fn = Function( + "from_json", + [TypedParam("obj", _json_interface_name(name))], + Suite( + [ + *obj_kind_checks, + Assign("kind", 'obj["kind"]'), + Raise('ValueError(f"Unrecognized enum kind: {kind}")'), + ] + ), + _kind_interface_name(name), + ) + formatted_cstructs = ",".join(cstructs) + layout_assignment = Assign( + "layout", + f"EnumForCodegen({formatted_cstructs})", + ) + json_variants = Union(json_variants_members) + type_variants = Union(type_variants_members) + kind_type_alias = Assign(_kind_interface_name(name), type_variants) + json_type_alias = Assign(_json_interface_name(name), json_variants) + return Collection( + [ + *imports, + *json_interface_value_field_types, + *value_type_aliases, + *json_interfaces, + *classes, + kind_type_alias, + json_type_alias, + from_decoded_fn, + from_json_fn, + layout_assignment, + ] + ) diff --git a/basics/anchorpy-main/src/anchorpy/coder/__init__.py b/basics/anchorpy-main/src/anchorpy/coder/__init__.py new file mode 100644 index 0000000..1bcf95b --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/coder/__init__.py @@ -0,0 +1 @@ +"""This subpackage defines the Coder class.""" diff --git a/basics/anchorpy-main/src/anchorpy/coder/accounts.py b/basics/anchorpy-main/src/anchorpy/coder/accounts.py new file mode 100644 index 0000000..af2f999 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/coder/accounts.py @@ -0,0 +1,73 @@ +"""This module provides `AccountsCoder` and `_account_discriminator`.""" +from hashlib import sha256 +from typing import Any, Tuple + +from anchorpy_core.idl import Idl +from construct import Adapter, Bytes, Container, Sequence, Switch + +from anchorpy.coder.idl import _typedef_layout +from anchorpy.program.common import NamedInstruction as AccountToSerialize + +ACCOUNT_DISCRIMINATOR_SIZE = 8 # bytes + + +class AccountsCoder(Adapter): + """Encodes and decodes account data.""" + + def __init__(self, idl: Idl) -> None: + """Init. + + Args: + idl: The parsed IDL object. + """ + self._accounts_layout = { + acc.name: _typedef_layout(acc, idl.types, acc.name) for acc in idl.accounts + } + self.acc_name_to_discriminator = { + acc.name: _account_discriminator(acc.name) for acc in idl.accounts + } + self.discriminator_to_acc_name = { + disc: acc_name for acc_name, disc in self.acc_name_to_discriminator.items() + } + discriminator_to_typedef_layout = { + disc: self._accounts_layout[acc_name] + for acc_name, disc in self.acc_name_to_discriminator.items() + } + subcon = Sequence( + "discriminator" / Bytes(ACCOUNT_DISCRIMINATOR_SIZE), + Switch(lambda this: this.discriminator, discriminator_to_typedef_layout), + ) + super().__init__(subcon) # type: ignore + + def decode(self, obj: bytes) -> Container[Any]: + """Decode account data. + + Args: + obj: Data to decode. + + Returns: + Decoded data. + """ + return self.parse(obj).data + + def _decode(self, obj: Tuple[bytes, Any], context, path) -> AccountToSerialize: + return AccountToSerialize( + data=obj[1], + name=self.discriminator_to_acc_name[obj[0]], + ) + + def _encode(self, obj: AccountToSerialize, context, path) -> Tuple[bytes, Any]: + discriminator = self.acc_name_to_discriminator[obj.name] + return discriminator, obj.data + + +def _account_discriminator(name: str) -> bytes: + """Calculate unique 8 byte discriminator prepended to all anchor accounts. + + Args: + name: The account name. + + Returns: + The discriminator in bytes. + """ + return sha256(f"account:{name}".encode()).digest()[:ACCOUNT_DISCRIMINATOR_SIZE] diff --git a/basics/anchorpy-main/src/anchorpy/coder/coder.py b/basics/anchorpy-main/src/anchorpy/coder/coder.py new file mode 100644 index 0000000..72cfb62 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/coder/coder.py @@ -0,0 +1,20 @@ +"""Provides the Coder class.""" +from anchorpy_core.idl import Idl + +from anchorpy.coder.accounts import AccountsCoder +from anchorpy.coder.event import EventCoder +from anchorpy.coder.instruction import InstructionCoder + + +class Coder: + """Coder provides a facade for encoding and decoding all IDL related objects.""" + + def __init__(self, idl: Idl): + """Initialize the coder. + + Args: + idl: a parsed Idl instance. + """ + self.instruction: InstructionCoder = InstructionCoder(idl) + self.accounts: AccountsCoder = AccountsCoder(idl) + self.events: EventCoder = EventCoder(idl) diff --git a/basics/anchorpy-main/src/anchorpy/coder/common.py b/basics/anchorpy-main/src/anchorpy/coder/common.py new file mode 100644 index 0000000..8a8872b --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/coder/common.py @@ -0,0 +1,125 @@ +"""Common utilities for encoding and decoding.""" +from hashlib import sha256 +from typing import Dict, Union + +from anchorpy_core.idl import ( + Idl, + IdlEnumVariant, + IdlField, + IdlType, + IdlTypeArray, + IdlTypeCompound, + IdlTypeDefined, + IdlTypeDefinition, + IdlTypeDefinitionTyEnum, + IdlTypeOption, + IdlTypeSimple, + IdlTypeVec, +) + + +def _sighash(ix_name: str) -> bytes: + """Not technically sighash, since we don't include the arguments. + + (Because Rust doesn't allow function overloading.) + + Args: + ix_name: The instruction name. + + Returns: + The sighash bytes. + """ + formatted_str = f"global:{ix_name}" + return sha256(formatted_str.encode()).digest()[:8] + + +def _type_size_compound_type(idl: Idl, ty: IdlTypeCompound) -> int: + if isinstance(ty, IdlTypeVec): + return 1 + if isinstance(ty, IdlTypeOption): + return 1 + _type_size(idl, ty.option) + if isinstance(ty, IdlTypeDefined): + defined = ty.defined + filtered = [t for t in idl.types if t.name == defined] + if len(filtered) != 1: + raise ValueError(f"Type not found {ty}") + type_def = filtered[0] + return _account_size(idl, type_def) + if isinstance(ty, IdlTypeArray): + element_type = ty.array[0] + array_size = ty.array[1] + return _type_size(idl, element_type) * array_size + raise ValueError(f"type_size not implemented for {ty}") + + +def _type_size(idl: Idl, ty: IdlType) -> int: + """Return the size of the type in bytes. + + For variable length types, just return 1. + Users should override this value in such cases. + + Args: + idl: The parsed `Idl` object. + ty: The type object from the IDL. + + Returns: + The size of the object in bytes. + """ + sizes: Dict[IdlTypeSimple, int] = { + IdlTypeSimple.Bool: 1, + IdlTypeSimple.U8: 1, + IdlTypeSimple.I8: 1, + IdlTypeSimple.Bytes: 1, + IdlTypeSimple.String: 1, + IdlTypeSimple.I16: 2, + IdlTypeSimple.U16: 2, + IdlTypeSimple.U32: 4, + IdlTypeSimple.I32: 4, + IdlTypeSimple.F32: 4, + IdlTypeSimple.U64: 8, + IdlTypeSimple.I64: 8, + IdlTypeSimple.F64: 8, + IdlTypeSimple.U128: 16, + IdlTypeSimple.I128: 16, + IdlTypeSimple.PublicKey: 32, + } + if isinstance(ty, IdlTypeSimple): + return sizes[ty] + return _type_size_compound_type(idl, ty) + + +def _variant_field_size(idl: Idl, field: Union[IdlField, IdlType]) -> int: + if isinstance(field, IdlField): + return _type_size(idl, field.ty) + return _type_size(idl, field) + + +def _variant_size(idl: Idl, variant: IdlEnumVariant) -> int: + if variant.fields is None: + return 0 + field_sizes = [] + field: Union[IdlField, IdlType] + for field in variant.fields.fields: + field_sizes.append(_variant_field_size(idl, field)) + return sum(field_sizes) + + +def _account_size(idl: Idl, idl_account: IdlTypeDefinition) -> int: + """Calculate account size in bytes. + + Args: + idl: The parsed `Idl` instance. + idl_account: An item from `idl.accounts`. + + Returns: + Account size. + """ + idl_account_type = idl_account.ty + if isinstance(idl_account_type, IdlTypeDefinitionTyEnum): + variant_sizes = ( + _variant_size(idl, variant) for variant in idl_account_type.variants + ) + return max(variant_sizes) + 1 + if idl_account_type.fields is None: + return 0 + return sum(_type_size(idl, f.ty) for f in idl_account_type.fields) diff --git a/basics/anchorpy-main/src/anchorpy/coder/event.py b/basics/anchorpy-main/src/anchorpy/coder/event.py new file mode 100644 index 0000000..5abd0a2 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/coder/event.py @@ -0,0 +1,82 @@ +"""This module deals with (de)serializing Anchor events.""" +from hashlib import sha256 +from typing import Any, Dict, Optional, Tuple + +from anchorpy_core.idl import ( + Idl, + IdlEvent, + IdlField, + IdlTypeDefinition, + IdlTypeDefinitionTyStruct, +) +from construct import Adapter, Bytes, Construct, Sequence, Switch +from pyheck import snake + +from anchorpy.coder.idl import _typedef_layout +from anchorpy.program.common import Event + + +def _event_discriminator(name: str) -> bytes: + """Get 8-byte discriminator from event name. + + Args: + name: The event name. + + Returns: + Discriminator + """ + return sha256(f"event:{name}".encode()).digest()[:8] + + +def _event_layout(event: IdlEvent, idl: Idl) -> Construct: + event_type_def = IdlTypeDefinition( + name=event.name, + docs=None, + ty=IdlTypeDefinitionTyStruct( + fields=[ + IdlField(name=snake(f.name), docs=None, ty=f.ty) for f in event.fields + ], + ), + ) + return _typedef_layout(event_type_def, idl.types, event.name) + + +class EventCoder(Adapter): + """Encodes and decodes Anchor events.""" + + def __init__(self, idl: Idl): + """Initialize the EventCoder. + + Args: + idl: The parsed Idl object. + """ + self.idl = idl + idl_events = idl.events + layouts: Dict[str, Construct] + if idl_events: + layouts = {event.name: _event_layout(event, idl) for event in idl_events} + else: + layouts = {} + self.layouts = layouts + self.discriminators: Dict[bytes, str] = ( + {} + if idl_events is None + else {_event_discriminator(event.name): event.name for event in idl_events} + ) + self.discriminator_to_layout = { + disc: self.layouts[event_name] + for disc, event_name in self.discriminators.items() + } + subcon = Sequence( + "discriminator" / Bytes(8), # not base64-encoded here + Switch(lambda this: this.discriminator, self.discriminator_to_layout), + ) + super().__init__(subcon) # type: ignore + + def _decode(self, obj: Tuple[bytes, Any], context, path) -> Optional[Event]: + disc = obj[0] + try: + event_name = self.discriminators[disc] + except KeyError: + return None + return Event(data=obj[1], name=event_name) diff --git a/basics/anchorpy-main/src/anchorpy/coder/idl.py b/basics/anchorpy-main/src/anchorpy/coder/idl.py new file mode 100644 index 0000000..5651ae3 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/coder/idl.py @@ -0,0 +1,325 @@ +"""IDL coding.""" +from dataclasses import fields as dc_fields +from dataclasses import make_dataclass +from keyword import kwlist +from types import MappingProxyType +from typing import Mapping, Type, cast + +from anchorpy_core.idl import ( + IdlField, + IdlType, + IdlTypeArray, + IdlTypeDefined, + IdlTypeDefinition, + IdlTypeDefinitionTyEnum, + IdlTypeDefinitionTyStruct, + IdlTypeOption, + IdlTypeSimple, + IdlTypeVec, +) +from borsh_construct import ( + F32, + F64, + I8, + I16, + I32, + I64, + I128, + U8, + U16, + U32, + U64, + U128, + Bool, + Bytes, + CStruct, + Enum, + Option, + String, + TupleStruct, + Vec, +) +from construct import Construct +from pyheck import snake + +from anchorpy.borsh_extension import BorshPubkey, _DataclassStruct +from anchorpy.idl import TypeDefs + +FIELD_TYPE_MAP: Mapping[IdlTypeSimple, Construct] = MappingProxyType( + { + IdlTypeSimple.Bool: Bool, + IdlTypeSimple.U8: U8, + IdlTypeSimple.I8: I8, + IdlTypeSimple.U16: U16, + IdlTypeSimple.I16: I16, + IdlTypeSimple.U32: U32, + IdlTypeSimple.I32: I32, + IdlTypeSimple.F32: F32, + IdlTypeSimple.U64: U64, + IdlTypeSimple.I64: I64, + IdlTypeSimple.F64: F64, + IdlTypeSimple.U128: U128, + IdlTypeSimple.I128: I128, + IdlTypeSimple.Bytes: Bytes, + IdlTypeSimple.String: String, + IdlTypeSimple.PublicKey: BorshPubkey, + }, +) + + +_enums_cache: dict[tuple[str, str], Enum] = {} + + +def _handle_enum_variants( + idl_enum: IdlTypeDefinitionTyEnum, + types: TypeDefs, + name: str, +) -> Enum: + dict_key = (name, str(idl_enum)) + try: + return _enums_cache[dict_key] + except KeyError: + result = _handle_enum_variants_no_cache(idl_enum, types, name) + _enums_cache[dict_key] = result + return result + + +def _handle_enum_variants_no_cache( + idl_enum: IdlTypeDefinitionTyEnum, + types: TypeDefs, + name: str, +) -> Enum: + variants = [] + dclasses = {} + for variant in idl_enum.variants: + variant_name = variant.name + if variant.fields is None: + variants.append(variant_name) + else: + variant_fields = variant.fields + flds = variant_fields.fields + if isinstance(flds[0], IdlField): + fields = [] + named_fields = cast(list[IdlField], flds) + for fld in named_fields: + fields.append(_field_layout(fld, types)) + cstruct = CStruct(*fields) + datacls = _idl_enum_fields_named_to_dataclass_type( + named_fields, + variant_name, + ) + dclasses[variant_name] = datacls + renamed = variant_name / cstruct + else: + fields = [] + unnamed_fields = cast(list[IdlType], flds) + for type_ in unnamed_fields: + fields.append(_type_layout(type_, types)) + tuple_struct = TupleStruct(*fields) + renamed = variant_name / tuple_struct + variants.append(renamed) # type: ignore + enum_without_types = Enum(*variants, enum_name=name) + if dclasses: + for cname in enum_without_types.enum._sumtype_constructor_names: + try: + dclass = dclasses[cname] + except KeyError: + continue + dclass_fields = dc_fields(dclass) + constructr = getattr(enum_without_types.enum, cname) + for constructor_field in constructr._sumtype_attribs: + attrib = constructor_field[1] # type: ignore + fld_name = constructor_field[0] # type: ignore + dclass_field = [f for f in dclass_fields if f.name == fld_name][0] + attrib.type = dclass_field.type # type: ignore + return enum_without_types + + +def _typedef_layout_without_field_name( + typedef: IdlTypeDefinition, + types: TypeDefs, +) -> Construct: + typedef_type = typedef.ty + name = typedef.name + if isinstance(typedef_type, IdlTypeDefinitionTyStruct): + field_layouts = [_field_layout(field, types) for field in typedef_type.fields] + cstruct = CStruct(*field_layouts) + datacls = _idl_typedef_ty_struct_to_dataclass_type(typedef_type, name) + return _DataclassStruct(cstruct, datacls=datacls) + elif isinstance(typedef_type, IdlTypeDefinitionTyEnum): + return _handle_enum_variants(typedef_type, types, name) + unknown_type = typedef_type.kind + raise ValueError(f"Unknown type {unknown_type}") + + +def _typedef_layout( + typedef: IdlTypeDefinition, + types: list[IdlTypeDefinition], + field_name: str, +) -> Construct: + """Map an IDL typedef to a `Construct` object. + + Args: + typedef: The IDL typedef object. + types: IDL type definitions. + field_name: The name of the field. + + Raises: + ValueError: If an unknown type is passed. + + Returns: + `Construct` object from `borsh-construct`. + """ + return field_name / _typedef_layout_without_field_name(typedef, types) + + +def _type_layout(type_: IdlType, types: TypeDefs) -> Construct: + if isinstance(type_, IdlTypeSimple): + return FIELD_TYPE_MAP[type_] + if isinstance(type_, IdlTypeVec): + return Vec(_type_layout(type_.vec, types)) + elif isinstance(type_, IdlTypeOption): + return Option(_type_layout(type_.option, types)) + elif isinstance(type_, IdlTypeDefined): + defined = type_.defined + if not types: + raise ValueError("User defined types not provided") + filtered = [t for t in types if t.name == defined] + if len(filtered) != 1: + raise ValueError(f"Type not found {defined}") + return _typedef_layout_without_field_name(filtered[0], types) + elif isinstance(type_, IdlTypeArray): + array_ty = type_.array[0] + array_len = type_.array[1] + inner_layout = _type_layout(array_ty, types) + return inner_layout[array_len] + raise ValueError(f"Type {type_} not implemented yet") + + +def _field_layout(field: IdlField, types: TypeDefs) -> Construct: + """Map IDL spec to `borsh-construct` types. + + Args: + field: field object from the IDL. + types: IDL type definitions. + + Raises: + ValueError: If the user-defined types are not provided. + ValueError: If the type is not found. + ValueError: If the type is not implemented yet. + + Returns: + `Construct` object from `borsh-construct`. + """ + field_name = snake(field.name) if field.name else "" + return field_name / _type_layout(field.ty, types) + + +def _make_datacls(name: str, fields: list[str]) -> type: + return make_dataclass(name, fields) + + +_idl_typedef_ty_struct_to_dataclass_type_cache: dict[tuple[str, str], Type] = {} + + +def _idl_typedef_ty_struct_to_dataclass_type( + typedef_type: IdlTypeDefinitionTyStruct, + name: str, +) -> Type: + dict_key = (name, str(typedef_type)) + try: + return _idl_typedef_ty_struct_to_dataclass_type_cache[dict_key] + except KeyError: + result = _idl_typedef_ty_struct_to_dataclass_type_no_cache(typedef_type, name) + _idl_typedef_ty_struct_to_dataclass_type_cache[dict_key] = result + return result + + +def _idl_typedef_ty_struct_to_dataclass_type_no_cache( + typedef_type: IdlTypeDefinitionTyStruct, + name: str, +) -> Type: + """Generate a dataclass definition from an IDL struct. + + Args: + typedef_type: The IDL type. + name: The name of the dataclass. + + Returns: + Dataclass definition. + """ + dataclass_fields = [] + for field in typedef_type.fields: + field_name = snake(field.name) + field_name_to_use = f"{field_name}_" if field_name in kwlist else field_name + dataclass_fields.append( + field_name_to_use, + ) + return _make_datacls(name, dataclass_fields) + + +_idl_enum_fields_named_to_dataclass_type_cache: dict[tuple[str, str], Type] = {} + + +def _idl_enum_fields_named_to_dataclass_type( + fields: list[IdlField], + name: str, +) -> Type: + dict_key = (name, str(fields)) + try: + return _idl_enum_fields_named_to_dataclass_type_cache[dict_key] + except KeyError: + result = _idl_enum_fields_named_to_dataclass_type_no_cache(fields, name) + _idl_enum_fields_named_to_dataclass_type_cache[dict_key] = result + return result + + +def _idl_enum_fields_named_to_dataclass_type_no_cache( + fields: list[IdlField], + name: str, +) -> Type: + """Generate a dataclass definition from IDL named enum fields. + + Args: + fields: The IDL enum fields. + name: The name of the dataclass. + + Returns: + Dataclass type definition. + """ + dataclass_fields = [] + for field in fields: + field_name = snake(field.name) + field_name_to_use = f"{field_name}_" if field_name in kwlist else field_name + dataclass_fields.append( + field_name_to_use, + ) + return _make_datacls(name, dataclass_fields) + + +def _idl_typedef_to_python_type( + typedef: IdlTypeDefinition, + types: TypeDefs, +) -> Type: + """Generate Python type from IDL user-defined type. + + Args: + typedef: The user-defined type. + types: IDL type definitions. + + Raises: + ValueError: If an unknown type is passed. + + Returns: + The Python type. + """ + typedef_type = typedef.ty + if isinstance(typedef_type, IdlTypeDefinitionTyStruct): + return _idl_typedef_ty_struct_to_dataclass_type( + typedef_type, + typedef.name, + ) + elif isinstance(typedef_type, IdlTypeDefinitionTyEnum): + return _handle_enum_variants(typedef_type, types, typedef.name).enum + unknown_type = typedef_type.kind + raise ValueError(f"Unknown type {unknown_type}") diff --git a/basics/anchorpy-main/src/anchorpy/coder/instruction.py b/basics/anchorpy-main/src/anchorpy/coder/instruction.py new file mode 100644 index 0000000..e648f44 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/coder/instruction.py @@ -0,0 +1,98 @@ +"""This module deals (de)serializing program instructions.""" +from typing import Any, Dict, Protocol, Tuple, TypeVar, cast + +from anchorpy_core.idl import Idl +from borsh_construct import CStruct +from construct import Adapter, Bytes, Construct, Container, Sequence, Switch +from pyheck import snake + +from anchorpy.coder.common import _sighash +from anchorpy.coder.idl import _field_layout +from anchorpy.idl import TypeDefs +from anchorpy.program.common import NamedInstruction + + +class _Sighash(Adapter): + """Sighash as a Construct Adapter.""" + + def __init__(self) -> None: + """Initialize.""" + super().__init__(Bytes(8)) # type: ignore + + def _encode(self, obj: str, context, path) -> bytes: + return _sighash(obj) + + def _decode(self, obj: bytes, context, path): + raise ValueError("Sighash cannot be reversed") + + +class InstructionCoder(Adapter): + """Encodes and decodes program instructions.""" + + def __init__(self, idl: Idl) -> None: + """Init. + + Args: + idl: The parsed IDL object. + """ + self.ix_layout = _parse_ix_layout(idl) + sighasher = _Sighash() + sighash_layouts: Dict[bytes, Construct] = {} + sighashes: Dict[str, bytes] = {} + sighash_to_name: Dict[bytes, str] = {} + for ix in idl.instructions: + ix_name = snake(ix.name) + sh = sighasher.build(ix_name) + sighashes[ix_name] = sh + sighash_layouts[sh] = self.ix_layout[ix_name] + sighash_to_name[sh] = ix_name + self.sighash_layouts = sighash_layouts + self.sighashes = sighashes + self.sighash_to_name = sighash_to_name + subcon = Sequence( + "sighash" / Bytes(8), + Switch(lambda this: this.sighash, sighash_layouts), + ) + super().__init__(subcon) # type: ignore + + def encode(self, ix_name: str, ix: Dict[str, Any]) -> bytes: + """Encode a program instruction. + + Args: + ix_name: The name of the instruction + ix: The data to encode. + + Returns: + The encoded instruction. + """ + return self.build(NamedInstruction(name=ix_name, data=ix)) + + def _decode(self, obj: Tuple[bytes, Any], context, path) -> NamedInstruction: + return NamedInstruction(data=obj[1], name=self.sighash_to_name[obj[0]]) + + def _encode( + self, obj: NamedInstruction, context: Container, path + ) -> Tuple[bytes, Any]: + return (self.sighashes[obj.name], obj.data) + + +_SA = TypeVar("_SA", bound="_SupportsAdd") + + +class _SupportsAdd(Protocol): + """Any type T where +(:T, :T) -> T.""" + + def __add__(self: _SA, other: _SA) -> _SA: + ... + + +def _parse_ix_layout(idl: Idl) -> Dict[str, Construct]: + ix_layout: Dict[str, Construct] = {} + for ix in idl.instructions: + typedefs = cast(_SupportsAdd, idl.accounts) + cast(_SupportsAdd, idl.types) + field_layouts = [ + _field_layout(arg, cast(TypeDefs, typedefs)) for arg in ix.args + ] + ix_name = snake(ix.name) + ix_layout[ix_name] = ix_name / CStruct(*field_layouts) + return ix_layout diff --git a/basics/anchorpy-main/src/anchorpy/error.py b/basics/anchorpy-main/src/anchorpy/error.py new file mode 100644 index 0000000..ef7aa6b --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/error.py @@ -0,0 +1,340 @@ +"""This module handles AnchorPy errors.""" +from __future__ import annotations + +import re +from enum import IntEnum +from typing import Dict, List, Optional, Tuple + +from solders.pubkey import Pubkey +from solders.rpc.errors import SendTransactionPreflightFailureMessage +from solders.rpc.responses import RPCError +from solders.transaction_status import ( + InstructionErrorCustom, + TransactionErrorInstructionError, + TransactionErrorType, +) + + +class AccountDoesNotExistError(Exception): + """Raise if account doesn't exist.""" + + +class AccountInvalidDiscriminator(Exception): + """Raise if account discriminator doesn't match the IDL.""" + + +class IdlNotFoundError(Exception): + """Raise when requested IDL account does not exist.""" + + +class ArgsError(Exception): + """Raise when the incorrect number of args is passed to the RPC function.""" + + +class _LangErrorCode(IntEnum): + """Enumerates Anchor error codes.""" + + # Instructions. + InstructionMissing = 100 + InstructionFallbackNotFound = 101 + InstructionDidNotDeserialize = 102 + InstructionDidNotSerialize = 103 + # IDL instructions. + IdlInstructionStub = 1000 + IdlInstructionInvalidProgram = 1001 + # Constraints. + ConstraintMut = 2000 + ConstraintHasOne = 2001 + ConstraintSigner = 2002 + ConstraintRaw = 2003 + ConstraintOwner = 2004 + ConstraintRentExempt = 2005 + ConstraintSeeds = 2006 + ConstraintExecutable = 2007 + ConstraintState = 2008 + ConstraintAssociated = 2009 + ConstraintAssociatedInit = 2010 + ConstraintClose = 2011 + ConstraintAddress = 2012 + ConstraintZero = 2013 + ConstraintTokenMint = 2014 + ConstraintTokenOwner = 2015 + ConstraintMintMintAuthority = 2016 + ConstraintMintFreezeAuthority = 2017 + ConstraintMintDecimals = 2018 + ConstraintSpace = 2019 + # Require + RequireViolated = 2500 + RequireEqViolated = 2501 + RequireKeysEqViolated = 2502 + RequireNeqViolated = 2503 + RequireKeysNeqViolated = 2504 + RequireGtViolated = 2505 + RequireGteViolated = 2506 + # Accounts. + AccountDiscriminatorAlreadySet = 3000 + AccountDiscriminatorNotFound = 3001 + AccountDiscriminatorMismatch = 3002 + AccountDidNotDeserialize = 3003 + AccountDidNotSerialize = 3004 + AccountNotEnoughKeys = 3005 + AccountNotMutable = 3006 + AccountOwnedByWrongProgram = 3007 + InvalidProgramId = 3008 + InvalidProgramExecutable = 3009 + AccountNotSigner = 3010 + AccountNotSystemOwned = 3011 + AccountNotInitialized = 3012 + AccountNotProgramData = 3013 + AccountNotAssociatedTokenAccount = 3014 + AccountSysvarMismatch = 3015 + # State. + StateInvalidAddress = 4000 + + # Used for APIs that shouldn't be used anymore. + Deprecated = 5000 + + +LangErrorMessage: Dict[int, str] = { + # Instructions. + _LangErrorCode.InstructionMissing: "8 byte instruction identifier not provided", + _LangErrorCode.InstructionFallbackNotFound: "Fallback functions are not supported", + _LangErrorCode.InstructionDidNotDeserialize: ( + "The program could not deserialize the given instruction" + ), + _LangErrorCode.InstructionDidNotSerialize: ( + "The program could not serialize the given instruction" + ), + # Idl instructions. + _LangErrorCode.IdlInstructionStub: ( + "The program was compiled without idl instructions" + ), + _LangErrorCode.IdlInstructionInvalidProgram: ( + "The transaction was given an invalid program for the IDL instruction" + ), + # Constraints. + _LangErrorCode.ConstraintMut: "A mut constraint was violated", + _LangErrorCode.ConstraintHasOne: "A has_one constraint was violated", + _LangErrorCode.ConstraintSigner: "A signer constraint was violated", + _LangErrorCode.ConstraintRaw: "A raw constraint was violated", + _LangErrorCode.ConstraintOwner: "An owner constraint was violated", + _LangErrorCode.ConstraintRentExempt: "A rent exempt constraint was violated", + _LangErrorCode.ConstraintSeeds: "A seeds constraint was violated", + _LangErrorCode.ConstraintExecutable: "An executable constraint was violated", + _LangErrorCode.ConstraintState: "A state constraint was violated", + _LangErrorCode.ConstraintAssociated: "An associated constraint was violated", + _LangErrorCode.ConstraintAssociatedInit: ( + "An associated init constraint was violated" + ), + _LangErrorCode.ConstraintClose: "A close constraint was violated", + _LangErrorCode.ConstraintAddress: "An address constraint was violated", + _LangErrorCode.ConstraintZero: "Expected zero account discriminant", + _LangErrorCode.ConstraintTokenMint: "A token mint constraint was violated", + _LangErrorCode.ConstraintTokenOwner: "A token owner constraint was violated", + _LangErrorCode.ConstraintMintMintAuthority: ( + "A mint mint authority constraint was violated" + ), + _LangErrorCode.ConstraintMintFreezeAuthority: ( + "A mint freeze authority constraint was violated" + ), + _LangErrorCode.ConstraintMintDecimals: "A mint decimals constraint was violated", + _LangErrorCode.ConstraintSpace: "A space constraint was violated", + # Require. + _LangErrorCode.RequireViolated: "A require expression was violated", + _LangErrorCode.RequireEqViolated: "A require_eq expression was violated", + _LangErrorCode.RequireKeysEqViolated: "A require_keys_eq expression was violated", + _LangErrorCode.RequireNeqViolated: "A require_neq expression was violated", + _LangErrorCode.RequireKeysNeqViolated: "A require_keys_neq expression was violated", + _LangErrorCode.RequireGtViolated: "A require_gt expression was violated", + _LangErrorCode.RequireGteViolated: "A require_gte expression was violated", + # Accounts. + _LangErrorCode.AccountDiscriminatorAlreadySet: ( + "The account discriminator was already set on this account" + ), + _LangErrorCode.AccountDiscriminatorNotFound: ( + "No 8 byte discriminator was found on the account" + ), + _LangErrorCode.AccountDiscriminatorMismatch: ( + "8 byte discriminator did not match what was expected" + ), + _LangErrorCode.AccountDidNotDeserialize: "Failed to deserialize the account", + _LangErrorCode.AccountDidNotSerialize: "Failed to serialize the account", + _LangErrorCode.AccountNotEnoughKeys: ( + "Not enough account keys given to the instruction" + ), + _LangErrorCode.AccountNotMutable: "The given account is not mutable", + _LangErrorCode.AccountOwnedByWrongProgram: ( + "The given account is owned by a different program than expected" + ), + _LangErrorCode.InvalidProgramId: "Program ID was not as expected", + _LangErrorCode.InvalidProgramExecutable: "Program account is not executable", + _LangErrorCode.AccountNotSigner: "The given account did not sign", + _LangErrorCode.AccountNotSystemOwned: ( + "The given account is not owned by the system program" + ), + _LangErrorCode.AccountNotInitialized: ( + "The program expected this account to be already initialized" + ), + _LangErrorCode.AccountNotProgramData: ( + "The given account is not a program data account" + ), + _LangErrorCode.AccountNotAssociatedTokenAccount: ( + "The given account is not the associated token account" + ), + _LangErrorCode.AccountSysvarMismatch: ( + "The given public key does not match the required sysvar" + ), + # State. + _LangErrorCode.StateInvalidAddress: ( + "The given state account does not have the correct address" + ), + # Misc. + _LangErrorCode.Deprecated: ( + "The API being used is deprecated and should no longer be used" + ), +} + + +class ProgramError(Exception): + """An error from a user defined program.""" + + def __init__( + self, code: int, msg: Optional[str], logs: Optional[list[str]] = None + ) -> None: + """Init. + + Args: + code: The error code. + msg: The error message. + logs: The transaction simulation logs. + """ + self.code = code + self.msg = msg + self.logs = logs + super().__init__(f"{code}: {msg}") + + @classmethod + def parse( + cls, + err_info: RPCError, + idl_errors: dict[int, str], + program_id: Pubkey, + ) -> Optional[ProgramError]: + """Convert an RPC error into a ProgramError, if possible. + + Args: + err_info: The RPC error. + idl_errors: Errors from the IDL file. + program_id: The ID of the program we expect the error to come from. + + Returns: + A ProgramError or None. + """ + extracted = extract_code_and_logs(err_info, program_id) + if extracted is None: + return None + code, logs = extracted + msg = idl_errors.get(code) + if msg is not None: + return cls(code, msg, logs) + # parse framework internal error + msg = LangErrorMessage.get(code) + if msg is not None: + return cls(code, msg, logs) + # Unable to parse the error. + return None + + @classmethod + def parse_tx_error( + cls, + err_info: TransactionErrorType, + idl_errors: dict[int, str], + program_id: Pubkey, + logs: List[str], + ) -> Optional[ProgramError]: + """Convert an RPC error into a ProgramError, if possible. + + Args: + err_info: The RPC error. + idl_errors: Errors from the IDL file. + program_id: The ID of the program we expect the error to come from. + logs: The transaction logs. + + Returns: + A ProgramError or None. + """ + code = extract_code_tx_error(err_info, program_id, logs) + if code is None: + return None + msg = idl_errors.get(code) + if msg is not None: + return cls(code, msg, logs) + # parse framework internal error + msg = LangErrorMessage.get(code) + if msg is not None: + return cls(code, msg, logs) + # Unable to parse the error. + return None + + +error_re = re.compile(r"Program (\w+) failed: custom program error: (\w+)") + + +def _find_first_match(logs: list[str]) -> Optional[re.Match]: + for logline in logs: + first_match = error_re.match(logline) + if first_match is not None: + return first_match + return None + + +def extract_code_and_logs( + err_info: RPCError, program_id: Pubkey +) -> Optional[Tuple[int, List[str]]]: + """Extract the custom instruction error code from an RPC response. + + Args: + err_info: The RPC error. + program_id: The ID of the program we expect the error to come from. + """ + if isinstance(err_info, SendTransactionPreflightFailureMessage): + err_data = err_info.data + err_data_err = err_data.err + logs = err_data.logs + if logs is None: + return None + if err_data_err is None: + return None + maybe_code = _handle_ix_err(err_data_err, logs, program_id) + return None if maybe_code is None else (maybe_code, logs) + return None + + +def extract_code_tx_error( + err_info: TransactionErrorType, program_id: Pubkey, logs: List[str] +) -> Optional[int]: + """Extract the custom instruction error code from a transaction error. + + Args: + err_info: The tx error. + program_id: The ID of the program we expect the error to come from. + logs: The tx logs. + """ + return _handle_ix_err(err_info, logs, program_id) + + +def _handle_ix_err( + err: TransactionErrorType, logs: List[str], program_id: Pubkey +) -> Optional[int]: + if isinstance(err, TransactionErrorInstructionError): + instruction_err = err.err + if isinstance(instruction_err, InstructionErrorCustom): + code = instruction_err.code + first_match = _find_first_match(logs) + if first_match is None: + return None + program_id_raw, _ = first_match.groups() + if program_id_raw != str(program_id): + return None + return code + return None diff --git a/basics/anchorpy-main/src/anchorpy/idl.py b/basics/anchorpy-main/src/anchorpy/idl.py new file mode 100644 index 0000000..a4a27ee --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/idl.py @@ -0,0 +1,46 @@ +"""Contains code for parsing the IDL file.""" +from typing import Sequence, TypedDict + +import solders.pubkey +from anchorpy_core.idl import IdlTypeDefinition +from borsh_construct import U8, CStruct, Vec + +from anchorpy.borsh_extension import BorshPubkey + + +def _idl_address(program_id: solders.pubkey.Pubkey) -> solders.pubkey.Pubkey: + """Deterministic IDL address as a function of the program id. + + Args: + program_id: The program ID. + + Returns: + The public key of the IDL. + """ + base = solders.pubkey.Pubkey.find_program_address([], program_id)[0] + return solders.pubkey.Pubkey.create_with_seed(base, "anchor:idl", program_id) + + +class IdlProgramAccount(TypedDict): + """The on-chain account of the IDL.""" + + authority: solders.pubkey.Pubkey + data: bytes + + +IDL_ACCOUNT_LAYOUT = CStruct("authority" / BorshPubkey, "data" / Vec(U8)) + + +def _decode_idl_account(data: bytes) -> IdlProgramAccount: + """Decode on-chain IDL. + + Args: + data: binary data from the account that stores the IDL. + + Returns: + Decoded IDL. + """ + return IDL_ACCOUNT_LAYOUT.parse(data) + + +TypeDefs = Sequence[IdlTypeDefinition] diff --git a/basics/anchorpy-main/src/anchorpy/program/__init__.py b/basics/anchorpy-main/src/anchorpy/program/__init__.py new file mode 100644 index 0000000..46bbdd9 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/__init__.py @@ -0,0 +1 @@ +"""This subpacakge defines the `Program` class.""" diff --git a/basics/anchorpy-main/src/anchorpy/program/common.py b/basics/anchorpy-main/src/anchorpy/program/common.py new file mode 100644 index 0000000..8dd0979 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/common.py @@ -0,0 +1,90 @@ +"""Common utilities.""" +from dataclasses import dataclass +from typing import Any, Dict, NamedTuple, Tuple, Union, cast + +from anchorpy_core.idl import ( + IdlAccountItem, + IdlAccounts, + IdlInstruction, +) +from construct import Container +from pyheck import snake +from solders.pubkey import Pubkey + +from anchorpy.program.context import Accounts + +AddressType = Union[Pubkey, str] + + +class Event(NamedTuple): + """A parsed event object.""" + + name: str + data: Any + + +@dataclass +class NamedInstruction: + """Container for a named instruction. + + Attributes: + data: The actual instruction data. + name: The name of the instruction. + """ + + data: Union[Dict[str, Any], Container[Any]] + name: str + + +def _to_instruction(idl_ix: IdlInstruction, args: Tuple) -> NamedInstruction: + """Convert an IDL instruction and arguments to an Instruction object. + + Args: + idl_ix: The IDL instruction object. + args: The instruction arguments. + + Raises: + ValueError: If the incorrect number of arguments is provided. + + Returns: + The parsed Instruction object. + """ + if len(idl_ix.args) != len(args): + raise ValueError("Invalid argument length") + ix: Dict[str, Any] = {} + for idx, ix_arg in enumerate(idl_ix.args): + ix[snake(ix_arg.name)] = args[idx] + return NamedInstruction(data=ix, name=snake(idl_ix.name)) + + +def validate_accounts(ix_accounts: list[IdlAccountItem], accounts: Accounts): + """Check that accounts passed in `ctx` match the IDL. + + Args: + ix_accounts: Accounts from the IDL. + accounts: Accounts from the `ctx` arg. + + Raises: + ValueError: If `ctx` accounts don't match the IDL. + """ + for acc in ix_accounts: + acc_name = snake(acc.name) + if isinstance(acc, IdlAccounts): + nested = cast(Accounts, accounts[acc_name]) + validate_accounts(acc.accounts, nested) + elif acc_name not in accounts: + raise ValueError(f"Invalid arguments: {acc_name} not provided") + + +def translate_address(address: AddressType) -> Pubkey: + """Convert `str | Pubkey` into `Pubkey`. + + Args: + address: Public key as string or `Pubkey`. + + Returns: + Public key as `Pubkey`. + """ + if isinstance(address, str): + return Pubkey.from_string(address) + return address diff --git a/basics/anchorpy-main/src/anchorpy/program/context.py b/basics/anchorpy-main/src/anchorpy/program/context.py new file mode 100644 index 0000000..8da74e4 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/context.py @@ -0,0 +1,69 @@ +"""This module contains code handling the Context object.""" +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional, Tuple + +from anchorpy_core.idl import IdlInstruction +from pyheck import snake +from solana.rpc.types import TxOpts +from solders.instruction import AccountMeta, Instruction +from solders.keypair import Keypair + +from anchorpy.error import ArgsError + +# should be Dict[str, Union[Pubkey, Accounts]] +# but mypy doesn't support recursive types +Accounts = Dict[str, Any] + + +@dataclass +class Context: + """Context provides all non-argument inputs for generating Anchor transactions. + + Attributes: + accounts: The accounts used in the instruction context. + remaining_accounts: All accounts to pass into an instruction *after* the main + `accounts`. This can be used for optional or otherwise unknown accounts. + signers: Accounts that must sign a given transaction. + pre_instructions: Instructions to run *before* a given method. Often this is + used, for example to create accounts prior to executing a method. + post_instructions: Instructions to run *after* a given method. Often this is + used, for example to close accounts prior to executing a method. + options: Commitment parameters to use for a transaction. + + """ + + # For some reason mkdocstrings doesn't understand the full type hint + # here if we use list[Instruction] instead of typing.List. + # Weirdly there are other places where it understands list[whatever]. + + accounts: Accounts = field(default_factory=dict) + remaining_accounts: List[AccountMeta] = field(default_factory=list) + signers: List[Keypair] = field(default_factory=list) + pre_instructions: List[Instruction] = field(default_factory=list) + post_instructions: List[Instruction] = field(default_factory=list) + options: Optional[TxOpts] = None + + +def _check_args_length( + idl_ix: IdlInstruction, + args: Tuple, +) -> None: + """Check that the correct number of args is passed to the RPC function. + + Args: + idl_ix: The IDL instruction object. + args: The instruction arguments. + + Raises: + ArgsError: If the correct number of args is not parsed. + """ + if len(args) != len(idl_ix.args): + expected_arg_names = [snake(arg.name) for arg in idl_ix.args] + raise ArgsError( + f"Provided incorrect number of args to instruction={snake(idl_ix.name)}. " + f"Expected {expected_arg_names}", + f"Received {args}", + ) + + +EMPTY_CONTEXT = Context() diff --git a/basics/anchorpy-main/src/anchorpy/program/core.py b/basics/anchorpy-main/src/anchorpy/program/core.py new file mode 100644 index 0000000..65e69a4 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/core.py @@ -0,0 +1,264 @@ +"""This module defines the Program class.""" +from __future__ import annotations + +import zlib +from typing import Any, Optional + +from anchorpy_core.idl import Idl +from pyheck import snake +from solders.pubkey import Pubkey + +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.coder.coder import Coder +from anchorpy.error import IdlNotFoundError +from anchorpy.idl import _decode_idl_account, _idl_address +from anchorpy.program.common import AddressType, translate_address +from anchorpy.program.namespace.account import AccountClient, _build_account +from anchorpy.program.namespace.instruction import ( + _InstructionFn, +) +from anchorpy.program.namespace.methods import ( + IdlFuncs, + MethodsBuilder, + _build_methods_item, +) +from anchorpy.program.namespace.rpc import ( + _build_rpc_item, + _RpcFn, +) +from anchorpy.program.namespace.simulate import ( + _build_simulate_item, + _SimulateFn, +) +from anchorpy.program.namespace.transaction import ( + _build_transaction_fn, + _TransactionFn, +) +from anchorpy.program.namespace.types import _build_types +from anchorpy.provider import Provider + + +def _parse_idl_errors(idl: Idl) -> dict[int, str]: + """Turn IDL errors into something readable. + + Uses message if available, otherwise name. + + Args: + idl: Parsed `Idl` instance. + + """ + errors = {} + idl_errors = idl.errors + if idl_errors is not None: + for e in idl_errors: + msg = e.msg if e.msg else e.name + errors[e.code] = msg + return errors + + +def _build_namespace( + idl: Idl, + coder: Coder, + program_id: Pubkey, + provider: Provider, +) -> tuple[ + dict[str, _RpcFn], + dict[str, _InstructionFn], + dict[str, _TransactionFn], + dict[str, AccountClient], + dict[str, _SimulateFn], + dict[str, Any], + dict[str, MethodsBuilder], +]: + """Generate all namespaces for a given program. + + Args: + idl: The parsed IDL object. + coder: The program's Coder object . + program_id: The Program ID. + provider: The program's provider. + + Returns: + The program namespaces. + """ + idl_errors = _parse_idl_errors(idl) + + rpc = {} + instruction = {} + transaction = {} + simulate = {} + methods = {} + + for idl_ix in idl.instructions: + + ix_item = _InstructionFn(idl_ix, coder.instruction.build, program_id) + tx_item = _build_transaction_fn(idl_ix, ix_item) + rpc_item = _build_rpc_item(idl_ix, tx_item, idl_errors, provider, program_id) + simulate_item = _build_simulate_item( + idl_ix, + tx_item, + idl_errors, + provider, + coder, + program_id, + idl, + ) + idl_funcs = IdlFuncs( + ix_fn=ix_item, tx_fn=tx_item, rpc_fn=rpc_item, simulate_fn=simulate_item + ) + methods_item = _build_methods_item(idl_funcs) + + name = snake(idl_ix.name) + instruction[name] = ix_item + transaction[name] = tx_item + rpc[name] = rpc_item + simulate[name] = simulate_item + methods[name] = methods_item + + account = _build_account(idl, coder, program_id, provider) if idl.accounts else {} + types = _build_types(idl) + return rpc, instruction, transaction, account, simulate, types, methods + + +def _pako_inflate(data): + # https://stackoverflow.com/questions/46351275/using-pako-deflate-with-python + decompress = zlib.decompressobj(15) + decompressed_data = decompress.decompress(data) + decompressed_data += decompress.flush() + return decompressed_data + + +class Program(object): + """Program provides the IDL deserialized client representation of an Anchor program. + + This API is the one stop shop for all things related to communicating with + on-chain programs. Among other things, one can send transactions, fetch + deserialized accounts, decode instruction data, subscribe to account + changes, and listen to events. + + In addition to field accessors and methods, the object provides a set of + dynamically generated properties, also known as namespaces, that + map one-to-one to program methods and accounts. + + """ + + def __init__( + self, idl: Idl, program_id: Pubkey, provider: Optional[Provider] = None + ): + """Initialize the Program object. + + Args: + idl: The parsed IDL object. + program_id: The program ID. + provider: The Provider object for the Program. Defaults to Provider.local(). + """ + self.idl = idl + self.program_id = program_id + self.provider = provider if provider is not None else Provider.local() + self.coder = Coder(idl) + + ( + rpc, + instruction, + transaction, + account, + simulate, + types, + methods, + ) = _build_namespace( + idl, + self.coder, + program_id, + self.provider, + ) + + self.rpc = rpc + self.instruction = instruction + self.transaction = transaction + self.account = account + self.simulate = simulate + self.type = types + self.methods = methods + + async def __aenter__(self) -> Program: + """Use as a context manager.""" + await self.provider.__aenter__() + return self + + async def __aexit__(self, _exc_type, _exc, _tb): + """Exit the context manager.""" + await self.close() + + async def close(self) -> None: + """Use this when you are done with the client.""" + await self.provider.close() + + @staticmethod + async def fetch_raw_idl( + address: AddressType, + provider: Provider, + ) -> str: + """Fetch an idl from the blockchain as a raw JSON dictionary. + + Args: + address: The program ID. + provider: The network and wallet context. + + Raises: + IdlNotFoundError: If the requested IDL account does not exist. + + Returns: + str: The raw IDL. + """ + program_id = translate_address(address) + actual_provider = provider if provider is not None else Provider.local() + idl_addr = _idl_address(program_id) + account_info = await actual_provider.connection.get_account_info(idl_addr) + account_info_val = account_info.value + if account_info_val is None: + raise IdlNotFoundError(f"IDL not found for program: {address}") + idl_account = _decode_idl_account( + account_info_val.data[ACCOUNT_DISCRIMINATOR_SIZE:] + ) + return _pako_inflate(bytes(idl_account["data"])).decode() + + @classmethod + async def fetch_idl( + cls, + address: AddressType, + provider: Provider, + ) -> Idl: + """Fetch and parse an idl from the blockchain. + + Args: + address: The program ID. + provider: The network and wallet context. + + Returns: + Idl: The fetched IDL. + """ + raw = await cls.fetch_raw_idl(address, provider) + return Idl.from_json(raw) + + @classmethod + async def at( + cls, + address: AddressType, + provider: Optional[Provider] = None, + ) -> Program: + """Generate a Program client by fetching the IDL from the network. + + In order to use this method, an IDL must have been previously initialized + via the anchor CLI's `anchor idl init` command. + + Args: + address: The program ID. + provider: The network and wallet context. + + Returns: + The Program instantiated using the fetched IDL. + """ + provider_to_use = Provider.local() if provider is None else provider + program_id = translate_address(address) + idl = await cls.fetch_idl(program_id, provider_to_use) + return cls(idl, program_id, provider) diff --git a/basics/anchorpy-main/src/anchorpy/program/event.py b/basics/anchorpy-main/src/anchorpy/program/event.py new file mode 100644 index 0000000..dbccfe1 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/event.py @@ -0,0 +1,166 @@ +"""This module contains code for handling Anchor events.""" +import binascii +from base64 import b64decode +from dataclasses import dataclass +from typing import Callable, List, Optional, cast + +from solders.pubkey import Pubkey + +from anchorpy.coder.coder import Coder +from anchorpy.program.common import Event + +PROGRAM_LOG = "Program log: " +PROGRAM_DATA = "Program data: " +PROGRAM_LOG_START_INDEX = len(PROGRAM_LOG) +PROGRAM_DATA_START_INDEX = len(PROGRAM_DATA) + + +class _ExecutionContext: + """Stack frame execution context, allowing one to track what program is executing for a given log.""" # noqa: E501 + + def __init__(self, log: str) -> None: + """Init. + + Args: + log: The log to process. + + Raises: + ValueError: If the log line is malformed. + """ + try: + program = log.split("Program ")[1].split(" invoke [")[0] + except IndexError as e: + raise ValueError("Could not find program invocation log line") from e + self.stack = [program] + + def program(self) -> str: + """Return the currently executing program. + + Returns: + The name of the program. + """ + return self.stack[-1] + + def push(self, new_program: str) -> None: + """Add to the stack. + + Args: + new_program: The program to add. + """ + self.stack.append(new_program) + + def pop(self) -> None: + """Pop from the stack.""" + self.stack.pop() + + +@dataclass +class EventParser: + """Parser to handle on_logs callbacks.""" + + program_id: Pubkey + coder: Coder + + def parse_logs(self, logs: List[str], callback: Callable[[Event], None]) -> None: + """Parse a list of logs using a provided callback. + + Args: + logs: The logs to parse. + callback: The function to handle the parsed log. + """ + log_scanner = _LogScanner(logs) + execution = _ExecutionContext(cast(str, log_scanner.to_next())) + log = log_scanner.to_next() + while log is not None: + event, new_program, did_pop = self.handle_log(execution, log) + if event is not None: + callback(event) + if new_program is not None: + execution.push(new_program) + if did_pop: + execution.pop() + log = log_scanner.to_next() + + def handle_log( + self, + execution: _ExecutionContext, + log: str, + ) -> tuple[Optional[Event], Optional[str], bool]: + """Main log handler. + + Args: + execution: The execution stack. + log: log string from the RPC node. + + Returns: + A three element array of the event, the next program + that was invoked for CPI, and a boolean indicating if + a program has completed execution (and thus should be popped off the + execution stack). + """ + # Executing program is this program. + if execution.stack and execution.program() == str(self.program_id): + return self.handle_program_log(log) + # Executing program is not this program. + return (None, *self.handle_system_log(log)) + + def handle_program_log( + self, log: str + ) -> tuple[Optional[Event], Optional[str], bool]: + """Handle logs from *this* program. + + Args: + log: log string from the RPC node. + + """ + # This is a `msg!` log or a `sol_log_data!` log. + if log.startswith(PROGRAM_LOG) or log.startswith(PROGRAM_DATA): + log_str = ( + log[PROGRAM_LOG_START_INDEX:] + if log.startswith(PROGRAM_LOG) + else log[PROGRAM_DATA_START_INDEX:] + ) + try: + decoded = b64decode(log_str) + except binascii.Error: + return None, None, False + event = self.coder.events.parse(decoded) + return event, None, False + return (None, *self.handle_system_log(log)) + + def handle_system_log(self, log: str) -> tuple[Optional[str], bool]: + """Handle logs when the current program being executing is *not* this. + + Args: + log: log string from the RPC node. + + """ + log_start = log.split(":")[0] + splitted = log_start.split(" ") + invoke_msg = f"Program {str(self.program_id)} invoke" + if len(splitted) == 3 and splitted[0] == "Program" and splitted[2] == "success": + return None, True + if log_start.startswith(invoke_msg): + return str(self.program_id), False + if "invoke" in log_start: + return "cpi", False + return None, False + + +@dataclass +class _LogScanner: + """Object that iterates over logs.""" + + logs: list[str] + + def to_next(self) -> Optional[str]: + """Move to the next log item. + + Returns: + The next log line, or None if there's nothing to return. + """ + if self.logs: + log = self.logs[0] + self.logs = self.logs[1:] + return log + return None diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/__init__.py b/basics/anchorpy-main/src/anchorpy/program/namespace/__init__.py new file mode 100644 index 0000000..cc1abae --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/__init__.py @@ -0,0 +1 @@ +"""This subpackage deals with the dynamic namespaces under `Program`.""" diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/account.py b/basics/anchorpy-main/src/anchorpy/program/namespace/account.py new file mode 100644 index 0000000..133e5fd --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/account.py @@ -0,0 +1,231 @@ +"""Provides the `AccountClient` class.""" +from dataclasses import dataclass +from typing import Any, Dict, List, Optional, Sequence, Union + +from anchorpy_core.idl import Idl, IdlTypeDefinition +from based58 import b58encode +from construct import Container +from solana.rpc.commitment import Commitment +from solana.rpc.types import MemcmpOpts +from solana.transaction import Instruction +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.system_program import CreateAccountParams, create_account + +from anchorpy.coder.accounts import ( + ACCOUNT_DISCRIMINATOR_SIZE, + _account_discriminator, +) +from anchorpy.coder.coder import Coder +from anchorpy.coder.common import _account_size +from anchorpy.error import AccountDoesNotExistError, AccountInvalidDiscriminator +from anchorpy.provider import Provider +from anchorpy.utils.rpc import get_multiple_accounts + + +def _build_account( + idl: Idl, + coder: Coder, + program_id: Pubkey, + provider: Provider, +) -> Dict[str, "AccountClient"]: + """Generate the `.account` namespace. + + Args: + idl: The parsed Idl object. + coder: The program's coder object. + program_id: The program ID. + provider: The Provider instance. + + Returns: + Mapping of account name to `AccountClient` instance. + """ + accounts_fns = {} + for idl_account in idl.accounts: + account_client = AccountClient(idl, idl_account, coder, program_id, provider) + accounts_fns[idl_account.name] = account_client + return accounts_fns + + +@dataclass +class ProgramAccount: + """Deserialized account owned by a program.""" + + public_key: Pubkey + account: Container + + +class AccountClient(object): + """Provides methods for fetching and creating accounts.""" + + def __init__( + self, + idl: Idl, + idl_account: IdlTypeDefinition, + coder: Coder, + program_id: Pubkey, + provider: Provider, + ): + """Init. + + Args: + idl: the parsed IDL object. + idl_account: the account definition from the IDL. + coder: The program's Coder object. + program_id: the program ID. + provider: The Provider object for the Program. + """ + self._idl_account = idl_account + self._program_id = program_id + self._provider = provider + self._coder = coder + self._size = ACCOUNT_DISCRIMINATOR_SIZE + _account_size(idl, idl_account) + + async def fetch( + self, address: Pubkey, commitment: Optional[Commitment] = None + ) -> Container[Any]: + """Return a deserialized account. + + Args: + address: The address of the account to fetch. + commitment: Bank state to query. + + + Raises: + AccountDoesNotExistError: If the account doesn't exist. + AccountInvalidDiscriminator: If the discriminator doesn't match the IDL. + """ + account_info = await self._provider.connection.get_account_info( + address, + encoding="base64", + commitment=commitment, + ) + if not account_info.value: + raise AccountDoesNotExistError(f"Account {address} does not exist") + data = account_info.value.data + discriminator = _account_discriminator(self._idl_account.name) + if discriminator != data[:ACCOUNT_DISCRIMINATOR_SIZE]: + msg = f"Account {address} has an invalid discriminator" + raise AccountInvalidDiscriminator(msg) + return self._coder.accounts.decode(data) + + async def fetch_multiple( + self, + addresses: List[Pubkey], + batch_size: int = 300, + commitment: Optional[Commitment] = None, + ) -> list[Optional[Container[Any]]]: + """Return multiple deserialized accounts. + + Accounts not found or with wrong discriminator are returned as None. + + Args: + addresses: The addresses of the accounts to fetch. + batch_size: The number of `getMultipleAccounts` objects to send + in each HTTP request. + commitment: Bank state to query. + """ + accounts = await get_multiple_accounts( + self._provider.connection, + addresses, + batch_size=batch_size, + commitment=commitment, + ) + discriminator = _account_discriminator(self._idl_account.name) + result: list[Optional[Container[Any]]] = [] + for account in accounts: + if account is None: + result.append(None) + elif discriminator == account.account.data[:8]: + result.append(self._coder.accounts.decode(account.account.data)) + else: + result.append(None) + return result + + async def create_instruction( + self, + signer: Keypair, + size_override: int = 0, + ) -> Instruction: + """Return an instruction for creating this account. + + Args: + signer: [description] + size_override: Optional override for the account size. Defaults to 0. + + Returns: + The instruction to create the account. + """ + space = size_override if size_override else self._size + mbre_resp = ( + await self._provider.connection.get_minimum_balance_for_rent_exemption( + space + ) + ) + return create_account( + CreateAccountParams( + from_pubkey=self._provider.wallet.public_key, + to_pubkey=signer.pubkey(), + space=space, + lamports=mbre_resp.value, + owner=self._program_id, + ) + ) + + async def all( # noqa: A003 + self, + buffer: Optional[bytes] = None, + filters: Optional[Sequence[Union[int, MemcmpOpts]]] = None, + ) -> list[ProgramAccount]: + """Return all instances of this account type for the program. + + Args: + buffer: bytes filter to append to the discriminator. + filters: (optional) Options to compare a provided series of bytes with + program account data at a particular offset. + Note: an int entry is converted to a `dataSize` filter. + """ + all_accounts = [] + discriminator = _account_discriminator(self._idl_account.name) + to_encode = discriminator if buffer is None else discriminator + buffer + bytes_arg = b58encode(to_encode).decode("ascii") + base_memcmp_opt = MemcmpOpts( + offset=0, + bytes=bytes_arg, + ) + filters_to_use = [base_memcmp_opt] + [] if filters is None else filters + resp = await self._provider.connection.get_program_accounts( + self._program_id, + encoding="base64", + commitment=self.provider.connection._commitment, + filters=filters_to_use, + ) + for r in resp.value: + account_data = r.account.data + all_accounts.append( + ProgramAccount( + public_key=r.pubkey, + account=self._coder.accounts.decode(account_data), + ), + ) + return all_accounts + + @property + def size(self) -> int: + """Return the number of bytes in this account.""" + return self._size + + @property + def program_id(self) -> Pubkey: + """Return the program ID owning all accounts.""" + return self._program_id + + @property + def provider(self) -> Provider: + """Return the client's wallet and network provider.""" + return self._provider + + @property + def coder(self) -> Coder: + """Return the coder.""" + return self._coder diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/instruction.py b/basics/anchorpy-main/src/anchorpy/program/namespace/instruction.py new file mode 100644 index 0000000..64b5176 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/instruction.py @@ -0,0 +1,127 @@ +"""This module deals with generating program instructions.""" +from typing import Any, Callable, Sequence, Tuple, cast + +from anchorpy_core.idl import IdlAccount, IdlAccountItem, IdlAccounts, IdlInstruction +from pyheck import snake +from solders.instruction import AccountMeta, Instruction +from solders.pubkey import Pubkey + +from anchorpy.program.common import ( + NamedInstruction, + _to_instruction, + validate_accounts, +) +from anchorpy.program.context import ( + EMPTY_CONTEXT, + Accounts, + Context, + _check_args_length, +) + + +class _InstructionFn: + """Callable object to create a `Instruction` generated from an IDL. + + Additionally it provides an `accounts` utility method, returning a list + of ordered accounts for the instruction. + """ + + def __init__( + self, + idl_ix: IdlInstruction, + encode_fn: Callable[[NamedInstruction], bytes], + program_id: Pubkey, + ) -> None: + """Init. + + Args: + idl_ix: IDL instruction object + encode_fn: [description] + program_id: The program ID. + + Raises: + ValueError: [description] + """ + if snake(idl_ix.name) == "_inner": + raise ValueError("_inner name is reserved") + self.idl_ix = idl_ix + self.encode_fn = encode_fn + self.program_id = program_id + + def __call__( + self, + *args: Any, + ctx: Context = EMPTY_CONTEXT, + ) -> Instruction: + """Create the Instruction. + + Args: + *args: The positional arguments for the program. The type and number + of these arguments depend on the program being used. + ctx: non-argument parameters to pass to the method. + """ + _check_args_length(self.idl_ix, args) + validate_accounts(self.idl_ix.accounts, ctx.accounts) + _validate_instruction(self.idl_ix, args) + + keys = self.accounts(ctx.accounts) + if ctx.remaining_accounts: + keys.extend(ctx.remaining_accounts) + return Instruction( + accounts=keys, + program_id=self.program_id, + data=self.encode_fn(_to_instruction(self.idl_ix, args)), + ) + + def accounts(self, accs: Accounts) -> list[AccountMeta]: + """Order the accounts for this instruction. + + Args: + accs: Accounts from `ctx` kwarg. + + Returns: + Ordered and flattened accounts. + """ + return _accounts_array(accs, self.idl_ix.accounts) + + +def _accounts_array( + ctx: Accounts, + accounts: Sequence[IdlAccountItem], +) -> list[AccountMeta]: + """Create a list of AccountMeta from a (possibly nested) dict of accounts. + + Args: + ctx: `accounts` field from the `Context` object. + accounts: accounts from the IDL. + + Returns: + AccountMeta objects. + """ + accounts_ret: list[AccountMeta] = [] + for acc in accounts: + if isinstance(acc, IdlAccounts): + rpc_accs = cast(Accounts, ctx[snake(acc.name)]) + acc_arr = _accounts_array(rpc_accs, acc.accounts) + accounts_ret.extend(acc_arr) + else: + account: IdlAccount = acc + single_account = cast(Pubkey, ctx[snake(account.name)]) + accounts_ret.append( + AccountMeta( + pubkey=single_account, + is_writable=account.is_mut, + is_signer=account.is_signer, + ), + ) + return accounts_ret + + +def _validate_instruction(ix: IdlInstruction, args: Tuple): # noqa: ARG001 + """Throws error if any argument required for the `ix` is not given. + + Args: + ix: The IDL instruction object. + args: The instruction arguments. + """ + # TODO: this isn't implemented in the TS client yet diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/methods.py b/basics/anchorpy-main/src/anchorpy/program/namespace/methods.py new file mode 100644 index 0000000..bec2a76 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/methods.py @@ -0,0 +1,158 @@ +from dataclasses import dataclass +from typing import Any, List, Optional + +from solana.rpc import types +from solders.hash import Hash +from solders.instruction import AccountMeta, Instruction +from solders.keypair import Keypair +from solders.signature import Signature +from solders.transaction import VersionedTransaction + +from anchorpy.program.context import Accounts, Context +from anchorpy.program.namespace.instruction import _InstructionFn +from anchorpy.program.namespace.rpc import _RpcFn +from anchorpy.program.namespace.simulate import SimulateResponse, _SimulateFn +from anchorpy.program.namespace.transaction import _TransactionFn + + +@dataclass +class IdlFuncs: + ix_fn: _InstructionFn + tx_fn: _TransactionFn + rpc_fn: _RpcFn + simulate_fn: _SimulateFn + + +class MethodsBuilder: + def __init__( + self, + idl_funcs: IdlFuncs, + accounts: Accounts, + remaining_accounts: List[AccountMeta], + signers: List[Keypair], + pre_instructions: List[Instruction], + post_instructions: List[Instruction], + args: List[Any], + ) -> None: + self._idl_funcs = idl_funcs + self._accounts = accounts + self._remaining_accounts = remaining_accounts + self._signers = signers + self._pre_instructions = pre_instructions + self._post_instructions = post_instructions + self._args = args + + async def rpc(self, opts: Optional[types.TxOpts] = None) -> Signature: + ctx = self._build_context(opts) + return await self._idl_funcs.rpc_fn(*self._args, ctx=ctx) + + async def simulate(self, opts: Optional[types.TxOpts] = None) -> SimulateResponse: + ctx = self._build_context(opts) + return await self._idl_funcs.simulate_fn(*self._args, ctx=ctx) + + def instruction(self) -> Instruction: + ctx = self._build_context(opts=None) + return self._idl_funcs.ix_fn(*self._args, ctx=ctx) + + def transaction(self, payer: Keypair, blockhash: Hash) -> VersionedTransaction: + ctx = self._build_context(opts=None) + return self._idl_funcs.tx_fn( + *self._args, ctx=ctx, payer=payer, blockhash=blockhash + ) + + def pubkeys(self) -> Accounts: + return self._accounts + + def args(self, arguments: List[Any]) -> "MethodsBuilder": + idl_funcs = self._idl_funcs + return MethodsBuilder( + idl_funcs=idl_funcs, + accounts=self._accounts, + remaining_accounts=self._remaining_accounts, + signers=self._signers, + pre_instructions=self._pre_instructions, + post_instructions=self._post_instructions, + args=arguments, + ) + + def accounts(self, accs: Accounts) -> "MethodsBuilder": + idl_funcs = self._idl_funcs + return MethodsBuilder( + idl_funcs=idl_funcs, + accounts=accs, + remaining_accounts=self._remaining_accounts, + signers=self._signers, + pre_instructions=self._pre_instructions, + post_instructions=self._post_instructions, + args=self._args, + ) + + def signers(self, signers: List[Keypair]) -> "MethodsBuilder": + idl_funcs = self._idl_funcs + return MethodsBuilder( + idl_funcs=idl_funcs, + accounts=self._accounts, + remaining_accounts=self._remaining_accounts, + signers=self._signers + signers, + pre_instructions=self._pre_instructions, + post_instructions=self._post_instructions, + args=self._args, + ) + + def remaining_accounts(self, accounts: List[AccountMeta]) -> "MethodsBuilder": + idl_funcs = self._idl_funcs + return MethodsBuilder( + idl_funcs=idl_funcs, + accounts=self._accounts, + remaining_accounts=self._remaining_accounts + accounts, + signers=self._signers, + pre_instructions=self._pre_instructions, + post_instructions=self._post_instructions, + args=self._args, + ) + + def pre_instructions(self, ixs: List[Instruction]) -> "MethodsBuilder": + idl_funcs = self._idl_funcs + return MethodsBuilder( + idl_funcs=idl_funcs, + accounts=self._accounts, + remaining_accounts=self._remaining_accounts, + signers=self._signers, + pre_instructions=self._pre_instructions + ixs, + post_instructions=self._post_instructions, + args=self._args, + ) + + def post_instructions(self, ixs: List[Instruction]) -> "MethodsBuilder": + idl_funcs = self._idl_funcs + return MethodsBuilder( + idl_funcs=idl_funcs, + accounts=self._accounts, + remaining_accounts=self._remaining_accounts, + signers=self._signers, + pre_instructions=self._pre_instructions, + post_instructions=self._post_instructions + ixs, + args=self._args, + ) + + def _build_context(self, opts: Optional[types.TxOpts]) -> Context: + return Context( + accounts=self._accounts, + remaining_accounts=self._remaining_accounts, + signers=self._signers, + pre_instructions=self._pre_instructions, + post_instructions=self._post_instructions, + options=opts, + ) + + +def _build_methods_item(idl_funcs: IdlFuncs) -> MethodsBuilder: + return MethodsBuilder( + idl_funcs=idl_funcs, + accounts={}, + remaining_accounts=[], + signers=[], + pre_instructions=[], + post_instructions=[], + args=[], + ) diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/rpc.py b/basics/anchorpy-main/src/anchorpy/program/namespace/rpc.py new file mode 100644 index 0000000..97da05f --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/rpc.py @@ -0,0 +1,71 @@ +"""This module contains code for generating RPC functions.""" +from typing import Any, Awaitable, Dict, Protocol + +from anchorpy_core.idl import IdlInstruction +from solana.rpc.commitment import Confirmed +from solana.rpc.core import RPCException +from solders.pubkey import Pubkey +from solders.signature import Signature + +from anchorpy.error import ProgramError +from anchorpy.program.context import EMPTY_CONTEXT, Context, _check_args_length +from anchorpy.program.namespace.transaction import _TransactionFn +from anchorpy.provider import Provider + + +class _RpcFn(Protocol): + """_RpcFn is a single RPC method generated from an IDL, sending a transaction paid for and signed by the configured provider.""" # noqa: E501 + + def __call__( + self, + *args: Any, + ctx: Context = EMPTY_CONTEXT, + ) -> Awaitable[Signature]: + """Call the function (this is just a protocol declaration). + + Args: + *args: The positional arguments for the program. The type and number + of these arguments depend on the program being used. + ctx: non-argument parameters to pass to the method. + """ + ... + + +def _build_rpc_item( # ts: RpcFactory + idl_ix: IdlInstruction, + tx_fn: _TransactionFn, + idl_errors: Dict[int, str], + provider: Provider, + program_id: Pubkey, +) -> _RpcFn: + """Build the function that sends transactions for the given method. + + Args: + idl_ix: The IDL instruction object. + tx_fn: The function that generates the `Transaction` to send. + idl_errors: Mapping of error code to error message. + provider: Anchor Provider instance. + program_id: The ID of the Anchor program. + + Returns: + The RPC function. + """ + + async def rpc_fn(*args: Any, ctx: Context = EMPTY_CONTEXT) -> Signature: + recent_blockhash = ( + await provider.connection.get_latest_blockhash(Confirmed) + ).value.blockhash + tx = tx_fn( + *args, payer=provider.wallet.payer, blockhash=recent_blockhash, ctx=ctx + ) + _check_args_length(idl_ix, args) + try: + return await provider.send(tx, ctx.options) + except RPCException as e: + err_info = e.args[0] + translated_err = ProgramError.parse(err_info, idl_errors, program_id) + if translated_err is not None: + raise translated_err from e + raise + + return rpc_fn diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/simulate.py b/basics/anchorpy-main/src/anchorpy/program/namespace/simulate.py new file mode 100644 index 0000000..d354cfc --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/simulate.py @@ -0,0 +1,94 @@ +"""This module contains code for creating simulate functions.""" +from typing import Any, Awaitable, Dict, NamedTuple, Protocol + +from anchorpy_core.idl import Idl, IdlInstruction +from solana.rpc.commitment import Confirmed +from solana.rpc.core import RPCException +from solders.pubkey import Pubkey + +from anchorpy.coder.coder import Coder +from anchorpy.error import ProgramError +from anchorpy.program.context import EMPTY_CONTEXT, Context, _check_args_length +from anchorpy.program.event import Event, EventParser +from anchorpy.program.namespace.transaction import _TransactionFn +from anchorpy.provider import Provider + + +class SimulateResponse(NamedTuple): + """The result of a simulate function call.""" + + events: list[Event] + raw: list[str] + + +class _SimulateFn(Protocol): + """A single method generated from an IDL. + + It simulates a method against a cluster configured by the provider, + returning a list of all the events and raw logs that were emitted + during the execution of the method. + """ + + def __call__( + self, + *args: Any, + ctx: Context = EMPTY_CONTEXT, + ) -> Awaitable[SimulateResponse]: + """Protocol definition. + + Args: + *args: The positional arguments for the program. The type and number + of these arguments depend on the program being used. + ctx: non-argument parameters to pass to the method. + + """ + + +def _build_simulate_item( + idl_ix: IdlInstruction, + tx_fn: _TransactionFn, + idl_errors: Dict[int, str], + provider: Provider, + coder: Coder, + program_id: Pubkey, + idl: Idl, +) -> _SimulateFn: + """Build the function to simulate transactions for a given method of a program. + + Args: + idl_ix: An IDL instruction object. + tx_fn: The function to generate the `Transaction` object. + idl_errors: Mapping of error code to message. + provider: A provider instance. + coder: The program's coder object. + program_id: The program ID. + idl: The parsed Idl instance. + + Returns: + The simulate function. + """ + + async def simulate_fn(*args: Any, ctx: Context = EMPTY_CONTEXT) -> SimulateResponse: + blockhash = ( + await provider.connection.get_latest_blockhash(Confirmed) + ).value.blockhash + tx = tx_fn(*args, payer=provider.wallet.payer, blockhash=blockhash, ctx=ctx) + _check_args_length(idl_ix, args) + resp = (await provider.simulate(tx, ctx.options)).value + resp_err = resp.err + logs = resp.logs or [] + if resp_err is None: + events = [] + if idl.events is not None: + parser = EventParser(program_id, coder) + parser.parse_logs(logs, lambda evt: events.append(evt)) + return SimulateResponse(events, logs) + else: + translated_err = ProgramError.parse_tx_error( + resp_err, idl_errors, program_id, logs + ) + if translated_err is not None: + raise translated_err + raise RPCException(resp_err) + + return simulate_fn diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/transaction.py b/basics/anchorpy-main/src/anchorpy/program/namespace/transaction.py new file mode 100644 index 0000000..635d114 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/transaction.py @@ -0,0 +1,65 @@ +"""This module deals with generating transactions.""" +from typing import Any, Protocol + +from anchorpy_core.idl import IdlInstruction +from more_itertools import unique_everseen +from solders.hash import Hash +from solders.instruction import Instruction +from solders.keypair import Keypair +from solders.message import Message +from solders.transaction import VersionedTransaction + +from anchorpy.program.context import EMPTY_CONTEXT, Context, _check_args_length +from anchorpy.program.namespace.instruction import _InstructionFn + + +class _TransactionFn(Protocol): + """A function to create a `Transaction` for a given program instruction.""" + + def __call__( + self, *args: Any, payer: Keypair, blockhash: Hash, ctx: Context = EMPTY_CONTEXT + ) -> VersionedTransaction: + """Make sure that the function looks like this. + + Args: + *args: The positional arguments for the program. The type and number + of these arguments depend on the program being used. + payer: The transaction fee payer. + blockhash: A recent blockhash. + ctx: non-argument parameters to pass to the method. + + """ + ... + + +# ts TransactionNamespaceFactory.build +def _build_transaction_fn( + idl_ix: IdlInstruction, ix_fn: _InstructionFn +) -> _TransactionFn: + """Build the function that generates Transaction objects. + + Args: + idl_ix: Instruction item from the IDL. + ix_fn (_InstructionFn): The function that generates instructions. + + Returns: + _TransactionFn: [description] + """ + + def tx_fn( + *args: Any, payer: Keypair, blockhash: Hash, ctx: Context = EMPTY_CONTEXT + ) -> VersionedTransaction: + ixns: list[Instruction] = [] + _check_args_length(idl_ix, args) + if ctx.pre_instructions: + ixns.extend(ctx.pre_instructions) + ixns.append(ix_fn(*args, ctx=ctx)) + if ctx.post_instructions: + ixns.extend(ctx.post_instructions) + ctx_signers = ctx.signers + signers = [] if ctx_signers is None else ctx_signers + all_signers = list(unique_everseen([payer, *signers])) + msg = Message.new_with_blockhash(ixns, payer.pubkey(), blockhash) + return VersionedTransaction(msg, all_signers) + + return tx_fn diff --git a/basics/anchorpy-main/src/anchorpy/program/namespace/types.py b/basics/anchorpy-main/src/anchorpy/program/namespace/types.py new file mode 100644 index 0000000..47b6711 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/program/namespace/types.py @@ -0,0 +1,27 @@ +"""This module contains code for handling user-defined types.""" +from typing import Any, Type + +from anchorpy_core.idl import Idl + +from anchorpy.coder.idl import _idl_typedef_to_python_type + + +def _build_types( + idl: Idl, +) -> dict[str, Type[Any]]: + """Generate the `.type` namespace. + + Args: + idl: A parsed `Idl` instance. + + Returns: + Mapping of type name to Python object. + """ + result = {} + for idl_type in idl.types: + try: + python_type = _idl_typedef_to_python_type(idl_type, idl.types) + except ValueError: + continue + result[idl_type.name] = python_type + return result diff --git a/basics/anchorpy-main/src/anchorpy/provider.py b/basics/anchorpy-main/src/anchorpy/provider.py new file mode 100644 index 0000000..507ccdb --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/provider.py @@ -0,0 +1,219 @@ +"""This module contains the Provider class and associated utilities.""" +from __future__ import annotations + +import json +from os import environ, getenv +from pathlib import Path +from types import MappingProxyType +from typing import List, Optional, Sequence, Union + +from solana.rpc import types +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Confirmed, Finalized, Processed +from solana.transaction import Transaction +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.rpc.responses import SimulateTransactionResp +from solders.signature import Signature +from solders.transaction import VersionedTransaction + +DEFAULT_OPTIONS = types.TxOpts(skip_confirmation=False, preflight_commitment=Processed) +COMMITMENT_RANKS = MappingProxyType({Processed: 0, Confirmed: 1, Finalized: 2}) + + +class Provider: + """The network and wallet context used to send transactions paid for and signed by the provider.""" # noqa: E501 + + def __init__( + self, + connection: AsyncClient, + wallet: Wallet, + opts: types.TxOpts = DEFAULT_OPTIONS, + ) -> None: + """Initialize the Provider. + + Args: + connection: The cluster connection where the program is deployed. + wallet: The wallet used to pay for and sign all transactions. + opts: Transaction confirmation options to use by default. + """ + self.connection = connection + self.wallet = wallet + self.opts = opts + + @classmethod + def local( + cls, url: Optional[str] = None, opts: types.TxOpts = DEFAULT_OPTIONS + ) -> Provider: + """Create a `Provider` with a wallet read from the local filesystem. + + Args: + url: The network cluster url. + opts: The default transaction confirmation options. + """ + connection = AsyncClient(url, opts.preflight_commitment) + wallet = Wallet.local() + return cls(connection, wallet, opts) + + @classmethod + def readonly( + cls, url: Optional[str] = None, opts: types.TxOpts = DEFAULT_OPTIONS + ) -> Provider: + """Create a `Provider` that can only fetch data, not send transactions. + + Args: + url: The network cluster url. + opts: The default transaction confirmation options. + """ + connection = AsyncClient(url, opts.preflight_commitment) + wallet = Wallet.dummy() + return cls(connection, wallet, opts) + + @classmethod + def env(cls) -> Provider: + """Create a `Provider` using the `ANCHOR_PROVIDER_URL` environment variable.""" + url = environ["ANCHOR_PROVIDER_URL"] + options = DEFAULT_OPTIONS + connection = AsyncClient(url, options.preflight_commitment) + wallet = Wallet.local() + return cls(connection, wallet, options) + + async def simulate( + self, + tx: Union[Transaction, VersionedTransaction], + opts: Optional[types.TxOpts] = None, + ) -> SimulateTransactionResp: + """Simulate the given transaction, returning emitted logs from execution. + + Args: + tx: The transaction to send. + signers: The set of signers in addition to the provider wallet that will + sign the transaction. + opts: Transaction confirmation options. + + Returns: + The transaction simulation result. + """ + if opts is None: + opts = self.opts + return await self.connection.simulate_transaction( + tx, sig_verify=True, commitment=opts.preflight_commitment + ) + + async def send( + self, + tx: Union[Transaction, VersionedTransaction], + opts: Optional[types.TxOpts] = None, + ) -> Signature: + """Send the given transaction, paid for and signed by the provider's wallet. + + Args: + tx: The transaction to send. + signers: The set of signers in addition to the provider wallet that will + sign the transaction. + opts: Transaction confirmation options. + + Returns: + The transaction signature from the RPC server. + """ + if opts is None: + opts = self.opts + raw = tx.serialize() if isinstance(tx, Transaction) else bytes(tx) + resp = await self.connection.send_raw_transaction(raw, opts=opts) + return resp.value + + async def send_all( + self, + txs: Sequence[Union[Transaction, VersionedTransaction]], + opts: Optional[types.TxOpts] = None, + ) -> list[Signature]: + """Similar to `send`, but for an array of transactions and signers. + + Args: + txs: a list of transaction objects. + opts: Transaction confirmation options. + + Returns: + The transaction signatures from the RPC server. + """ + if opts is None: + opts = self.opts + sigs = [] + for tx in txs: + raw = tx.serialize() if isinstance(tx, Transaction) else bytes(tx) + resp = await self.connection.send_raw_transaction(raw, opts=opts) + sigs.append(resp.value) + return sigs + + async def __aenter__(self) -> Provider: + """Use as a context manager.""" + await self.connection.__aenter__() + return self + + async def __aexit__(self, _exc_type, _exc, _tb): + """Exit the context manager.""" + await self.close() + + async def close(self) -> None: + """Use this when you are done with the connection.""" + await self.connection.close() + + +class Wallet: + """Python wallet object.""" + + def __init__(self, payer: Keypair): + """Initialize the wallet. + + Args: + payer: the Keypair used to sign transactions. + """ + self.payer = payer + + @property + def public_key(self) -> Pubkey: + """Get the public key of the wallet.""" + return self.payer.pubkey() + + def sign_transaction(self, tx: Transaction) -> Transaction: + """Sign a transaction using the wallet's keypair. + + Args: + tx: The transaction to sign. + + Returns: + The signed transaction. + """ + tx.sign(self.payer) + return tx + + def sign_all_transactions(self, txs: list[Transaction]) -> list[Transaction]: + """Sign a list of transactions using the wallet's keypair. + + Args: + txs: The transactions to sign. + + Returns: + The signed transactions. + """ + for tx in txs: + tx.sign_partial(self.payer) + return txs + + @classmethod + def local(cls) -> Wallet: + """Create a wallet instance from the filesystem. + + Uses the path at the ANCHOR_WALLET env var if set, + otherwise uses ~/.config/solana/id.json. + """ + path = Path(getenv("ANCHOR_WALLET", Path.home() / ".config/solana/id.json")) + with path.open() as f: + keypair: List[int] = json.load(f) + return cls(Keypair.from_bytes(keypair)) + + @classmethod + def dummy(cls) -> Wallet: + """Create a dummy wallet instance that won't be used to sign transactions.""" + keypair = Keypair.from_bytes([0] * 64) + return cls(keypair) diff --git a/basics/anchorpy-main/src/anchorpy/py.typed b/basics/anchorpy-main/src/anchorpy/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/src/anchorpy/pytest_plugin.py b/basics/anchorpy-main/src/anchorpy/pytest_plugin.py new file mode 100644 index 0000000..ba876ff --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/pytest_plugin.py @@ -0,0 +1,296 @@ +"""This module provides the `localnet_fixture` fixture factory.""" +import os +import signal +import subprocess +from contextlib import suppress +from pathlib import Path +from typing import AsyncGenerator, Callable, Literal, Optional, Sequence, Tuple, Union + +from pytest import fixture +from pytest_asyncio import fixture as async_fixture +from pytest_xprocess import getrootdir +from solders.account import Account +from solders.pubkey import Pubkey +from xprocess import ProcessStarter, XProcess, XProcessInfo + +from anchorpy.program.core import Program +from anchorpy.workspace import close_workspace, create_workspace + +with suppress(ImportError): + from solders import bankrun + +_Scope = Literal["session", "package", "module", "class", "function"] + + +class _FixedXProcessInfo(XProcessInfo): + def terminate(self, timeout=60): # noqa: ARG002 + if not self.pid: + return 0 + try: + pgid = os.getpgid(self.pid) + except ProcessLookupError: + return 0 + try: + os.killpg(pgid, signal.SIGTERM) + except OSError as err: + print(f"Error while terminating process {err}") + return -1 + return 1 + + +class _FixedXProcess(XProcess): + def getinfo(self, name: str) -> _FixedXProcessInfo: + """Return Process Info for the given external process. + + Args: + name: Name of the external process. + """ + return _FixedXProcessInfo(self.rootdir, name) + + def ensure( + self, name: str, preparefunc: ProcessStarter, restart: bool = False + ) -> tuple: + """Return (PID, logfile) from a newly started or already running process. + + Args: + name: Name of the external process, used for caching info across test runs. + preparefunc: A subclass of ProcessStarter. + restart: Force restarting the process if it is running. + + Raises: + RuntimeError: If process fails to start within the required time. + + Returns: + (PID, logfile) logfile will be seeked to the end if the + server was running, otherwise seeked to the line after + where the wait pattern matched. + """ + info = self.getinfo(name) + if not restart and not info.isrunning(): + restart = True + + if restart: + # ensure the process is terminated first + if info.pid is not None: + info.terminate() + + controldir = info.controldir.ensure(dir=1) + starter = preparefunc(controldir, self) + args = [str(x) for x in starter.args] + self.log.debug("%s$ %s", controldir, " ".join(args)) + stdout = open(str(info.logpath), "wb", 0) # noqa: SIM115 + + # is env still necessary? we could pass all in popen_kwargs + kwargs = {"env": starter.env} + + popen_kwargs = { + "stdout": stdout, + "stderr": subprocess.STDOUT, + # this gives the user the ability to + # override the previous keywords if + # desired + **starter.popen_kwargs, + } + + kwargs["close_fds"] = True + + # keep references of all popen + # and info objects for cleanup + self._info_objects.append((info, starter.terminate_on_interrupt)) + popen_instance = subprocess.Popen( + args, + **popen_kwargs, + **kwargs, # type: ignore + ) + self._popen_instances.append(popen_instance) + + info.pid = pid = self._popen_instances[-1].pid + info.pidpath.write(str(pid)) + self.log.debug("process %r started pid=%s", name, pid) + stdout.close() + + # keep track of all file handles so we can + # cleanup later during teardown phase + self._file_handles.append(info.logpath.open()) + + if not restart: + self._file_handles[-1].seek(0, 2) + else: + if not starter.wait(self._file_handles[-1]): + raise RuntimeError( + f"Could not start process {name}, the specified " + f"log pattern was not found within {starter.max_read_lines} lines." + ) + self.log.debug("%s process startup detected", name) + + pytest_extlogfiles = self.config.__dict__.setdefault("_extlogfiles", {}) + pytest_extlogfiles[name] = self._file_handles[-1] + self.getinfo(name) + + return info.pid, info.logpath + + +@async_fixture(scope="session") +def _fixed_xprocess(request): + """Yield session-scoped XProcess helper to manage long-running processes required for testing.""" # noqa: E501 + rootdir = getrootdir(request.config) + with _FixedXProcess(request.config, rootdir) as xproc: + # pass in xprocess object into pytest_unconfigure + # through config for proper cleanup during teardown + request.config._xprocess = xproc + yield xproc + + +def localnet_fixture( + path: Path, + scope: _Scope = "module", + timeout_seconds: int = 60, + build_cmd: Optional[str] = None, +) -> Callable: + """Create a fixture that sets up and tears down a localnet instance with workspace programs deployed. + + Args: + path: Path to root of the Anchor project. + scope: Pytest fixture scope. + timeout_seconds: Time to wait for Anchor localnet to start. + build_cmd: Command to run before `anchor localnet`. Defaults to `anchor build`. + + Returns: + A localnet fixture for use with pytest. + """ # noqa: E501,D202 + + @fixture(scope=scope) + def _localnet_fixture(_fixed_xprocess): + class Starter(ProcessStarter): + # startup pattern + pattern = "JSON RPC URL" + terminate_on_interrupt = True + # command to start process + args = ["anchor", "localnet", "--skip-build"] + timeout = timeout_seconds + popen_kwargs = { + "cwd": path, + "start_new_session": True, + } + max_read_lines = 1_000 + # command to start process + + actual_build_cmd = "anchor build" if build_cmd is None else build_cmd + subprocess.run(actual_build_cmd, cwd=path, check=True, shell=True) + # ensure process is running and return its logfile + logfile = _fixed_xprocess.ensure("localnet", Starter) + + yield logfile + + # clean up whole process tree afterwards + _fixed_xprocess.getinfo("localnet").terminate() + + return _localnet_fixture + + +# Should figure out how to reuse localnet_fixture +# instead of copy-pasting (Pytest didn't like it). +def workspace_fixture( + path: Union[Path, str], + scope: _Scope = "module", + timeout_seconds: int = 60, + build_cmd: Optional[str] = None, +) -> Callable: + """Create a fixture that sets up and tears down a localnet instance and returns a workspace dict. + + Equivalent to combining `localnet_fixture`, `create_workspace` and `close_workspace`. + + Args: + path: Path to root of the Anchor project. + scope: Pytest fixture scope. + timeout_seconds: Time to wait for Anchor localnet to start. + build_cmd: Command to run before `anchor localnet`. Defaults to `anchor build`. + + Returns: + A workspace fixture for use with pytest. + """ # noqa: E501,D202 + + @async_fixture(scope=scope) + async def _workspace_fixture( + _fixed_xprocess, + ) -> AsyncGenerator[dict[str, Program], None]: + class Starter(ProcessStarter): + # startup pattern + pattern = "JSON RPC URL" + terminate_on_interrupt = True + # command to start process + args = ["anchor", "localnet", "--skip-build"] + timeout = timeout_seconds + popen_kwargs = { + "cwd": path, + "start_new_session": True, + } + max_read_lines = 1_000 + # command to start process + + actual_build_cmd = "anchor build" if build_cmd is None else build_cmd + subprocess.run(actual_build_cmd, cwd=path, check=True, shell=True) + # ensure process is running + _ = _fixed_xprocess.ensure("localnet", Starter) + ws = create_workspace(path) + yield ws + await close_workspace(ws) + + # clean up whole process tree afterwards + _fixed_xprocess.getinfo("localnet").terminate() + + return _workspace_fixture + + +async def _bankrun_helper( + path: Union[Path, str], + build_cmd: Optional[str] = None, + accounts: Optional[Sequence[Tuple[Pubkey, Account]]] = None, + compute_max_units: Optional[int] = None, + transaction_account_lock_limit: Optional[int] = None, +) -> "bankrun.ProgramTestContext": + actual_build_cmd = "anchor build" if build_cmd is None else build_cmd + subprocess.run(actual_build_cmd, cwd=path, check=True, shell=True) + path_to_use = Path(path) + return await bankrun.start_anchor( + path_to_use, + accounts=accounts, + compute_max_units=compute_max_units, + transaction_account_lock_limit=transaction_account_lock_limit, + ) + + +def bankrun_fixture( + path: Union[Path, str], + scope: _Scope = "module", + build_cmd: Optional[str] = None, + accounts: Optional[Sequence[Tuple[Pubkey, Account]]] = None, + compute_max_units: Optional[int] = None, + transaction_account_lock_limit: Optional[int] = None, +) -> "bankrun.ProgramTestContext": + """Create a fixture that builds the project and starts a bankrun with all the programs in the workspace deployed. + + Args: + path: Path to root of the Anchor project. + scope: Pytest fixture scope. + build_cmd: Command to build the project. Defaults to `anchor build`. + accounts: A sequence of (address, account_object) tuples, indicating + what data to write to the given addresses. + compute_max_units: Override the default compute unit limit for a transaction. + transaction_account_lock_limit: Override the default transaction account lock limit. + + Returns: + A bankrun fixture for use with pytest. + """ # noqa: E501,D202 + + @async_fixture(scope=scope) + async def _bankrun_fixture() -> bankrun.ProgramTestContext: + return await _bankrun_helper( + path, + build_cmd, + accounts, + compute_max_units, + transaction_account_lock_limit, + ) + + return _bankrun_fixture diff --git a/basics/anchorpy-main/src/anchorpy/template.py b/basics/anchorpy-main/src/anchorpy/template.py new file mode 100644 index 0000000..cf0a1ad --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/template.py @@ -0,0 +1,31 @@ +INIT_TESTS = '''"""AnchorPy integration tests.""" +import asyncio +from pytest import fixture, mark + +from anchorpy import Program +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType + + +@fixture(scope="module") +def event_loop(): + """Create a module-scoped event loop so we can use module-scope async fixtures.""" + loop = asyncio.get_event_loop_policy().new_event_loop() # noqa: DAR301 + yield loop + loop.close() + + +workspace = workspace_fixture(".") + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + """Create a Program instance.""" + return workspace["{}"] + + +@mark.asyncio +async def test_init(program: Program) -> None: + """Test that the initialize function is invoked successfully.""" + await program.rpc["initialize"]() +''' diff --git a/basics/anchorpy-main/src/anchorpy/utils/__init__.py b/basics/anchorpy-main/src/anchorpy/utils/__init__.py new file mode 100644 index 0000000..d701d15 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/utils/__init__.py @@ -0,0 +1,4 @@ +"""Various utility functions.""" +from anchorpy.utils import rpc, token + +__all__ = ["rpc", "token"] diff --git a/basics/anchorpy-main/src/anchorpy/utils/rpc.py b/basics/anchorpy-main/src/anchorpy/utils/rpc.py new file mode 100644 index 0000000..12ab015 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/utils/rpc.py @@ -0,0 +1,157 @@ +"""This module contains the invoke function.""" +from asyncio import gather +from base64 import b64decode +from dataclasses import dataclass +from typing import Any, NamedTuple, Optional + +import jsonrpcclient +import zstandard +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +from solana.rpc.core import RPCException +from solana.transaction import Transaction +from solders.instruction import AccountMeta, Instruction +from solders.pubkey import Pubkey +from solders.signature import Signature +from toolz import concat, partition_all + +from anchorpy.program.common import AddressType, translate_address +from anchorpy.provider import Provider + +_GET_MULTIPLE_ACCOUNTS_LIMIT = 100 +_MAX_ACCOUNT_SIZE = 10 * 1048576 + + +class AccountInfo(NamedTuple): + """Information describing an account. + + Attributes: + executable: `True` if this account's data contains a loaded program. + owner: Identifier of the program that owns the account. + lamports: Number of lamports assigned to the account. + data: Optional data assigned to the account. + rent_epoch: Optional rent epoch info for for account. + """ + + executable: bool + owner: Pubkey + lamports: int + data: bytes + rent_epoch: Optional[int] + + +async def invoke( + program_id: AddressType, + provider: Provider, + accounts: Optional[list[AccountMeta]] = None, + data: Optional[bytes] = None, +) -> Signature: + """Send a transaction to a program with the given accounts and instruction data. + + Args: + program_id: The program ID + provider: the `Provider` instance. + accounts: `AccountMeta` objects. + data: The transaction data. + + Returns: + The transaction signature. + """ + translated_program_id = translate_address(program_id) + tx = Transaction() + tx.add( + Instruction( + program_id=translated_program_id, + accounts=[] if accounts is None else accounts, + data=bytes(0) if data is None else data, + ), + ) + return await provider.send(tx) + + +@dataclass +class _MultipleAccountsItem: + pubkey: Pubkey + account: AccountInfo + + +async def get_multiple_accounts( + connection: AsyncClient, + pubkeys: list[Pubkey], + batch_size: int = 3, + commitment: Optional[Commitment] = None, +) -> list[Optional[_MultipleAccountsItem]]: + """Fetch multiple account infos through batched `getMultipleAccount` RPC requests. + + Args: + connection: The `solana-py` client object. + pubkeys: Pubkeys to fetch. + batch_size: The number of `getMultipleAccount` objects to include in each + HTTP request. + commitment: Bank state to query. + + Returns: + Account infos and pubkeys. + """ + pubkeys_per_network_request = _GET_MULTIPLE_ACCOUNTS_LIMIT * batch_size + chunks = partition_all(pubkeys_per_network_request, pubkeys) + awaitables = [ + _get_multiple_accounts_core(connection, pubkeys_chunk, commitment) + for pubkeys_chunk in chunks + ] + results = await gather(*awaitables, return_exceptions=False) + return list(concat(results)) + + +async def _get_multiple_accounts_core( + connection: AsyncClient, pubkeys: list[Pubkey], commitment: Optional[Commitment] +) -> list[Optional[_MultipleAccountsItem]]: + pubkey_batches = partition_all(_GET_MULTIPLE_ACCOUNTS_LIMIT, pubkeys) + rpc_requests: list[dict[str, Any]] = [] + commitment_to_use = connection._commitment if commitment is None else commitment + for pubkey_batch in pubkey_batches: + pubkeys_to_send = [str(pubkey) for pubkey in pubkey_batch] + rpc_request = jsonrpcclient.request( + "getMultipleAccounts", + params=[ + pubkeys_to_send, + {"encoding": "base64+zstd", "commitment": commitment_to_use}, + ], + ) + rpc_requests.append(rpc_request) + resp = await connection._provider.session.post( + connection._provider.endpoint_uri, + json=rpc_requests, + headers={"content-encoding": "gzip"}, + ) + parsed = jsonrpcclient.parse(resp.json()) + result: list[Optional[_MultipleAccountsItem]] = [] + dctx = zstandard.ZstdDecompressor() + idx = 0 + for rpc_result in parsed: + if isinstance(rpc_result, jsonrpcclient.Error): + raise RPCException( + f"Failed to get info about accounts: {rpc_result.message}" + ) + for account in rpc_result.result["value"]: + if account is None: + result.append(None) + else: + acc_info_data = account["data"][0] + decoded = b64decode(acc_info_data) + decompressed = dctx.decompress( + decoded, max_output_size=_MAX_ACCOUNT_SIZE + ) + acc_info = AccountInfo( + executable=account["executable"], + owner=Pubkey.from_string(account["owner"]), + lamports=account["lamports"], + data=decompressed, + rent_epoch=account["rentEpoch"], + ) + multiple_accounts_item = _MultipleAccountsItem( + pubkey=pubkeys[idx], account=acc_info + ) + result.append(multiple_accounts_item) + idx += 1 + return result diff --git a/basics/anchorpy-main/src/anchorpy/utils/token.py b/basics/anchorpy-main/src/anchorpy/utils/token.py new file mode 100644 index 0000000..1289478 --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/utils/token.py @@ -0,0 +1,318 @@ +"""This module contains utilities for the SPL Token Program.""" +from typing import Optional + +from solana.rpc.commitment import Confirmed +from solders.instruction import Instruction +from solders.keypair import Keypair +from solders.message import Message +from solders.pubkey import Pubkey +from solders.rpc.responses import GetAccountInfoResp +from solders.system_program import CreateAccountParams, create_account +from solders.transaction import VersionedTransaction +from spl.token._layouts import ACCOUNT_LAYOUT, MINT_LAYOUT +from spl.token.async_client import AsyncToken +from spl.token.constants import TOKEN_PROGRAM_ID +from spl.token.core import AccountInfo, MintInfo +from spl.token.instructions import ( + InitializeAccountParams, + InitializeMintParams, + MintToParams, + initialize_account, + initialize_mint, + mint_to, +) + +from anchorpy.provider import Provider + + +async def create_token_account( + prov: Provider, + mint: Pubkey, + owner: Pubkey, +) -> Pubkey: + """Create a token account. + + Args: + prov: An anchorpy Provider instance. + mint: The pubkey of the token's mint. + owner: User account that will own the new account. + + Returns: + The pubkey of the new account. + """ + token = AsyncToken(prov.connection, mint, TOKEN_PROGRAM_ID, prov.wallet.payer) + return await token.create_account(owner) + + +async def create_token_account_instrs( + provider: Provider, + new_account_pubkey: Pubkey, + mint: Pubkey, + owner: Pubkey, +) -> tuple[Instruction, Instruction]: + """Generate instructions for creating a token account. + + Args: + provider: An anchorpy Provider instance. + new_account_pubkey: The pubkey of the new account. + mint: The pubkey of the token's mint. + owner: User account that will own the new account. + + Returns: + Transaction instructions to create the new account. + """ + mbre_resp = await provider.connection.get_minimum_balance_for_rent_exemption(165) + lamports = mbre_resp.value + return ( + create_account( + CreateAccountParams( + from_pubkey=provider.wallet.public_key, + to_pubkey=new_account_pubkey, + space=165, + lamports=lamports, + owner=TOKEN_PROGRAM_ID, + ) + ), + initialize_account( + InitializeAccountParams( + account=new_account_pubkey, + mint=mint, + owner=owner, + program_id=TOKEN_PROGRAM_ID, + ) + ), + ) + + +async def create_mint_and_vault( + provider: Provider, + amount: int, + owner: Optional[Pubkey] = None, + decimals: Optional[int] = None, +) -> tuple[Pubkey, Pubkey]: + """Create a mint and a vault, then mint tokens to the vault. + + Args: + provider: An anchorpy Provider instance. + amount: The amount of tokens to mint to the vault. + owner: User account that will own the new account. + decimals: The number of decimal places for the token to support. + + Returns: + The mint and vault pubkeys. + """ + actual_owner = provider.wallet.public_key if owner is None else owner + mint = Keypair() + vault = Keypair() + mint_space = 82 + create_mint_mbre_resp = ( + await provider.connection.get_minimum_balance_for_rent_exemption(mint_space) + ) + create_mint_mbre = create_mint_mbre_resp.value + create_mint_account_params = CreateAccountParams( + from_pubkey=provider.wallet.public_key, + to_pubkey=mint.pubkey(), + space=mint_space, + lamports=create_mint_mbre, + owner=TOKEN_PROGRAM_ID, + ) + create_mint_account_instruction = create_account( + create_mint_account_params, + ) + init_mint_instruction = initialize_mint( + InitializeMintParams( + mint=mint.pubkey(), + decimals=0 if decimals is None else decimals, + mint_authority=provider.wallet.public_key, + program_id=TOKEN_PROGRAM_ID, + ), + ) + vault_space = 165 + create_vault_mbre_resp = ( + await provider.connection.get_minimum_balance_for_rent_exemption(vault_space) + ) + create_vault_mbre = create_vault_mbre_resp.value + create_vault_account_instruction = create_account( + CreateAccountParams( + from_pubkey=provider.wallet.public_key, + to_pubkey=vault.pubkey(), + space=vault_space, + lamports=create_vault_mbre, + owner=TOKEN_PROGRAM_ID, + ), + ) + init_vault_instruction = initialize_account( + InitializeAccountParams( + program_id=TOKEN_PROGRAM_ID, + account=vault.pubkey(), + mint=mint.pubkey(), + owner=actual_owner, + ), + ) + mint_to_instruction = mint_to( + MintToParams( + program_id=TOKEN_PROGRAM_ID, + mint=mint.pubkey(), + dest=vault.pubkey(), + amount=amount, + mint_authority=provider.wallet.public_key, + ), + ) + blockhash = ( + await provider.connection.get_latest_blockhash(Confirmed) + ).value.blockhash + msg = Message.new_with_blockhash( + [ + create_mint_account_instruction, + init_mint_instruction, + create_vault_account_instruction, + init_vault_instruction, + mint_to_instruction, + ], + provider.wallet.public_key, + blockhash, + ) + tx = VersionedTransaction(msg, [provider.wallet.payer, mint, vault]) + await provider.send(tx) + return mint.pubkey(), vault.pubkey() + + +def parse_token_account(info: GetAccountInfoResp) -> AccountInfo: + """Parse `AccountInfo` from RPC response. + + Args: + info: the `get_account_info` RPC response. + + Raises: + ValueError: If the fetched data is the wrong size. + AttributeError: If the account is not owned by the token program. + + Returns: + The parsed `AccountInfo`. + """ + val = info.value + if not val: + raise ValueError("Invalid account owner") + + if val.owner != TOKEN_PROGRAM_ID: + raise AttributeError("Invalid account owner") + + bytes_data = val.data + if len(bytes_data) != ACCOUNT_LAYOUT.sizeof(): + raise ValueError("Invalid account size") + + decoded_data = ACCOUNT_LAYOUT.parse(bytes_data) + + mint = Pubkey(decoded_data.mint) + owner = Pubkey(decoded_data.owner) + amount = decoded_data.amount + + if decoded_data.delegate_option == 0: + delegate = None + delegated_amount = 0 + else: + delegate = Pubkey(decoded_data.delegate) + delegated_amount = decoded_data.delegated_amount + + is_initialized = decoded_data.state != 0 + is_frozen = decoded_data.state == 2 + + if decoded_data.is_native_option == 1: + rent_exempt_reserve = decoded_data.is_native + is_native = True + else: + rent_exempt_reserve = None + is_native = False + + if decoded_data.close_authority_option == 0: + close_authority = None + else: + close_authority = Pubkey(decoded_data.owner) + + return AccountInfo( + mint, + owner, + amount, + delegate, + delegated_amount, + is_initialized, + is_frozen, + is_native, + rent_exempt_reserve, + close_authority, + ) + + +async def get_token_account(provider: Provider, addr: Pubkey) -> AccountInfo: + """Retrieve token account information. + + Args: + provider: The anchorpy Provider instance. + addr: The pubkey of the token account. + + Returns: + The parsed `AccountInfo` of the token account. + """ + depositor_acc_info_raw = await provider.connection.get_account_info(addr) + return parse_token_account(depositor_acc_info_raw) + + +async def get_mint_info( + provider: Provider, + addr: Pubkey, +) -> MintInfo: + """Retrieve mint information. + + Args: + provider: The anchorpy Provider instance. + addr: The pubkey of the mint. + + Returns: + The parsed `MintInfo`. + """ + depositor_acc_info_raw = await provider.connection.get_account_info(addr) + return parse_mint_account(depositor_acc_info_raw) + + +def parse_mint_account(info: GetAccountInfoResp) -> MintInfo: + """Parse raw RPC response into `MintInfo`. + + Args: + info: The RPC response from calling `.get_account_info` for the mint pubkey. + + Raises: + AttributeError: If the account is not owned by the Token Program. + ValueError: If the fetched data is the wrong size. + + Returns: + The parsed `MintInfo`. + """ + val = info.value + if val is None: + raise ValueError("Account does not exist.") + owner = val.owner + if owner != TOKEN_PROGRAM_ID: + raise AttributeError(f"Invalid mint owner: {owner}") + + bytes_data = val.data + if len(bytes_data) != MINT_LAYOUT.sizeof(): + raise ValueError("Invalid mint size") + + decoded_data = MINT_LAYOUT.parse(bytes_data) + decimals = decoded_data.decimals + + mint_authority = ( + None + if decoded_data.mint_authority_option == 0 + else Pubkey(decoded_data.mint_authority) + ) + + supply = decoded_data.supply + is_initialized = decoded_data.is_initialized != 0 + + if decoded_data.freeze_authority_option == 0: + freeze_authority = None + else: + freeze_authority = Pubkey(decoded_data.freeze_authority) + + return MintInfo(mint_authority, supply, decimals, is_initialized, freeze_authority) diff --git a/basics/anchorpy-main/src/anchorpy/workspace.py b/basics/anchorpy-main/src/anchorpy/workspace.py new file mode 100644 index 0000000..276015c --- /dev/null +++ b/basics/anchorpy-main/src/anchorpy/workspace.py @@ -0,0 +1,52 @@ +"""This module contains code for creating the Anchor workspace.""" +from pathlib import Path +from typing import Dict, Optional, Union + +import toml # type: ignore +from anchorpy_core.idl import Idl +from solders.pubkey import Pubkey + +from anchorpy.program.core import Program +from anchorpy.provider import Provider + +WorkspaceType = Dict[str, Program] + + +def create_workspace( + path: Optional[Union[Path, str]] = None, url: Optional[str] = None +) -> WorkspaceType: + """Get a workspace from the provided path to the project root. + + Args: + path: The path to the project root. Defaults to the current working + directory if omitted. + url: The URL of the JSON RPC. Defaults to http://localhost:8899. + + Returns: + Mapping of program name to Program object. + """ + result = {} + project_root = Path.cwd() if path is None else Path(path) + idl_folder = project_root / "target/idl" + localnet_programs: dict[str, str] = toml.load(project_root / "Anchor.toml")[ + "programs" + ]["localnet"] + for file in idl_folder.iterdir(): + raw = file.read_text() + idl = Idl.from_json(raw) + name = idl.name + program_id = Pubkey.from_string(localnet_programs[name]) + program = Program(idl, program_id, Provider.local(url)) + result[idl.name] = program + return result + + +async def close_workspace(workspace: WorkspaceType) -> None: + """Close the HTTP clients of all the programs in the workspace. + + Args: + workspace: The workspace to close. + """ + for program in workspace.values(): + # could do this in a faster way but there's probably no point. + await program.close() diff --git a/basics/anchorpy-main/tests/__init__.py b/basics/anchorpy-main/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/tests/client-gen/__init__.py b/basics/anchorpy-main/tests/client-gen/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/tests/client-gen/example-program/Anchor.toml b/basics/anchorpy-main/tests/client-gen/example-program/Anchor.toml new file mode 100644 index 0000000..d6d5c12 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example-program/Anchor.toml @@ -0,0 +1,12 @@ +[programs.localnet] +example_program = "3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8" + +[registry] +url = "https://anchor.projectserum.com" + +[provider] +cluster = "localnet" +wallet = "~/.config/solana/id.json" + +[features] +seeds = true diff --git a/basics/anchorpy-main/tests/client-gen/example-program/Cargo.lock b/basics/anchorpy-main/tests/client-gen/example-program/Cargo.lock new file mode 100644 index 0000000..17ca9f0 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example-program/Cargo.lock @@ -0,0 +1,1562 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.7", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "regex", + "syn 1.0.102", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3bcd731f21048a032be27c7791701120e44f3f6371358fc4261a7f716283d29" +dependencies = [ + "anchor-syn", + "anyhow", + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.102", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" +dependencies = [ + "anchor-syn", + "proc-macro2", + "syn 1.0.102", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "anchor-attribute-interface" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6700a6f5c888a9c33fe8afc0c64fd8575fa28d05446037306d0f96102ae4480" +dependencies = [ + "anchor-syn", + "anyhow", + "heck", + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "anchor-attribute-state" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "anchor-lang" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662ceafe667448ee4199a4be2ee83b6bb76da28566eee5cea05f96ab38255af8" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-interface", + "anchor-attribute-program", + "anchor-attribute-state", + "anchor-derive-accounts", + "arrayref", + "base64 0.13.0", + "bincode", + "borsh", + "bytemuck", + "solana-program", + "thiserror", +] + +[[package]] +name = "anchor-syn" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0418bcb5daac3b8cb1b60d8fdb1d468ca36f5509f31fb51179326fae1028fdcc" +dependencies = [ + "anyhow", + "bs58 0.3.1", + "heck", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "serde", + "serde_json", + "sha2 0.9.9", + "syn 1.0.102", + "thiserror", +] + +[[package]] +name = "anyhow" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "blake3" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.5", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn 1.0.102", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "bs58" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9e1f5fa78f69496407a27ae9ed989e3c3b072310286f5ef385525e4cbc24a9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "example-program" +version = "0.1.0" +dependencies = [ + "anchor-lang", +] + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "serde", + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac", +] + +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "rayon", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", + "version_check", + "yansi", +] + +[[package]] +name = "quote" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" + +[[package]] +name = "serde" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "serde_json" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.5", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.5", + "keccak", +] + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "solana-frozen-abi" +version = "1.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a100b7fa8198c20354eb7256c0d9789107d8a62280221f3efe15f7c9dc4cec" +dependencies = [ + "ahash", + "blake3", + "block-buffer 0.9.0", + "bs58 0.4.0", + "bv", + "byteorder", + "cc", + "either", + "generic-array", + "getrandom 0.1.16", + "hashbrown 0.12.3", + "im", + "lazy_static", + "log", + "memmap2", + "once_cell", + "rand_core 0.6.4", + "rustc_version", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.6", + "solana-frozen-abi-macro", + "subtle", + "thiserror", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f527f44601b35dd67d11bc72f2f7512976a466f9304ef574b87dac83ced8a42" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.102", +] + +[[package]] +name = "solana-program" +version = "1.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ad5f48743ce505f6139a07e20aecdc689def12da7230fed661c2073ab97df8" +dependencies = [ + "base64 0.13.0", + "bincode", + "bitflags", + "blake3", + "borsh", + "borsh-derive", + "bs58 0.4.0", + "bv", + "bytemuck", + "cc", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.7", + "itertools", + "js-sys", + "lazy_static", + "libc", + "libsecp256k1", + "log", + "memoffset 0.6.5", + "num-derive", + "num-traits", + "parking_lot", + "rand", + "rand_chacha", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.6", + "sha3", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk-macro", + "thiserror", + "tiny-bip39", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bbc3ab3070c090e1a18fd5a0a07d729d0db2bc8524414dc3e16504286d38049" +dependencies = [ + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.102", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac", + "once_cell", + "pbkdf2", + "rand", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.102", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.102", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.26", +] diff --git a/basics/anchorpy-main/tests/client-gen/example-program/Cargo.toml b/basics/anchorpy-main/tests/client-gen/example-program/Cargo.toml new file mode 100644 index 0000000..a60de98 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example-program/Cargo.toml @@ -0,0 +1,4 @@ +[workspace] +members = [ + "programs/*" +] diff --git a/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/Cargo.toml b/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/Cargo.toml new file mode 100644 index 0000000..c08202b --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example-program" +version = "0.1.0" +description = "Created with Anchor" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "example_program" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = "0.26.0" diff --git a/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/Xargo.toml b/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/src/lib.rs b/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/src/lib.rs new file mode 100644 index 0000000..0875609 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example-program/programs/example-program/src/lib.rs @@ -0,0 +1,351 @@ +use std::str::FromStr; + +use anchor_lang::prelude::*; + +declare_id!("3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8"); + +pub const MY_SEED: [u8; 2] = *b"hi"; +pub const MY_SEED_STR: &str = "hi"; +pub const MY_SEED_U8: u8 = 1; +pub const MY_SEED_U32: u32 = 2; +pub const MY_SEED_U64: u64 = 3; + +#[program] +pub mod example_program { + use super::*; + + pub fn initialize(ctx: Context) -> Result<()> { + ctx.accounts.state.set_inner(State::default()); + Ok(()) + } + + pub fn initialize_with_values( + ctx: Context, + bool_field: bool, + u8_field: u8, + i8_field: i8, + u16_field: u16, + i16_field: i16, + u32_field: u32, + i32_field: i32, + f32_field: f32, + u64_field: u64, + i64_field: i64, + f64_field: f64, + u128_field: u128, + i128_field: i128, + bytes_field: Vec, + string_field: String, + pubkey_field: Pubkey, + vec_field: Vec, + vec_struct_field: Vec, + option_field: Option, + option_struct_field: Option, + struct_field: FooStruct, + array_field: [bool; 3], + enum_field_1: FooEnum, + enum_field_2: FooEnum, + enum_field_3: FooEnum, + enum_field_4: FooEnum, + ) -> Result<()> { + ctx.accounts.state.set_inner(State { + bool_field, + u8_field, + i8_field, + u16_field, + i16_field, + u32_field, + i32_field, + f32_field, + u64_field, + i64_field, + f64_field, + u128_field, + i128_field, + bytes_field, + string_field, + pubkey_field, + vec_field, + vec_struct_field, + option_field, + option_struct_field, + struct_field, + array_field, + enum_field_1, + enum_field_2, + enum_field_3, + enum_field_4, + }); + + Ok(()) + } + + // a separate instruction due to initialize_with_values having too many arguments + // https://github.com/solana-labs/solana/issues/23978 + pub fn initialize_with_values2( + ctx: Context, + vec_of_option: Vec>, + ) -> Result<()> { + ctx.accounts.state.set_inner(State2 { vec_of_option }); + Ok(()) + } + + pub fn cause_error(_ctx: Context) -> Result<()> { + return Err(error!(ErrorCode::SomeError)); + } + + pub fn init_my_account(ctx: Context, _seed_a: u8) -> Result<()> { + ctx.accounts.account.data = 1337; + Ok(()) + } + + pub fn increment_state_when_present(ctx: Context) -> Result<()> { + if let Some(state) = ctx.accounts.first_state.as_mut() { + state.u8_field += 1; + } + Ok(()) + } +} + +#[derive(Accounts)] +pub struct InitMyAccount<'info> { + base: Account<'info, BaseAccount>, + /// CHECK: shut up + base2: AccountInfo<'info>, + #[account( + seeds = [ + "another-seed".as_bytes(), + b"test".as_ref(), + MY_SEED.as_ref(), + MY_SEED_STR.as_bytes(), + MY_SEED_U8.to_le_bytes().as_ref(), + &MY_SEED_U32.to_le_bytes(), + &MY_SEED_U64.to_le_bytes(), + ], + bump, + )] + account: Account<'info, MyAccount>, + nested: Nested<'info>, + system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct Nested<'info> { + #[account( + seeds = [ + "nested-seed".as_bytes(), + b"test".as_ref(), + MY_SEED.as_ref(), + MY_SEED_STR.as_bytes(), + MY_SEED_U8.to_le_bytes().as_ref(), + &MY_SEED_U32.to_le_bytes(), + &MY_SEED_U64.to_le_bytes(), + ], + bump, + )] + /// CHECK: Not needed + account_nested: AccountInfo<'info>, +} + +#[account] +pub struct MyAccount { + data: u64, +} + +#[account] +pub struct BaseAccount { + base_data: u64, + base_data_key: Pubkey, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub enum FooEnum { + Unnamed(bool, u8, BarStruct), + UnnamedSingle(BarStruct), + Named { + bool_field: bool, + u8_field: u8, + nested: BarStruct, + }, + Struct(BarStruct), + OptionStruct(Option), + VecStruct(Vec), + NoFields, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct BarStruct { + some_field: bool, + other_field: u8, +} + +impl Default for BarStruct { + fn default() -> Self { + return BarStruct { + some_field: true, + other_field: 10, + }; + } +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct FooStruct { + field1: u8, + field2: u16, + nested: BarStruct, + vec_nested: Vec, + option_nested: Option, + enum_field: FooEnum, +} + +impl Default for FooStruct { + fn default() -> Self { + return FooStruct { + field1: 123, + field2: 999, + nested: BarStruct::default(), + vec_nested: vec![BarStruct::default()], + option_nested: Some(BarStruct::default()), + enum_field: FooEnum::Named { + bool_field: true, + u8_field: 15, + nested: BarStruct::default(), + }, + }; + } +} + +#[account] +pub struct State { + bool_field: bool, + u8_field: u8, + i8_field: i8, + u16_field: u16, + i16_field: i16, + u32_field: u32, + i32_field: i32, + f32_field: f32, + u64_field: u64, + i64_field: i64, + f64_field: f64, + u128_field: u128, + i128_field: i128, + bytes_field: Vec, + string_field: String, + pubkey_field: Pubkey, + vec_field: Vec, + vec_struct_field: Vec, + option_field: Option, + option_struct_field: Option, + struct_field: FooStruct, + array_field: [bool; 3], + enum_field_1: FooEnum, + enum_field_2: FooEnum, + enum_field_3: FooEnum, + enum_field_4: FooEnum, +} + +impl Default for State { + fn default() -> Self { + // some arbitrary default values + return State { + bool_field: true, + u8_field: 234, + i8_field: -123, + u16_field: 62345, + i16_field: -31234, + u32_field: 1234567891, + i32_field: -1234567891, + f32_field: 123456.5, + u64_field: u64::MAX / 2 + 10, + i64_field: i64::MIN / 2 - 10, + f64_field: 1234567891.345, + u128_field: u128::MAX / 2 + 10, + i128_field: i128::MIN / 2 - 10, + bytes_field: vec![1, 2, 255, 254], + string_field: String::from("hello"), + pubkey_field: Pubkey::from_str("EPZP2wrcRtMxrAPJCXVEQaYD9eH7fH7h12YqKDcd4aS7").unwrap(), + vec_field: vec![1, 2, 100, 1000, u64::MAX], + vec_struct_field: vec![FooStruct::default()], + option_field: None, + option_struct_field: Some(FooStruct::default()), + struct_field: FooStruct::default(), + array_field: [true, false, true], + enum_field_1: FooEnum::Unnamed(false, 10, BarStruct::default()), + enum_field_2: FooEnum::Named { + bool_field: true, + u8_field: 20, + nested: BarStruct::default(), + }, + enum_field_3: FooEnum::Struct(BarStruct::default()), + enum_field_4: FooEnum::NoFields, + }; + } +} + +#[account] +pub struct State2 { + vec_of_option: Vec>, +} +impl Default for State2 { + fn default() -> Self { + return State2 { + vec_of_option: vec![None, Some(10)], + }; + } +} + +#[derive(Accounts)] +pub struct NestedAccounts<'info> { + clock: Sysvar<'info, Clock>, + rent: Sysvar<'info, Rent>, +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account( + init, + space = 8 + 1000, // TODO: use exact space required + payer = payer, + )] + state: Account<'info, State>, + + nested: NestedAccounts<'info>, + + #[account(mut)] + payer: Signer<'info>, + system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct Initialize2<'info> { + #[account( + init, + space = 8 + 1000, // TODO: use exact space required + payer = payer, + )] + state: Account<'info, State2>, + + #[account(mut)] + payer: Signer<'info>, + system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct IncrementStateWhenPresent<'info> { + #[account(mut)] + first_state: Option>, + second_state: Account<'info, State2>, + system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct CauseError {} + +#[error_code] +pub enum ErrorCode { + #[msg("Example error.")] + SomeError, + #[msg("Another error.")] + OtherError, +} diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/__init__.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/__init__.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/__init__.py new file mode 100644 index 0000000..69f5a39 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/__init__.py @@ -0,0 +1,4 @@ +from .my_account import MyAccount, MyAccountJSON +from .base_account import BaseAccount, BaseAccountJSON +from .state import State, StateJSON +from .state2 import State2, State2JSON diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/base_account.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/base_account.py new file mode 100644 index 0000000..b3978ca --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/base_account.py @@ -0,0 +1,87 @@ +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from anchorpy.borsh_extension import BorshPubkey +from ..program_id import PROGRAM_ID + + +class BaseAccountJSON(typing.TypedDict): + base_data: int + base_data_key: str + + +@dataclass +class BaseAccount: + discriminator: typing.ClassVar = b"\x10Z\x82\xf2\x9f\n\xe8\x85" + layout: typing.ClassVar = borsh.CStruct( + "base_data" / borsh.U64, "base_data_key" / BorshPubkey + ) + base_data: int + base_data_key: Pubkey + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["BaseAccount"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["BaseAccount"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["BaseAccount"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "BaseAccount": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = BaseAccount.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + base_data=dec.base_data, + base_data_key=dec.base_data_key, + ) + + def to_json(self) -> BaseAccountJSON: + return { + "base_data": self.base_data, + "base_data_key": str(self.base_data_key), + } + + @classmethod + def from_json(cls, obj: BaseAccountJSON) -> "BaseAccount": + return cls( + base_data=obj["base_data"], + base_data_key=Pubkey.from_string(obj["base_data_key"]), + ) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/my_account.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/my_account.py new file mode 100644 index 0000000..49c922b --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/my_account.py @@ -0,0 +1,79 @@ +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from ..program_id import PROGRAM_ID + + +class MyAccountJSON(typing.TypedDict): + data: int + + +@dataclass +class MyAccount: + discriminator: typing.ClassVar = b"\xf6\x1c\x06W\xfb-2*" + layout: typing.ClassVar = borsh.CStruct("data" / borsh.U64) + data: int + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["MyAccount"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["MyAccount"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["MyAccount"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "MyAccount": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = MyAccount.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + data=dec.data, + ) + + def to_json(self) -> MyAccountJSON: + return { + "data": self.data, + } + + @classmethod + def from_json(cls, obj: MyAccountJSON) -> "MyAccount": + return cls( + data=obj["data"], + ) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/state.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/state.py new file mode 100644 index 0000000..1c0f39f --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/state.py @@ -0,0 +1,259 @@ +import typing +from dataclasses import dataclass +from construct import Construct +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from anchorpy.borsh_extension import BorshPubkey +from ..program_id import PROGRAM_ID +from .. import types + + +class StateJSON(typing.TypedDict): + bool_field: bool + u8_field: int + i8_field: int + u16_field: int + i16_field: int + u32_field: int + i32_field: int + f32_field: float + u64_field: int + i64_field: int + f64_field: float + u128_field: int + i128_field: int + bytes_field: list[int] + string_field: str + pubkey_field: str + vec_field: list[int] + vec_struct_field: list[types.foo_struct.FooStructJSON] + option_field: typing.Optional[bool] + option_struct_field: typing.Optional[types.foo_struct.FooStructJSON] + struct_field: types.foo_struct.FooStructJSON + array_field: list[bool] + enum_field1: types.foo_enum.FooEnumJSON + enum_field2: types.foo_enum.FooEnumJSON + enum_field3: types.foo_enum.FooEnumJSON + enum_field4: types.foo_enum.FooEnumJSON + + +@dataclass +class State: + discriminator: typing.ClassVar = b"\xd8\x92k^hK\xb6\xb1" + layout: typing.ClassVar = borsh.CStruct( + "bool_field" / borsh.Bool, + "u8_field" / borsh.U8, + "i8_field" / borsh.I8, + "u16_field" / borsh.U16, + "i16_field" / borsh.I16, + "u32_field" / borsh.U32, + "i32_field" / borsh.I32, + "f32_field" / borsh.F32, + "u64_field" / borsh.U64, + "i64_field" / borsh.I64, + "f64_field" / borsh.F64, + "u128_field" / borsh.U128, + "i128_field" / borsh.I128, + "bytes_field" / borsh.Bytes, + "string_field" / borsh.String, + "pubkey_field" / BorshPubkey, + "vec_field" / borsh.Vec(typing.cast(Construct, borsh.U64)), + "vec_struct_field" + / borsh.Vec(typing.cast(Construct, types.foo_struct.FooStruct.layout)), + "option_field" / borsh.Option(borsh.Bool), + "option_struct_field" / borsh.Option(types.foo_struct.FooStruct.layout), + "struct_field" / types.foo_struct.FooStruct.layout, + "array_field" / borsh.Bool[3], + "enum_field1" / types.foo_enum.layout, + "enum_field2" / types.foo_enum.layout, + "enum_field3" / types.foo_enum.layout, + "enum_field4" / types.foo_enum.layout, + ) + bool_field: bool + u8_field: int + i8_field: int + u16_field: int + i16_field: int + u32_field: int + i32_field: int + f32_field: float + u64_field: int + i64_field: int + f64_field: float + u128_field: int + i128_field: int + bytes_field: bytes + string_field: str + pubkey_field: Pubkey + vec_field: list[int] + vec_struct_field: list[types.foo_struct.FooStruct] + option_field: typing.Optional[bool] + option_struct_field: typing.Optional[types.foo_struct.FooStruct] + struct_field: types.foo_struct.FooStruct + array_field: list[bool] + enum_field1: types.foo_enum.FooEnumKind + enum_field2: types.foo_enum.FooEnumKind + enum_field3: types.foo_enum.FooEnumKind + enum_field4: types.foo_enum.FooEnumKind + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["State"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["State"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["State"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "State": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = State.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + bool_field=dec.bool_field, + u8_field=dec.u8_field, + i8_field=dec.i8_field, + u16_field=dec.u16_field, + i16_field=dec.i16_field, + u32_field=dec.u32_field, + i32_field=dec.i32_field, + f32_field=dec.f32_field, + u64_field=dec.u64_field, + i64_field=dec.i64_field, + f64_field=dec.f64_field, + u128_field=dec.u128_field, + i128_field=dec.i128_field, + bytes_field=dec.bytes_field, + string_field=dec.string_field, + pubkey_field=dec.pubkey_field, + vec_field=dec.vec_field, + vec_struct_field=list( + map( + lambda item: types.foo_struct.FooStruct.from_decoded(item), + dec.vec_struct_field, + ) + ), + option_field=dec.option_field, + option_struct_field=( + None + if dec.option_struct_field is None + else types.foo_struct.FooStruct.from_decoded(dec.option_struct_field) + ), + struct_field=types.foo_struct.FooStruct.from_decoded(dec.struct_field), + array_field=dec.array_field, + enum_field1=types.foo_enum.from_decoded(dec.enum_field1), + enum_field2=types.foo_enum.from_decoded(dec.enum_field2), + enum_field3=types.foo_enum.from_decoded(dec.enum_field3), + enum_field4=types.foo_enum.from_decoded(dec.enum_field4), + ) + + def to_json(self) -> StateJSON: + return { + "bool_field": self.bool_field, + "u8_field": self.u8_field, + "i8_field": self.i8_field, + "u16_field": self.u16_field, + "i16_field": self.i16_field, + "u32_field": self.u32_field, + "i32_field": self.i32_field, + "f32_field": self.f32_field, + "u64_field": self.u64_field, + "i64_field": self.i64_field, + "f64_field": self.f64_field, + "u128_field": self.u128_field, + "i128_field": self.i128_field, + "bytes_field": list(self.bytes_field), + "string_field": self.string_field, + "pubkey_field": str(self.pubkey_field), + "vec_field": self.vec_field, + "vec_struct_field": list( + map(lambda item: item.to_json(), self.vec_struct_field) + ), + "option_field": self.option_field, + "option_struct_field": ( + None + if self.option_struct_field is None + else self.option_struct_field.to_json() + ), + "struct_field": self.struct_field.to_json(), + "array_field": self.array_field, + "enum_field1": self.enum_field1.to_json(), + "enum_field2": self.enum_field2.to_json(), + "enum_field3": self.enum_field3.to_json(), + "enum_field4": self.enum_field4.to_json(), + } + + @classmethod + def from_json(cls, obj: StateJSON) -> "State": + return cls( + bool_field=obj["bool_field"], + u8_field=obj["u8_field"], + i8_field=obj["i8_field"], + u16_field=obj["u16_field"], + i16_field=obj["i16_field"], + u32_field=obj["u32_field"], + i32_field=obj["i32_field"], + f32_field=obj["f32_field"], + u64_field=obj["u64_field"], + i64_field=obj["i64_field"], + f64_field=obj["f64_field"], + u128_field=obj["u128_field"], + i128_field=obj["i128_field"], + bytes_field=bytes(obj["bytes_field"]), + string_field=obj["string_field"], + pubkey_field=Pubkey.from_string(obj["pubkey_field"]), + vec_field=obj["vec_field"], + vec_struct_field=list( + map( + lambda item: types.foo_struct.FooStruct.from_json(item), + obj["vec_struct_field"], + ) + ), + option_field=obj["option_field"], + option_struct_field=( + None + if obj["option_struct_field"] is None + else types.foo_struct.FooStruct.from_json(obj["option_struct_field"]) + ), + struct_field=types.foo_struct.FooStruct.from_json(obj["struct_field"]), + array_field=obj["array_field"], + enum_field1=types.foo_enum.from_json(obj["enum_field1"]), + enum_field2=types.foo_enum.from_json(obj["enum_field2"]), + enum_field3=types.foo_enum.from_json(obj["enum_field3"]), + enum_field4=types.foo_enum.from_json(obj["enum_field4"]), + ) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/state2.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/state2.py new file mode 100644 index 0000000..2dd9ab1 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/accounts/state2.py @@ -0,0 +1,82 @@ +import typing +from dataclasses import dataclass +from construct import Construct +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from ..program_id import PROGRAM_ID + + +class State2JSON(typing.TypedDict): + vec_of_option: list[typing.Optional[int]] + + +@dataclass +class State2: + discriminator: typing.ClassVar = b"ja\xff\xa1\xfa\xcd\xb9\xc0" + layout: typing.ClassVar = borsh.CStruct( + "vec_of_option" / borsh.Vec(typing.cast(Construct, borsh.Option(borsh.U64))) + ) + vec_of_option: list[typing.Optional[int]] + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["State2"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["State2"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["State2"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "State2": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = State2.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + vec_of_option=dec.vec_of_option, + ) + + def to_json(self) -> State2JSON: + return { + "vec_of_option": self.vec_of_option, + } + + @classmethod + def from_json(cls, obj: State2JSON) -> "State2": + return cls( + vec_of_option=obj["vec_of_option"], + ) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/__init__.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/__init__.py new file mode 100644 index 0000000..421993d --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/__init__.py @@ -0,0 +1,29 @@ +import typing +import re +from solders.transaction_status import ( + InstructionErrorCustom, + TransactionErrorInstructionError, +) +from solana.rpc.core import RPCException +from solders.rpc.errors import SendTransactionPreflightFailureMessage +from anchorpy.error import extract_code_and_logs +from ..program_id import PROGRAM_ID +from . import anchor +from . import custom + + +def from_code(code: int) -> typing.Union[custom.CustomError, anchor.AnchorError, None]: + return custom.from_code(code) if code >= 6000 else anchor.from_code(code) + + +error_re = re.compile(r"Program (\w+) failed: custom program error: (\w+)") + + +def from_tx_error( + error: RPCException, +) -> typing.Union[anchor.AnchorError, custom.CustomError, None]: + err_info = error.args[0] + extracted = extract_code_and_logs(err_info, PROGRAM_ID) + if extracted is None: + return None + return from_code(extracted[0]) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/anchor.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/anchor.py new file mode 100644 index 0000000..3f266ef --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/anchor.py @@ -0,0 +1,590 @@ +import typing +from anchorpy.error import ProgramError + + +class InstructionMissing(ProgramError): + def __init__(self): + super().__init__(100, "8 byte instruction identifier not provided") + + code = 100 + name = "InstructionMissing" + msg = "8 byte instruction identifier not provided" + + +class InstructionFallbackNotFound(ProgramError): + def __init__(self): + super().__init__(101, "Fallback functions are not supported") + + code = 101 + name = "InstructionFallbackNotFound" + msg = "Fallback functions are not supported" + + +class InstructionDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(102, "The program could not deserialize the given instruction") + + code = 102 + name = "InstructionDidNotDeserialize" + msg = "The program could not deserialize the given instruction" + + +class InstructionDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(103, "The program could not serialize the given instruction") + + code = 103 + name = "InstructionDidNotSerialize" + msg = "The program could not serialize the given instruction" + + +class IdlInstructionStub(ProgramError): + def __init__(self): + super().__init__(1000, "The program was compiled without idl instructions") + + code = 1000 + name = "IdlInstructionStub" + msg = "The program was compiled without idl instructions" + + +class IdlInstructionInvalidProgram(ProgramError): + def __init__(self): + super().__init__( + 1001, "The transaction was given an invalid program for the IDL instruction" + ) + + code = 1001 + name = "IdlInstructionInvalidProgram" + msg = "The transaction was given an invalid program for the IDL instruction" + + +class ConstraintMut(ProgramError): + def __init__(self): + super().__init__(2000, "A mut constraint was violated") + + code = 2000 + name = "ConstraintMut" + msg = "A mut constraint was violated" + + +class ConstraintHasOne(ProgramError): + def __init__(self): + super().__init__(2001, "A has_one constraint was violated") + + code = 2001 + name = "ConstraintHasOne" + msg = "A has_one constraint was violated" + + +class ConstraintSigner(ProgramError): + def __init__(self): + super().__init__(2002, "A signer constraint was violated") + + code = 2002 + name = "ConstraintSigner" + msg = "A signer constraint was violated" + + +class ConstraintRaw(ProgramError): + def __init__(self): + super().__init__(2003, "A raw constraint was violated") + + code = 2003 + name = "ConstraintRaw" + msg = "A raw constraint was violated" + + +class ConstraintOwner(ProgramError): + def __init__(self): + super().__init__(2004, "An owner constraint was violated") + + code = 2004 + name = "ConstraintOwner" + msg = "An owner constraint was violated" + + +class ConstraintRentExempt(ProgramError): + def __init__(self): + super().__init__(2005, "A rent exempt constraint was violated") + + code = 2005 + name = "ConstraintRentExempt" + msg = "A rent exempt constraint was violated" + + +class ConstraintSeeds(ProgramError): + def __init__(self): + super().__init__(2006, "A seeds constraint was violated") + + code = 2006 + name = "ConstraintSeeds" + msg = "A seeds constraint was violated" + + +class ConstraintExecutable(ProgramError): + def __init__(self): + super().__init__(2007, "An executable constraint was violated") + + code = 2007 + name = "ConstraintExecutable" + msg = "An executable constraint was violated" + + +class ConstraintState(ProgramError): + def __init__(self): + super().__init__(2008, "A state constraint was violated") + + code = 2008 + name = "ConstraintState" + msg = "A state constraint was violated" + + +class ConstraintAssociated(ProgramError): + def __init__(self): + super().__init__(2009, "An associated constraint was violated") + + code = 2009 + name = "ConstraintAssociated" + msg = "An associated constraint was violated" + + +class ConstraintAssociatedInit(ProgramError): + def __init__(self): + super().__init__(2010, "An associated init constraint was violated") + + code = 2010 + name = "ConstraintAssociatedInit" + msg = "An associated init constraint was violated" + + +class ConstraintClose(ProgramError): + def __init__(self): + super().__init__(2011, "A close constraint was violated") + + code = 2011 + name = "ConstraintClose" + msg = "A close constraint was violated" + + +class ConstraintAddress(ProgramError): + def __init__(self): + super().__init__(2012, "An address constraint was violated") + + code = 2012 + name = "ConstraintAddress" + msg = "An address constraint was violated" + + +class ConstraintZero(ProgramError): + def __init__(self): + super().__init__(2013, "Expected zero account discriminant") + + code = 2013 + name = "ConstraintZero" + msg = "Expected zero account discriminant" + + +class ConstraintTokenMint(ProgramError): + def __init__(self): + super().__init__(2014, "A token mint constraint was violated") + + code = 2014 + name = "ConstraintTokenMint" + msg = "A token mint constraint was violated" + + +class ConstraintTokenOwner(ProgramError): + def __init__(self): + super().__init__(2015, "A token owner constraint was violated") + + code = 2015 + name = "ConstraintTokenOwner" + msg = "A token owner constraint was violated" + + +class ConstraintMintMintAuthority(ProgramError): + def __init__(self): + super().__init__(2016, "A mint mint authority constraint was violated") + + code = 2016 + name = "ConstraintMintMintAuthority" + msg = "A mint mint authority constraint was violated" + + +class ConstraintMintFreezeAuthority(ProgramError): + def __init__(self): + super().__init__(2017, "A mint freeze authority constraint was violated") + + code = 2017 + name = "ConstraintMintFreezeAuthority" + msg = "A mint freeze authority constraint was violated" + + +class ConstraintMintDecimals(ProgramError): + def __init__(self): + super().__init__(2018, "A mint decimals constraint was violated") + + code = 2018 + name = "ConstraintMintDecimals" + msg = "A mint decimals constraint was violated" + + +class ConstraintSpace(ProgramError): + def __init__(self): + super().__init__(2019, "A space constraint was violated") + + code = 2019 + name = "ConstraintSpace" + msg = "A space constraint was violated" + + +class RequireViolated(ProgramError): + def __init__(self): + super().__init__(2500, "A require expression was violated") + + code = 2500 + name = "RequireViolated" + msg = "A require expression was violated" + + +class RequireEqViolated(ProgramError): + def __init__(self): + super().__init__(2501, "A require_eq expression was violated") + + code = 2501 + name = "RequireEqViolated" + msg = "A require_eq expression was violated" + + +class RequireKeysEqViolated(ProgramError): + def __init__(self): + super().__init__(2502, "A require_keys_eq expression was violated") + + code = 2502 + name = "RequireKeysEqViolated" + msg = "A require_keys_eq expression was violated" + + +class RequireNeqViolated(ProgramError): + def __init__(self): + super().__init__(2503, "A require_neq expression was violated") + + code = 2503 + name = "RequireNeqViolated" + msg = "A require_neq expression was violated" + + +class RequireKeysNeqViolated(ProgramError): + def __init__(self): + super().__init__(2504, "A require_keys_neq expression was violated") + + code = 2504 + name = "RequireKeysNeqViolated" + msg = "A require_keys_neq expression was violated" + + +class RequireGtViolated(ProgramError): + def __init__(self): + super().__init__(2505, "A require_gt expression was violated") + + code = 2505 + name = "RequireGtViolated" + msg = "A require_gt expression was violated" + + +class RequireGteViolated(ProgramError): + def __init__(self): + super().__init__(2506, "A require_gte expression was violated") + + code = 2506 + name = "RequireGteViolated" + msg = "A require_gte expression was violated" + + +class AccountDiscriminatorAlreadySet(ProgramError): + def __init__(self): + super().__init__( + 3000, "The account discriminator was already set on this account" + ) + + code = 3000 + name = "AccountDiscriminatorAlreadySet" + msg = "The account discriminator was already set on this account" + + +class AccountDiscriminatorNotFound(ProgramError): + def __init__(self): + super().__init__(3001, "No 8 byte discriminator was found on the account") + + code = 3001 + name = "AccountDiscriminatorNotFound" + msg = "No 8 byte discriminator was found on the account" + + +class AccountDiscriminatorMismatch(ProgramError): + def __init__(self): + super().__init__(3002, "8 byte discriminator did not match what was expected") + + code = 3002 + name = "AccountDiscriminatorMismatch" + msg = "8 byte discriminator did not match what was expected" + + +class AccountDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(3003, "Failed to deserialize the account") + + code = 3003 + name = "AccountDidNotDeserialize" + msg = "Failed to deserialize the account" + + +class AccountDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(3004, "Failed to serialize the account") + + code = 3004 + name = "AccountDidNotSerialize" + msg = "Failed to serialize the account" + + +class AccountNotEnoughKeys(ProgramError): + def __init__(self): + super().__init__(3005, "Not enough account keys given to the instruction") + + code = 3005 + name = "AccountNotEnoughKeys" + msg = "Not enough account keys given to the instruction" + + +class AccountNotMutable(ProgramError): + def __init__(self): + super().__init__(3006, "The given account is not mutable") + + code = 3006 + name = "AccountNotMutable" + msg = "The given account is not mutable" + + +class AccountOwnedByWrongProgram(ProgramError): + def __init__(self): + super().__init__( + 3007, "The given account is owned by a different program than expected" + ) + + code = 3007 + name = "AccountOwnedByWrongProgram" + msg = "The given account is owned by a different program than expected" + + +class InvalidProgramId(ProgramError): + def __init__(self): + super().__init__(3008, "Program ID was not as expected") + + code = 3008 + name = "InvalidProgramId" + msg = "Program ID was not as expected" + + +class InvalidProgramExecutable(ProgramError): + def __init__(self): + super().__init__(3009, "Program account is not executable") + + code = 3009 + name = "InvalidProgramExecutable" + msg = "Program account is not executable" + + +class AccountNotSigner(ProgramError): + def __init__(self): + super().__init__(3010, "The given account did not sign") + + code = 3010 + name = "AccountNotSigner" + msg = "The given account did not sign" + + +class AccountNotSystemOwned(ProgramError): + def __init__(self): + super().__init__(3011, "The given account is not owned by the system program") + + code = 3011 + name = "AccountNotSystemOwned" + msg = "The given account is not owned by the system program" + + +class AccountNotInitialized(ProgramError): + def __init__(self): + super().__init__( + 3012, "The program expected this account to be already initialized" + ) + + code = 3012 + name = "AccountNotInitialized" + msg = "The program expected this account to be already initialized" + + +class AccountNotProgramData(ProgramError): + def __init__(self): + super().__init__(3013, "The given account is not a program data account") + + code = 3013 + name = "AccountNotProgramData" + msg = "The given account is not a program data account" + + +class AccountNotAssociatedTokenAccount(ProgramError): + def __init__(self): + super().__init__(3014, "The given account is not the associated token account") + + code = 3014 + name = "AccountNotAssociatedTokenAccount" + msg = "The given account is not the associated token account" + + +class AccountSysvarMismatch(ProgramError): + def __init__(self): + super().__init__( + 3015, "The given public key does not match the required sysvar" + ) + + code = 3015 + name = "AccountSysvarMismatch" + msg = "The given public key does not match the required sysvar" + + +class StateInvalidAddress(ProgramError): + def __init__(self): + super().__init__( + 4000, "The given state account does not have the correct address" + ) + + code = 4000 + name = "StateInvalidAddress" + msg = "The given state account does not have the correct address" + + +class Deprecated(ProgramError): + def __init__(self): + super().__init__( + 5000, "The API being used is deprecated and should no longer be used" + ) + + code = 5000 + name = "Deprecated" + msg = "The API being used is deprecated and should no longer be used" + + +AnchorError = typing.Union[ + InstructionMissing, + InstructionFallbackNotFound, + InstructionDidNotDeserialize, + InstructionDidNotSerialize, + IdlInstructionStub, + IdlInstructionInvalidProgram, + ConstraintMut, + ConstraintHasOne, + ConstraintSigner, + ConstraintRaw, + ConstraintOwner, + ConstraintRentExempt, + ConstraintSeeds, + ConstraintExecutable, + ConstraintState, + ConstraintAssociated, + ConstraintAssociatedInit, + ConstraintClose, + ConstraintAddress, + ConstraintZero, + ConstraintTokenMint, + ConstraintTokenOwner, + ConstraintMintMintAuthority, + ConstraintMintFreezeAuthority, + ConstraintMintDecimals, + ConstraintSpace, + RequireViolated, + RequireEqViolated, + RequireKeysEqViolated, + RequireNeqViolated, + RequireKeysNeqViolated, + RequireGtViolated, + RequireGteViolated, + AccountDiscriminatorAlreadySet, + AccountDiscriminatorNotFound, + AccountDiscriminatorMismatch, + AccountDidNotDeserialize, + AccountDidNotSerialize, + AccountNotEnoughKeys, + AccountNotMutable, + AccountOwnedByWrongProgram, + InvalidProgramId, + InvalidProgramExecutable, + AccountNotSigner, + AccountNotSystemOwned, + AccountNotInitialized, + AccountNotProgramData, + AccountNotAssociatedTokenAccount, + AccountSysvarMismatch, + StateInvalidAddress, + Deprecated, +] +ANCHOR_ERROR_MAP: dict[int, AnchorError] = { + 100: InstructionMissing(), + 101: InstructionFallbackNotFound(), + 102: InstructionDidNotDeserialize(), + 103: InstructionDidNotSerialize(), + 1000: IdlInstructionStub(), + 1001: IdlInstructionInvalidProgram(), + 2000: ConstraintMut(), + 2001: ConstraintHasOne(), + 2002: ConstraintSigner(), + 2003: ConstraintRaw(), + 2004: ConstraintOwner(), + 2005: ConstraintRentExempt(), + 2006: ConstraintSeeds(), + 2007: ConstraintExecutable(), + 2008: ConstraintState(), + 2009: ConstraintAssociated(), + 2010: ConstraintAssociatedInit(), + 2011: ConstraintClose(), + 2012: ConstraintAddress(), + 2013: ConstraintZero(), + 2014: ConstraintTokenMint(), + 2015: ConstraintTokenOwner(), + 2016: ConstraintMintMintAuthority(), + 2017: ConstraintMintFreezeAuthority(), + 2018: ConstraintMintDecimals(), + 2019: ConstraintSpace(), + 2500: RequireViolated(), + 2501: RequireEqViolated(), + 2502: RequireKeysEqViolated(), + 2503: RequireNeqViolated(), + 2504: RequireKeysNeqViolated(), + 2505: RequireGtViolated(), + 2506: RequireGteViolated(), + 3000: AccountDiscriminatorAlreadySet(), + 3001: AccountDiscriminatorNotFound(), + 3002: AccountDiscriminatorMismatch(), + 3003: AccountDidNotDeserialize(), + 3004: AccountDidNotSerialize(), + 3005: AccountNotEnoughKeys(), + 3006: AccountNotMutable(), + 3007: AccountOwnedByWrongProgram(), + 3008: InvalidProgramId(), + 3009: InvalidProgramExecutable(), + 3010: AccountNotSigner(), + 3011: AccountNotSystemOwned(), + 3012: AccountNotInitialized(), + 3013: AccountNotProgramData(), + 3014: AccountNotAssociatedTokenAccount(), + 3015: AccountSysvarMismatch(), + 4000: StateInvalidAddress(), + 5000: Deprecated(), +} + + +def from_code(code: int) -> typing.Optional[AnchorError]: + maybe_err = ANCHOR_ERROR_MAP.get(code) + if maybe_err is None: + return None + return maybe_err diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/custom.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/custom.py new file mode 100644 index 0000000..f92f321 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/errors/custom.py @@ -0,0 +1,34 @@ +import typing +from anchorpy.error import ProgramError + + +class SomeError(ProgramError): + def __init__(self) -> None: + super().__init__(6000, "Example error.") + + code = 6000 + name = "SomeError" + msg = "Example error." + + +class OtherError(ProgramError): + def __init__(self) -> None: + super().__init__(6001, "Another error.") + + code = 6001 + name = "OtherError" + msg = "Another error." + + +CustomError = typing.Union[SomeError, OtherError] +CUSTOM_ERROR_MAP: dict[int, CustomError] = { + 6000: SomeError(), + 6001: OtherError(), +} + + +def from_code(code: int) -> typing.Optional[CustomError]: + maybe_err = CUSTOM_ERROR_MAP.get(code) + if maybe_err is None: + return None + return maybe_err diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/__init__.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/__init__.py new file mode 100644 index 0000000..dee442f --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/__init__.py @@ -0,0 +1,17 @@ +from .initialize import initialize, InitializeAccounts +from .initialize_with_values import ( + initialize_with_values, + InitializeWithValuesArgs, + InitializeWithValuesAccounts, +) +from .initialize_with_values2 import ( + initialize_with_values2, + InitializeWithValues2Args, + InitializeWithValues2Accounts, +) +from .cause_error import cause_error +from .init_my_account import init_my_account, InitMyAccountArgs, InitMyAccountAccounts +from .increment_state_when_present import ( + increment_state_when_present, + IncrementStateWhenPresentAccounts, +) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/cause_error.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/cause_error.py new file mode 100644 index 0000000..4bbd6f3 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/cause_error.py @@ -0,0 +1,18 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +def cause_error( + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"Ch%\x11\x02\x9bD\x11" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/increment_state_when_present.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/increment_state_when_present.py new file mode 100644 index 0000000..f7a41af --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/increment_state_when_present.py @@ -0,0 +1,33 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class IncrementStateWhenPresentAccounts(typing.TypedDict): + first_state: typing.Optional[Pubkey] + second_state: Pubkey + + +def increment_state_when_present( + accounts: IncrementStateWhenPresentAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["first_state"], is_signer=False, is_writable=True) + if accounts["first_state"] + else AccountMeta(pubkey=program_id, is_signer=False, is_writable=False), + AccountMeta( + pubkey=accounts["second_state"], is_signer=False, is_writable=False + ), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xf1!\xdd(\xa3Jy%" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/init_my_account.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/init_my_account.py new file mode 100644 index 0000000..063a597 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/init_my_account.py @@ -0,0 +1,72 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitMyAccountArgs(typing.TypedDict): + seed_a: int + + +layout = borsh.CStruct("seed_a" / borsh.U8) +NESTED_NESTED_ACCOUNT_NESTED = Pubkey.find_program_address( + seeds=[ + b"nested-seed", + b"test", + b"hi", + b"hi", + b"\x01", + b"\x02\x00\x00\x00", + b"\x03\x00\x00\x00\x00\x00\x00\x00", + ], + program_id=PROGRAM_ID, +)[0] +INIT_MY_ACCOUNT_ACCOUNTS_ACCOUNT = Pubkey.find_program_address( + seeds=[ + b"another-seed", + b"test", + b"hi", + b"hi", + b"\x01", + b"\x02\x00\x00\x00", + b"\x03\x00\x00\x00\x00\x00\x00\x00", + ], + program_id=PROGRAM_ID, +)[0] + + +class InitMyAccountAccounts(typing.TypedDict): + base: Pubkey + base2: Pubkey + + +def init_my_account( + args: InitMyAccountArgs, + accounts: InitMyAccountAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["base"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["base2"], is_signer=False, is_writable=False), + AccountMeta( + pubkey=INIT_MY_ACCOUNT_ACCOUNTS_ACCOUNT, is_signer=False, is_writable=False + ), + AccountMeta( + pubkey=NESTED_NESTED_ACCOUNT_NESTED, is_signer=False, is_writable=False + ), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b" ;\x05\xcd^E\xe3z" + encoded_args = layout.build( + { + "seed_a": args["seed_a"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize.py new file mode 100644 index 0000000..45b0cb7 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize.py @@ -0,0 +1,32 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.sysvar import RENT, CLOCK +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class InitializeAccounts(typing.TypedDict): + state: Pubkey + payer: Pubkey + + +def initialize( + accounts: InitializeAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["state"], is_signer=True, is_writable=True), + AccountMeta(pubkey=CLOCK, is_signer=False, is_writable=False), + AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xaf\xafm\x1f\r\x98\x9b\xed" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize_with_values.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize_with_values.py new file mode 100644 index 0000000..ccec19f --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize_with_values.py @@ -0,0 +1,132 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.sysvar import RENT, CLOCK +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey +from construct import Construct +import borsh_construct as borsh +from .. import types +from ..program_id import PROGRAM_ID + + +class InitializeWithValuesArgs(typing.TypedDict): + bool_field: bool + u8_field: int + i8_field: int + u16_field: int + i16_field: int + u32_field: int + i32_field: int + f32_field: float + u64_field: int + i64_field: int + f64_field: float + u128_field: int + i128_field: int + bytes_field: bytes + string_field: str + pubkey_field: Pubkey + vec_field: list[int] + vec_struct_field: list[types.foo_struct.FooStruct] + option_field: typing.Optional[bool] + option_struct_field: typing.Optional[types.foo_struct.FooStruct] + struct_field: types.foo_struct.FooStruct + array_field: list[bool] + enum_field1: types.foo_enum.FooEnumKind + enum_field2: types.foo_enum.FooEnumKind + enum_field3: types.foo_enum.FooEnumKind + enum_field4: types.foo_enum.FooEnumKind + + +layout = borsh.CStruct( + "bool_field" / borsh.Bool, + "u8_field" / borsh.U8, + "i8_field" / borsh.I8, + "u16_field" / borsh.U16, + "i16_field" / borsh.I16, + "u32_field" / borsh.U32, + "i32_field" / borsh.I32, + "f32_field" / borsh.F32, + "u64_field" / borsh.U64, + "i64_field" / borsh.I64, + "f64_field" / borsh.F64, + "u128_field" / borsh.U128, + "i128_field" / borsh.I128, + "bytes_field" / borsh.Bytes, + "string_field" / borsh.String, + "pubkey_field" / BorshPubkey, + "vec_field" / borsh.Vec(typing.cast(Construct, borsh.U64)), + "vec_struct_field" + / borsh.Vec(typing.cast(Construct, types.foo_struct.FooStruct.layout)), + "option_field" / borsh.Option(borsh.Bool), + "option_struct_field" / borsh.Option(types.foo_struct.FooStruct.layout), + "struct_field" / types.foo_struct.FooStruct.layout, + "array_field" / borsh.Bool[3], + "enum_field1" / types.foo_enum.layout, + "enum_field2" / types.foo_enum.layout, + "enum_field3" / types.foo_enum.layout, + "enum_field4" / types.foo_enum.layout, +) + + +class InitializeWithValuesAccounts(typing.TypedDict): + state: Pubkey + payer: Pubkey + + +def initialize_with_values( + args: InitializeWithValuesArgs, + accounts: InitializeWithValuesAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["state"], is_signer=True, is_writable=True), + AccountMeta(pubkey=CLOCK, is_signer=False, is_writable=False), + AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xdcI\x08\xd5\xb2E\xb5\x8d" + encoded_args = layout.build( + { + "bool_field": args["bool_field"], + "u8_field": args["u8_field"], + "i8_field": args["i8_field"], + "u16_field": args["u16_field"], + "i16_field": args["i16_field"], + "u32_field": args["u32_field"], + "i32_field": args["i32_field"], + "f32_field": args["f32_field"], + "u64_field": args["u64_field"], + "i64_field": args["i64_field"], + "f64_field": args["f64_field"], + "u128_field": args["u128_field"], + "i128_field": args["i128_field"], + "bytes_field": args["bytes_field"], + "string_field": args["string_field"], + "pubkey_field": args["pubkey_field"], + "vec_field": args["vec_field"], + "vec_struct_field": list( + map(lambda item: item.to_encodable(), args["vec_struct_field"]) + ), + "option_field": args["option_field"], + "option_struct_field": ( + None + if args["option_struct_field"] is None + else args["option_struct_field"].to_encodable() + ), + "struct_field": args["struct_field"].to_encodable(), + "array_field": args["array_field"], + "enum_field1": args["enum_field1"].to_encodable(), + "enum_field2": args["enum_field2"].to_encodable(), + "enum_field3": args["enum_field3"].to_encodable(), + "enum_field4": args["enum_field4"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize_with_values2.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize_with_values2.py new file mode 100644 index 0000000..6e56be8 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/instructions/initialize_with_values2.py @@ -0,0 +1,45 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.instruction import Instruction, AccountMeta +from construct import Construct +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitializeWithValues2Args(typing.TypedDict): + vec_of_option: list[typing.Optional[int]] + + +layout = borsh.CStruct( + "vec_of_option" / borsh.Vec(typing.cast(Construct, borsh.Option(borsh.U64))) +) + + +class InitializeWithValues2Accounts(typing.TypedDict): + state: Pubkey + payer: Pubkey + + +def initialize_with_values2( + args: InitializeWithValues2Args, + accounts: InitializeWithValues2Accounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["state"], is_signer=True, is_writable=True), + AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xf8\xbe\x15a\xef\x94'\xb5" + encoded_args = layout.build( + { + "vec_of_option": args["vec_of_option"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/program_id.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/program_id.py new file mode 100644 index 0000000..649b93e --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/program_id.py @@ -0,0 +1,3 @@ +from solders.pubkey import Pubkey + +PROGRAM_ID = Pubkey.from_string("3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8") diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/types/__init__.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/__init__.py new file mode 100644 index 0000000..a843328 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/__init__.py @@ -0,0 +1,7 @@ +import typing +from . import bar_struct +from .bar_struct import BarStruct, BarStructJSON +from . import foo_struct +from .foo_struct import FooStruct, FooStructJSON +from . import foo_enum +from .foo_enum import FooEnumKind, FooEnumJSON diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/types/bar_struct.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/bar_struct.py new file mode 100644 index 0000000..9ab95a7 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/bar_struct.py @@ -0,0 +1,33 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from construct import Container +import borsh_construct as borsh + + +class BarStructJSON(typing.TypedDict): + some_field: bool + other_field: int + + +@dataclass +class BarStruct: + layout: typing.ClassVar = borsh.CStruct( + "some_field" / borsh.Bool, "other_field" / borsh.U8 + ) + some_field: bool + other_field: int + + @classmethod + def from_decoded(cls, obj: Container) -> "BarStruct": + return cls(some_field=obj.some_field, other_field=obj.other_field) + + def to_encodable(self) -> dict[str, typing.Any]: + return {"some_field": self.some_field, "other_field": self.other_field} + + def to_json(self) -> BarStructJSON: + return {"some_field": self.some_field, "other_field": self.other_field} + + @classmethod + def from_json(cls, obj: BarStructJSON) -> "BarStruct": + return cls(some_field=obj["some_field"], other_field=obj["other_field"]) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/types/foo_enum.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/foo_enum.py new file mode 100644 index 0000000..b56185f --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/foo_enum.py @@ -0,0 +1,370 @@ +from __future__ import annotations +from . import bar_struct +import typing +from dataclasses import dataclass +from construct import Construct +from anchorpy.borsh_extension import EnumForCodegen +import borsh_construct as borsh + +UnnamedJSONValue = tuple[bool, int, bar_struct.BarStructJSON] +UnnamedSingleJSONValue = tuple[bar_struct.BarStructJSON] + + +class NamedJSONValue(typing.TypedDict): + bool_field: bool + u8_field: int + nested: bar_struct.BarStructJSON + + +StructJSONValue = tuple[bar_struct.BarStructJSON] +OptionStructJSONValue = tuple[typing.Optional[bar_struct.BarStructJSON]] +VecStructJSONValue = tuple[list[bar_struct.BarStructJSON]] +UnnamedValue = tuple[bool, int, bar_struct.BarStruct] +UnnamedSingleValue = tuple[bar_struct.BarStruct] + + +class NamedValue(typing.TypedDict): + bool_field: bool + u8_field: int + nested: bar_struct.BarStruct + + +StructValue = tuple[bar_struct.BarStruct] +OptionStructValue = tuple[typing.Optional[bar_struct.BarStruct]] +VecStructValue = tuple[list[bar_struct.BarStruct]] + + +class UnnamedJSON(typing.TypedDict): + value: UnnamedJSONValue + kind: typing.Literal["Unnamed"] + + +class UnnamedSingleJSON(typing.TypedDict): + value: UnnamedSingleJSONValue + kind: typing.Literal["UnnamedSingle"] + + +class NamedJSON(typing.TypedDict): + value: NamedJSONValue + kind: typing.Literal["Named"] + + +class StructJSON(typing.TypedDict): + value: StructJSONValue + kind: typing.Literal["Struct"] + + +class OptionStructJSON(typing.TypedDict): + value: OptionStructJSONValue + kind: typing.Literal["OptionStruct"] + + +class VecStructJSON(typing.TypedDict): + value: VecStructJSONValue + kind: typing.Literal["VecStruct"] + + +class NoFieldsJSON(typing.TypedDict): + kind: typing.Literal["NoFields"] + + +@dataclass +class Unnamed: + discriminator: typing.ClassVar = 0 + kind: typing.ClassVar = "Unnamed" + value: UnnamedValue + + def to_json(self) -> UnnamedJSON: + return UnnamedJSON( + kind="Unnamed", + value=( + self.value[0], + self.value[1], + self.value[2].to_json(), + ), + ) + + def to_encodable(self) -> dict: + return { + "Unnamed": { + "item_0": self.value[0], + "item_1": self.value[1], + "item_2": self.value[2].to_encodable(), + }, + } + + +@dataclass +class UnnamedSingle: + discriminator: typing.ClassVar = 1 + kind: typing.ClassVar = "UnnamedSingle" + value: UnnamedSingleValue + + def to_json(self) -> UnnamedSingleJSON: + return UnnamedSingleJSON( + kind="UnnamedSingle", + value=(self.value[0].to_json(),), + ) + + def to_encodable(self) -> dict: + return { + "UnnamedSingle": { + "item_0": self.value[0].to_encodable(), + }, + } + + +@dataclass +class Named: + discriminator: typing.ClassVar = 2 + kind: typing.ClassVar = "Named" + value: NamedValue + + def to_json(self) -> NamedJSON: + return NamedJSON( + kind="Named", + value={ + "bool_field": self.value["bool_field"], + "u8_field": self.value["u8_field"], + "nested": self.value["nested"].to_json(), + }, + ) + + def to_encodable(self) -> dict: + return { + "Named": { + "bool_field": self.value["bool_field"], + "u8_field": self.value["u8_field"], + "nested": self.value["nested"].to_encodable(), + }, + } + + +@dataclass +class Struct: + discriminator: typing.ClassVar = 3 + kind: typing.ClassVar = "Struct" + value: StructValue + + def to_json(self) -> StructJSON: + return StructJSON( + kind="Struct", + value=(self.value[0].to_json(),), + ) + + def to_encodable(self) -> dict: + return { + "Struct": { + "item_0": self.value[0].to_encodable(), + }, + } + + +@dataclass +class OptionStruct: + discriminator: typing.ClassVar = 4 + kind: typing.ClassVar = "OptionStruct" + value: OptionStructValue + + def to_json(self) -> OptionStructJSON: + return OptionStructJSON( + kind="OptionStruct", + value=((None if self.value[0] is None else self.value[0].to_json()),), + ) + + def to_encodable(self) -> dict: + return { + "OptionStruct": { + "item_0": ( + None if self.value[0] is None else self.value[0].to_encodable() + ), + }, + } + + +@dataclass +class VecStruct: + discriminator: typing.ClassVar = 5 + kind: typing.ClassVar = "VecStruct" + value: VecStructValue + + def to_json(self) -> VecStructJSON: + return VecStructJSON( + kind="VecStruct", + value=(list(map(lambda item: item.to_json(), self.value[0])),), + ) + + def to_encodable(self) -> dict: + return { + "VecStruct": { + "item_0": list(map(lambda item: item.to_encodable(), self.value[0])), + }, + } + + +@dataclass +class NoFields: + discriminator: typing.ClassVar = 6 + kind: typing.ClassVar = "NoFields" + + @classmethod + def to_json(cls) -> NoFieldsJSON: + return NoFieldsJSON( + kind="NoFields", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "NoFields": {}, + } + + +FooEnumKind = typing.Union[ + Unnamed, UnnamedSingle, Named, Struct, OptionStruct, VecStruct, NoFields +] +FooEnumJSON = typing.Union[ + UnnamedJSON, + UnnamedSingleJSON, + NamedJSON, + StructJSON, + OptionStructJSON, + VecStructJSON, + NoFieldsJSON, +] + + +def from_decoded(obj: dict) -> FooEnumKind: + if not isinstance(obj, dict): + raise ValueError("Invalid enum object") + if "Unnamed" in obj: + val = obj["Unnamed"] + return Unnamed( + ( + val["item_0"], + val["item_1"], + bar_struct.BarStruct.from_decoded(val["item_2"]), + ) + ) + if "UnnamedSingle" in obj: + val = obj["UnnamedSingle"] + return UnnamedSingle((bar_struct.BarStruct.from_decoded(val["item_0"]),)) + if "Named" in obj: + val = obj["Named"] + return Named( + NamedValue( + bool_field=val["bool_field"], + u8_field=val["u8_field"], + nested=bar_struct.BarStruct.from_decoded(val["nested"]), + ) + ) + if "Struct" in obj: + val = obj["Struct"] + return Struct((bar_struct.BarStruct.from_decoded(val["item_0"]),)) + if "OptionStruct" in obj: + val = obj["OptionStruct"] + return OptionStruct( + ( + ( + None + if val["item_0"] is None + else bar_struct.BarStruct.from_decoded(val["item_0"]) + ), + ) + ) + if "VecStruct" in obj: + val = obj["VecStruct"] + return VecStruct( + ( + list( + map( + lambda item: bar_struct.BarStruct.from_decoded(item), + val["item_0"], + ) + ), + ) + ) + if "NoFields" in obj: + return NoFields() + raise ValueError("Invalid enum object") + + +def from_json(obj: FooEnumJSON) -> FooEnumKind: + if obj["kind"] == "Unnamed": + unnamed_json_value = typing.cast(UnnamedJSONValue, obj["value"]) + return Unnamed( + ( + unnamed_json_value[0], + unnamed_json_value[1], + bar_struct.BarStruct.from_json(unnamed_json_value[2]), + ) + ) + if obj["kind"] == "UnnamedSingle": + unnamed_single_json_value = typing.cast(UnnamedSingleJSONValue, obj["value"]) + return UnnamedSingle( + (bar_struct.BarStruct.from_json(unnamed_single_json_value[0]),) + ) + if obj["kind"] == "Named": + named_json_value = typing.cast(NamedJSONValue, obj["value"]) + return Named( + NamedValue( + bool_field=named_json_value["bool_field"], + u8_field=named_json_value["u8_field"], + nested=bar_struct.BarStruct.from_json(named_json_value["nested"]), + ) + ) + if obj["kind"] == "Struct": + struct_json_value = typing.cast(StructJSONValue, obj["value"]) + return Struct((bar_struct.BarStruct.from_json(struct_json_value[0]),)) + if obj["kind"] == "OptionStruct": + option_struct_json_value = typing.cast(OptionStructJSONValue, obj["value"]) + return OptionStruct( + ( + ( + None + if option_struct_json_value[0] is None + else bar_struct.BarStruct.from_json(option_struct_json_value[0]) + ), + ) + ) + if obj["kind"] == "VecStruct": + vec_struct_json_value = typing.cast(VecStructJSONValue, obj["value"]) + return VecStruct( + ( + list( + map( + lambda item: bar_struct.BarStruct.from_json(item), + vec_struct_json_value[0], + ) + ), + ) + ) + if obj["kind"] == "NoFields": + return NoFields() + kind = obj["kind"] + raise ValueError(f"Unrecognized enum kind: {kind}") + + +layout = EnumForCodegen( + "Unnamed" + / borsh.CStruct( + "item_0" / borsh.Bool, + "item_1" / borsh.U8, + "item_2" / bar_struct.BarStruct.layout, + ), + "UnnamedSingle" / borsh.CStruct("item_0" / bar_struct.BarStruct.layout), + "Named" + / borsh.CStruct( + "bool_field" / borsh.Bool, + "u8_field" / borsh.U8, + "nested" / bar_struct.BarStruct.layout, + ), + "Struct" / borsh.CStruct("item_0" / bar_struct.BarStruct.layout), + "OptionStruct" + / borsh.CStruct("item_0" / borsh.Option(bar_struct.BarStruct.layout)), + "VecStruct" + / borsh.CStruct( + "item_0" / borsh.Vec(typing.cast(Construct, bar_struct.BarStruct.layout)) + ), + "NoFields" / borsh.CStruct(), +) diff --git a/basics/anchorpy-main/tests/client-gen/example_program_gen/types/foo_struct.py b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/foo_struct.py new file mode 100644 index 0000000..7db49d8 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/example_program_gen/types/foo_struct.py @@ -0,0 +1,97 @@ +from __future__ import annotations +from . import bar_struct, foo_enum +import typing +from dataclasses import dataclass +from construct import Container, Construct +import borsh_construct as borsh + + +class FooStructJSON(typing.TypedDict): + field1: int + field2: int + nested: bar_struct.BarStructJSON + vec_nested: list[bar_struct.BarStructJSON] + option_nested: typing.Optional[bar_struct.BarStructJSON] + enum_field: foo_enum.FooEnumJSON + + +@dataclass +class FooStruct: + layout: typing.ClassVar = borsh.CStruct( + "field1" / borsh.U8, + "field2" / borsh.U16, + "nested" / bar_struct.BarStruct.layout, + "vec_nested" / borsh.Vec(typing.cast(Construct, bar_struct.BarStruct.layout)), + "option_nested" / borsh.Option(bar_struct.BarStruct.layout), + "enum_field" / foo_enum.layout, + ) + field1: int + field2: int + nested: bar_struct.BarStruct + vec_nested: list[bar_struct.BarStruct] + option_nested: typing.Optional[bar_struct.BarStruct] + enum_field: foo_enum.FooEnumKind + + @classmethod + def from_decoded(cls, obj: Container) -> "FooStruct": + return cls( + field1=obj.field1, + field2=obj.field2, + nested=bar_struct.BarStruct.from_decoded(obj.nested), + vec_nested=list( + map( + lambda item: bar_struct.BarStruct.from_decoded(item), obj.vec_nested + ) + ), + option_nested=( + None + if obj.option_nested is None + else bar_struct.BarStruct.from_decoded(obj.option_nested) + ), + enum_field=foo_enum.from_decoded(obj.enum_field), + ) + + def to_encodable(self) -> dict[str, typing.Any]: + return { + "field1": self.field1, + "field2": self.field2, + "nested": self.nested.to_encodable(), + "vec_nested": list(map(lambda item: item.to_encodable(), self.vec_nested)), + "option_nested": ( + None + if self.option_nested is None + else self.option_nested.to_encodable() + ), + "enum_field": self.enum_field.to_encodable(), + } + + def to_json(self) -> FooStructJSON: + return { + "field1": self.field1, + "field2": self.field2, + "nested": self.nested.to_json(), + "vec_nested": list(map(lambda item: item.to_json(), self.vec_nested)), + "option_nested": ( + None if self.option_nested is None else self.option_nested.to_json() + ), + "enum_field": self.enum_field.to_json(), + } + + @classmethod + def from_json(cls, obj: FooStructJSON) -> "FooStruct": + return cls( + field1=obj["field1"], + field2=obj["field2"], + nested=bar_struct.BarStruct.from_json(obj["nested"]), + vec_nested=list( + map( + lambda item: bar_struct.BarStruct.from_json(item), obj["vec_nested"] + ) + ), + option_nested=( + None + if obj["option_nested"] is None + else bar_struct.BarStruct.from_json(obj["option_nested"]) + ), + enum_field=foo_enum.from_json(obj["enum_field"]), + ) diff --git a/basics/anchorpy-main/tests/client-gen/test_client_gen.py b/basics/anchorpy-main/tests/client-gen/test_client_gen.py new file mode 100644 index 0000000..03f2c3e --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/test_client_gen.py @@ -0,0 +1,444 @@ +import asyncio +import json +from pathlib import Path +from typing import AsyncGenerator, List + +from anchorpy import Provider, Wallet +from anchorpy.pytest_plugin import localnet_fixture +from construct import ListContainer +from pytest import fixture, mark +from pytest_asyncio import fixture as async_fixture +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Confirmed, Processed +from solana.rpc.core import RPCException +from solders.hash import Hash +from solders.keypair import Keypair +from solders.message import Message +from solders.pubkey import Pubkey +from solders.transaction import VersionedTransaction + +from tests.client_gen.example_program_gen.accounts import State, State2 +from tests.client_gen.example_program_gen.errors import from_tx_error +from tests.client_gen.example_program_gen.errors.custom import SomeError +from tests.client_gen.example_program_gen.instructions import ( + InitializeWithValuesAccounts, + InitializeWithValuesArgs, + cause_error, + increment_state_when_present, + initialize, + initialize_with_values, + initialize_with_values2, +) +from tests.client_gen.example_program_gen.program_id import PROGRAM_ID +from tests.client_gen.example_program_gen.types import BarStruct, FooStruct +from tests.client_gen.example_program_gen.types.foo_enum import ( + Named, + NoFields, + Struct, + Unnamed, +) + +EXAMPLE_PROGRAM_DIR = Path("tests/client_gen/example-program") + + +@fixture(scope="session") +def event_loop(): + """Create an instance of the default event loop for each test case.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + +localnet = localnet_fixture(EXAMPLE_PROGRAM_DIR, scope="session") + + +@fixture(scope="session") +def payer(localnet) -> Keypair: + with (EXAMPLE_PROGRAM_DIR / ".anchor/test-ledger/faucet-keypair.json").open() as f: + faucet_keypair_json: List[int] = json.load(f) + return Keypair.from_bytes(faucet_keypair_json) + + +@async_fixture(scope="session") +async def provider(localnet, payer: Keypair) -> AsyncGenerator[Provider, None]: + wallet = Wallet(payer) + conn = AsyncClient(commitment=Processed) + prov = Provider(conn, wallet) + yield prov + await prov.close() + + +@async_fixture(scope="session") +async def blockhash(provider: Provider) -> Hash: + return (await provider.connection.get_latest_blockhash(Confirmed)).value.blockhash + + +@async_fixture(scope="module") +async def init_and_account_fetch(provider: Provider, blockhash: Hash) -> Keypair: + state = Keypair() + initialize_ix = initialize( + { + "state": state.pubkey(), + "payer": provider.wallet.public_key, + } + ) + msg = Message.new_with_blockhash( + [initialize_ix], provider.wallet.public_key, blockhash + ) + tx = VersionedTransaction(msg, [provider.wallet.payer, state]) + await provider.send(tx) + return state + + +@mark.asyncio +async def test_init_and_account_fetch( + init_and_account_fetch: Keypair, provider: Provider +) -> None: + state = init_and_account_fetch + vec_struct_field_enum_field_expected = Named( + value={ + "bool_field": True, + "u8_field": 15, + "nested": BarStruct(some_field=True, other_field=10), + } + ) + assert vec_struct_field_enum_field_expected.discriminator == 2 + assert vec_struct_field_enum_field_expected.kind == "Named" + vec_struct_field_expected = [ + FooStruct( + field1=123, + field2=999, + nested=BarStruct(some_field=True, other_field=10), + vec_nested=[BarStruct(some_field=True, other_field=10)], + option_nested=BarStruct(some_field=True, other_field=10), + enum_field=vec_struct_field_enum_field_expected, + ) + ] + option_struct_field_expected = FooStruct( + field1=123, + field2=999, + nested=BarStruct(some_field=True, other_field=10), + vec_nested=[BarStruct(some_field=True, other_field=10)], + option_nested=BarStruct(some_field=True, other_field=10), + enum_field=Named( + value={ + "bool_field": True, + "u8_field": 15, + "nested": BarStruct(some_field=True, other_field=10), + } + ), + ) + struct_field_expected = FooStruct( + field1=123, + field2=999, + nested=BarStruct(some_field=True, other_field=10), + vec_nested=[BarStruct(some_field=True, other_field=10)], + option_nested=BarStruct(some_field=True, other_field=10), + enum_field=Named( + value={ + "bool_field": True, + "u8_field": 15, + "nested": BarStruct(some_field=True, other_field=10), + } + ), + ) + array_field_expected = ListContainer([True, False, True]) + vec_field_expected = ListContainer([1, 2, 100, 1000, 18446744073709551615]) + enum_field1_expected = Unnamed( + value=(False, 10, BarStruct(some_field=True, other_field=10)) + ) + assert enum_field1_expected.kind == "Unnamed" + assert enum_field1_expected.discriminator == 0 + enum_field2_expected = Named( + value={ + "bool_field": True, + "u8_field": 20, + "nested": BarStruct(some_field=True, other_field=10), + } + ) + assert enum_field2_expected.kind == "Named" + assert enum_field2_expected.discriminator == 2 + enum_field3_expected = Struct(value=(BarStruct(some_field=True, other_field=10),)) + assert enum_field3_expected.discriminator == 3 + assert enum_field3_expected.kind == "Struct" + enum_field4_expected = NoFields() + assert enum_field4_expected.discriminator == 6 + assert enum_field4_expected.kind == "NoFields" + expected = State( + bool_field=True, + u8_field=234, + i8_field=-123, + u16_field=62345, + i16_field=-31234, + u32_field=1234567891, + i32_field=-1234567891, + f32_field=123456.5, + u64_field=9223372036854775817, + i64_field=-4611686018427387914, + f64_field=1234567891.345, + u128_field=170141183460469231731687303715884105737, + i128_field=-85070591730234615865843651857942052874, + bytes_field=b"\x01\x02\xff\xfe", + string_field="hello", + pubkey_field=Pubkey.from_string("EPZP2wrcRtMxrAPJCXVEQaYD9eH7fH7h12YqKDcd4aS7"), + vec_field=vec_field_expected, + vec_struct_field=vec_struct_field_expected, + option_field=None, + option_struct_field=option_struct_field_expected, + struct_field=struct_field_expected, + array_field=array_field_expected, + enum_field1=enum_field1_expected, + enum_field2=enum_field2_expected, + enum_field3=enum_field3_expected, + enum_field4=enum_field4_expected, + ) + res = await State.fetch(provider.connection, state.pubkey()) + assert res == expected + res = await State.fetch(provider.connection, state.pubkey(), program_id=PROGRAM_ID) + assert res == expected + + +@async_fixture(scope="session") +async def setup_fetch_multiple( + provider: Provider, blockhash: Hash +) -> tuple[Keypair, Keypair]: + state = Keypair() + another_state = Keypair() + initialize_ixs = [ + initialize( + { + "state": state.pubkey(), + "payer": provider.wallet.public_key, + } + ), + initialize( + { + "state": another_state.pubkey(), + "payer": provider.wallet.public_key, + } + ), + ] + msg = Message.new_with_blockhash( + initialize_ixs, provider.wallet.public_key, blockhash + ) + tx = VersionedTransaction(msg, [provider.wallet.payer, state, another_state]) + await provider.send(tx) + return state, another_state + + +@mark.asyncio +async def test_fetch_multiple( + provider: Provider, setup_fetch_multiple: tuple[Keypair, Keypair] +) -> None: + state, another_state = setup_fetch_multiple + non_state = Keypair() + res = await State.fetch_multiple( + provider.connection, + [state.pubkey(), non_state.pubkey(), another_state.pubkey()], + ) + assert isinstance(res[0], State) + assert res[1] is None + assert isinstance(res[2], State) + + +@async_fixture(scope="session") +async def send_instructions_with_args( + provider: Provider, blockhash +) -> tuple[Keypair, Keypair]: + state = Keypair() + state2 = Keypair() + vec_struct_field = [ + FooStruct( + field1=1, + field2=2, + nested=BarStruct(some_field=True, other_field=55), + vec_nested=[BarStruct(some_field=False, other_field=11)], + option_nested=None, + enum_field=Unnamed((True, 22, BarStruct(some_field=True, other_field=33))), + ) + ] + struct_field = FooStruct( + field1=1, + field2=2, + nested=BarStruct(some_field=True, other_field=55), + vec_nested=[BarStruct(some_field=False, other_field=11)], + option_nested=None, + enum_field=NoFields(), + ) + enum_field1 = Unnamed((True, 15, BarStruct(some_field=False, other_field=200))) + enum_field2 = Named( + { + "bool_field": True, + "u8_field": 128, + "nested": BarStruct(some_field=False, other_field=1), + } + ) + enum_field3 = Struct((BarStruct(some_field=True, other_field=15),)) + initialize_with_values_args = InitializeWithValuesArgs( + bool_field=True, + u8_field=253, + i8_field=-120, + u16_field=61234, + i16_field=-31253, + u32_field=1234567899, + i32_field=-123456789, + f32_field=123458.5, + u64_field=9223372036854775810, + i64_field=-4611686018427387912, + f64_field=1234567892.445, + u128_field=170141183460469231731687303715884105740, + i128_field=-85070591730234615865843651857942052877, + bytes_field=bytes([5, 10, 255]), + string_field="string value", + pubkey_field=Pubkey.from_string("GDddEKTjLBqhskzSMYph5o54VYLQfPCR3PoFqKHLJK6s"), + vec_field=[1, 123456789123456789], + vec_struct_field=vec_struct_field, + option_field=True, + option_struct_field=None, + struct_field=struct_field, + array_field=[True, True, False], + enum_field1=enum_field1, + enum_field2=enum_field2, + enum_field3=enum_field3, + enum_field4=NoFields(), + ) + initialize_with_values_accounts = InitializeWithValuesAccounts( + state=state.pubkey(), + payer=provider.wallet.public_key, + ) + ix1 = initialize_with_values( + initialize_with_values_args, initialize_with_values_accounts + ) + ix2 = initialize_with_values2( + {"vec_of_option": [None, None, 20]}, + { + "state": state2.pubkey(), + "payer": provider.wallet.public_key, + }, + ) + msg = Message.new_with_blockhash([ix1, ix2], provider.wallet.public_key, blockhash) + tx = VersionedTransaction(msg, [provider.wallet.payer, state, state2]) + await provider.send(tx) + return state, state2 + + +@mark.asyncio +async def test_instructions_with_args( + send_instructions_with_args: tuple[Keypair, Keypair], provider: Provider +) -> None: + state, state2 = send_instructions_with_args + expected = State( + bool_field=True, + u8_field=253, + i8_field=-120, + u16_field=61234, + i16_field=-31253, + u32_field=1234567899, + i32_field=-123456789, + f32_field=123458.5, + u64_field=9223372036854775810, + i64_field=-4611686018427387912, + f64_field=1234567892.445, + u128_field=170141183460469231731687303715884105740, + i128_field=-85070591730234615865843651857942052877, + bytes_field=b"\x05\n\xff", + string_field="string value", + pubkey_field=Pubkey.from_string("GDddEKTjLBqhskzSMYph5o54VYLQfPCR3PoFqKHLJK6s"), + vec_field=ListContainer([1, 123456789123456789]), + vec_struct_field=[ + FooStruct( + field1=1, + field2=2, + nested=BarStruct(some_field=True, other_field=55), + vec_nested=[BarStruct(some_field=False, other_field=11)], + option_nested=None, + enum_field=Unnamed( + value=(True, 22, BarStruct(some_field=True, other_field=33)) + ), + ) + ], + option_field=True, + option_struct_field=None, + struct_field=FooStruct( + field1=1, + field2=2, + nested=BarStruct(some_field=True, other_field=55), + vec_nested=[BarStruct(some_field=False, other_field=11)], + option_nested=None, + enum_field=NoFields(), + ), + array_field=ListContainer([True, True, False]), + enum_field1=Unnamed( + value=(True, 15, BarStruct(some_field=False, other_field=200)) + ), + enum_field2=Named( + value={ + "bool_field": True, + "u8_field": 128, + "nested": BarStruct(some_field=False, other_field=1), + } + ), + enum_field3=Struct(value=(BarStruct(some_field=True, other_field=15),)), + enum_field4=NoFields(), + ) + expected2 = State2(vec_of_option=ListContainer([None, None, 20])) + res = await State.fetch(provider.connection, state.pubkey()) + res2 = await State2.fetch(provider.connection, state2.pubkey()) + assert res == expected + assert res2 == expected2 + + +@mark.asyncio +async def test_instruction_with_optional_account( + send_instructions_with_args: tuple[Keypair, Keypair], + provider: Provider, + blockhash: Hash, +) -> None: + def prepare_tx(ixs): + msg = Message.new_with_blockhash([ix], provider.wallet.public_key, blockhash) + tx = VersionedTransaction(msg, [provider.wallet.payer]) + return tx + + state, state2 = send_instructions_with_args + ix = increment_state_when_present( + { + "first_state": None, + "second_state": state2.pubkey(), + }, + ) + before_res = await State.fetch(provider.connection, state.pubkey()) + assert before_res is not None + tx = prepare_tx(ix) + await provider.send(tx) + + res = await State.fetch(provider.connection, state.pubkey()) + assert res is not None + assert before_res.u8_field == res.u8_field + + ix = increment_state_when_present( + { + "first_state": state.pubkey(), + "second_state": state2.pubkey(), + }, + ) + + res = await State.fetch(provider.connection, state.pubkey()) + tx = prepare_tx(ix) + await provider.send(tx) + + res = await State.fetch(provider.connection, state.pubkey()) + assert res is not None + assert before_res.u8_field + 1 == res.u8_field + + +@mark.asyncio +async def test_cause_error(provider: Provider, blockhash: Hash) -> None: + msg = Message.new_with_blockhash( + [cause_error()], provider.wallet.public_key, blockhash + ) + tx = VersionedTransaction(msg, [provider.wallet.payer]) + try: + await provider.send(tx) + except RPCException as exc: + caught = from_tx_error(exc) + assert isinstance(caught, SomeError) diff --git a/basics/anchorpy-main/tests/client-gen/test_functional.py b/basics/anchorpy-main/tests/client-gen/test_functional.py new file mode 100644 index 0000000..aa3d2db --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/test_functional.py @@ -0,0 +1,357 @@ +import json +from filecmp import dircmp +from pathlib import Path + +from anchorpy.cli import client_gen +from py.path import local +from solana.rpc.core import RPCException +from solders.pubkey import Pubkey +from solders.rpc.errors import SendTransactionPreflightFailureMessage +from solders.rpc.responses import SimulateTransactionResp + +from tests.client_gen.example_program_gen.accounts import State +from tests.client_gen.example_program_gen.errors import from_tx_error +from tests.client_gen.example_program_gen.errors.anchor import InvalidProgramId +from tests.client_gen.example_program_gen.types import BarStruct, FooStruct +from tests.client_gen.example_program_gen.types.foo_enum import ( + Named, + NamedValue, + NoFields, + Struct, + Unnamed, +) + + +def test_quarry_mine(tmpdir: local) -> None: + proj_dir = Path(tmpdir) + out_dir = proj_dir / "generated" + idl_path = Path("tests/idls/quarry_mine.json") + client_gen(idl_path, out_dir, "placeholder") + + +def test_merkle_distributor(tmpdir: local) -> None: + proj_dir = Path(tmpdir) + out_dir = proj_dir / "generated" + idl_path = Path("tests/idls/merkle_distributor.json") + client_gen(idl_path, out_dir, "placeholder") + + +def test_null_err_when_cpi_fails() -> None: + to_dump = { + "jsonrpc": "2.0", + "error": { + "code": -32002, + "message": "", + "data": { + "err": {"InstructionError": [0, {"Custom": 3}]}, + "logs": [ + "Program 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 invoke [1]", + "Program log: Instruction: CauseError", + "Program 11111111111111111111111111111111 invoke [2]", + "Allocate: requested 1000000000000000000, max allowed 10485760", + "Program 11111111111111111111111111111111 failed: custom program error: 0x3", + "Program 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 consumed 7958 of 1400000 compute units", + "Program 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 failed: custom program error: 0x3", + ], + }, + }, + } + raw = json.dumps(to_dump) + parsed = SimulateTransactionResp.from_json(raw) + assert isinstance(parsed, SendTransactionPreflightFailureMessage) + err_mock = RPCException(parsed) + assert from_tx_error(err_mock) is None + + +def test_parses_anchor_error() -> None: + to_dump = { + "jsonrpc": "2.0", + "error": { + "code": -32002, + "message": "", + "data": { + "err": {"InstructionError": [0, {"Custom": 3008}]}, + "logs": [ + "Program 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 invoke [1]", + "Program log: Instruction: CauseError", + "Program log: AnchorError caused by account: system_program. Error Code: InvalidProgramId. Error Number: 3008. Error Message: Program ID was not as expected.", + "Program log: Left:", + "Program log: 24S58Cp5Myf6iGx4umBNd7RgDrZ9nkKzvkfFHBMDomNa", + "Program log: Right:", + "Program log: 11111111111111111111111111111111", + "Program 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 consumed 5043 of 1400000 compute units", + "Program 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 failed: custom program error: 0xbc0", + ], + }, + }, + } + raw = json.dumps(to_dump) + parsed = SimulateTransactionResp.from_json(raw) + assert isinstance(parsed, SendTransactionPreflightFailureMessage) + err_mock = RPCException(parsed) + assert isinstance(from_tx_error(err_mock), InvalidProgramId) + + +def test_json() -> None: + vec_struct_field = [ + FooStruct( + field1=5, + field2=6, + nested=BarStruct( + some_field=True, + other_field=15, + ), + vec_nested=[ + BarStruct( + some_field=True, + other_field=13, + ), + ], + option_nested=None, + enum_field=Unnamed( + ( + False, + 111, + BarStruct( + some_field=False, + other_field=11, + ), + ) + ), + ), + ] + option_struct_field = FooStruct( + field1=8, + field2=9, + nested=BarStruct( + some_field=True, + other_field=17, + ), + vec_nested=[ + BarStruct( + some_field=True, + other_field=10, + ), + ], + option_nested=BarStruct( + some_field=False, + other_field=99, + ), + enum_field=NoFields(), + ) + struct_field = FooStruct( + field1=11, + field2=12, + nested=BarStruct( + some_field=False, + other_field=177, + ), + vec_nested=[ + BarStruct( + some_field=True, + other_field=15, + ), + ], + option_nested=BarStruct( + some_field=True, + other_field=75, + ), + enum_field=NoFields(), + ) + enum_field1 = Unnamed( + ( + False, + 157, + BarStruct( + some_field=True, + other_field=193, + ), + ) + ) + enum_field2 = Named( + NamedValue( + bool_field=False, + u8_field=77, + nested=BarStruct( + some_field=True, + other_field=100, + ), + ) + ) + enum_field3 = Struct( + ( + BarStruct( + some_field=False, + other_field=122, + ), + ) + ) + state = State( + bool_field=True, + u8_field=255, + i8_field=-120, + u16_field=62000, + i16_field=-31000, + u32_field=123456789, + i32_field=-123456789, + f32_field=123456.5, + u64_field=9223372036854775805, + i64_field=4611686018427387910, + f64_field=1234567891.35, + u128_field=170141183460469231731687303715884105760, + i128_field=-85070591730234615865843651857942052897, + bytes_field=bytes([1, 255]), + string_field="a string", + pubkey_field=Pubkey.from_string("EPZP2wrcRtMxrAPJCXVEQaYD9eH7fH7h12YqKDcd4aS7"), + vec_field=[10, 1234567890123456], + vec_struct_field=vec_struct_field, + option_field=None, + option_struct_field=option_struct_field, + struct_field=struct_field, + array_field=[True, False], + enum_field1=enum_field1, + enum_field2=enum_field2, + enum_field3=enum_field3, + enum_field4=NoFields(), + ) + state_json = state.to_json() + expected = { + "bool_field": True, + "u8_field": 255, + "i8_field": -120, + "u16_field": 62000, + "i16_field": -31000, + "u32_field": 123456789, + "i32_field": -123456789, + "f32_field": 123456.5, + "u64_field": 9223372036854775805, + "i64_field": 4611686018427387910, + "f64_field": 1234567891.35, + "u128_field": 170141183460469231731687303715884105760, + "i128_field": -85070591730234615865843651857942052897, + "bytes_field": [1, 255], + "string_field": "a string", + "pubkey_field": "EPZP2wrcRtMxrAPJCXVEQaYD9eH7fH7h12YqKDcd4aS7", + "vec_field": [10, 1234567890123456], + "vec_struct_field": [ + { + "field1": 5, + "field2": 6, + "nested": { + "some_field": True, + "other_field": 15, + }, + "vec_nested": [ + { + "some_field": True, + "other_field": 13, + }, + ], + "option_nested": None, + "enum_field": { + "kind": "Unnamed", + "value": ( + False, + 111, + { + "some_field": False, + "other_field": 11, + }, + ), + }, + }, + ], + "option_field": None, + "option_struct_field": { + "field1": 8, + "field2": 9, + "nested": { + "some_field": True, + "other_field": 17, + }, + "vec_nested": [ + { + "some_field": True, + "other_field": 10, + }, + ], + "option_nested": { + "some_field": False, + "other_field": 99, + }, + "enum_field": { + "kind": "NoFields", + }, + }, + "struct_field": { + "field1": 11, + "field2": 12, + "nested": { + "some_field": False, + "other_field": 177, + }, + "vec_nested": [ + { + "some_field": True, + "other_field": 15, + }, + ], + "option_nested": { + "some_field": True, + "other_field": 75, + }, + "enum_field": { + "kind": "NoFields", + }, + }, + "array_field": [True, False], + "enum_field1": { + "kind": "Unnamed", + "value": ( + False, + 157, + { + "some_field": True, + "other_field": 193, + }, + ), + }, + "enum_field2": { + "kind": "Named", + "value": { + "bool_field": False, + "u8_field": 77, + "nested": { + "some_field": True, + "other_field": 100, + }, + }, + }, + "enum_field3": { + "kind": "Struct", + "value": ( + { + "some_field": False, + "other_field": 122, + }, + ), + }, + "enum_field4": { + "kind": "NoFields", + }, + } + assert state_json == expected + state_from_json = State.from_json(state_json) + assert state_from_json == state + + +def has_differences(dcmp: dircmp) -> bool: + differences = dcmp.left_only + dcmp.right_only + dcmp.diff_files + if differences: + return True + return any([has_differences(subdcmp) for subdcmp in dcmp.subdirs.values()]) + + +def test_generated_as_expected(project_dir: Path) -> None: + dcmp = dircmp(project_dir, "tests/client_gen/example_program_gen") + assert not has_differences(dcmp) diff --git a/basics/anchorpy-main/tests/client-gen/token/__init__.py b/basics/anchorpy-main/tests/client-gen/token/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basics/anchorpy-main/tests/client-gen/token/accounts/__init__.py b/basics/anchorpy-main/tests/client-gen/token/accounts/__init__.py new file mode 100644 index 0000000..95f3234 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/accounts/__init__.py @@ -0,0 +1,3 @@ +from .mint import Mint, MintJSON +from .account import Account, AccountJSON +from .multisig import Multisig, MultisigJSON diff --git a/basics/anchorpy-main/tests/client-gen/token/accounts/account.py b/basics/anchorpy-main/tests/client-gen/token/accounts/account.py new file mode 100644 index 0000000..d85015e --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/accounts/account.py @@ -0,0 +1,133 @@ +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from anchorpy.borsh_extension import BorshPubkey, COption +from ..program_id import PROGRAM_ID +from .. import types + + +class AccountJSON(typing.TypedDict): + mint: str + owner: str + amount: int + delegate: typing.Optional[str] + state: types.account_state.AccountStateJSON + is_native: typing.Optional[int] + delegated_amount: int + close_authority: typing.Optional[str] + + +@dataclass +class Account: + discriminator: typing.ClassVar = b"qB\xe06\xbcw\xf0e" + layout: typing.ClassVar = borsh.CStruct( + "mint" / BorshPubkey, + "owner" / BorshPubkey, + "amount" / borsh.U64, + "delegate" / COption(BorshPubkey), + "state" / types.account_state.layout, + "is_native" / COption(borsh.U64), + "delegated_amount" / borsh.U64, + "close_authority" / COption(BorshPubkey), + ) + mint: Pubkey + owner: Pubkey + amount: int + delegate: typing.Optional[Pubkey] + state: types.account_state.AccountStateKind + is_native: typing.Optional[int] + delegated_amount: int + close_authority: typing.Optional[Pubkey] + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["Account"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["Account"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["Account"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "Account": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = Account.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + mint=dec.mint, + owner=dec.owner, + amount=dec.amount, + delegate=dec.delegate, + state=types.account_state.from_decoded(dec.state), + is_native=dec.is_native, + delegated_amount=dec.delegated_amount, + close_authority=dec.close_authority, + ) + + def to_json(self) -> AccountJSON: + return { + "mint": str(self.mint), + "owner": str(self.owner), + "amount": self.amount, + "delegate": (None if self.delegate is None else str(self.delegate)), + "state": self.state.to_json(), + "is_native": self.is_native, + "delegated_amount": self.delegated_amount, + "close_authority": ( + None if self.close_authority is None else str(self.close_authority) + ), + } + + @classmethod + def from_json(cls, obj: AccountJSON) -> "Account": + return cls( + mint=Pubkey.from_string(obj["mint"]), + owner=Pubkey.from_string(obj["owner"]), + amount=obj["amount"], + delegate=( + None if obj["delegate"] is None else Pubkey.from_string(obj["delegate"]) + ), + state=types.account_state.from_json(obj["state"]), + is_native=obj["is_native"], + delegated_amount=obj["delegated_amount"], + close_authority=( + None + if obj["close_authority"] is None + else Pubkey.from_string(obj["close_authority"]) + ), + ) diff --git a/basics/anchorpy-main/tests/client-gen/token/accounts/mint.py b/basics/anchorpy-main/tests/client-gen/token/accounts/mint.py new file mode 100644 index 0000000..8df31bb --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/accounts/mint.py @@ -0,0 +1,118 @@ +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from anchorpy.borsh_extension import BorshPubkey, COption +from ..program_id import PROGRAM_ID + + +class MintJSON(typing.TypedDict): + mint_authority: typing.Optional[str] + supply: int + decimals: int + is_initialized: bool + freeze_authority: typing.Optional[str] + + +@dataclass +class Mint: + discriminator: typing.ClassVar = b"P\xbc\xf5\x14_\x8a9\x9c" + layout: typing.ClassVar = borsh.CStruct( + "mint_authority" / COption(BorshPubkey), + "supply" / borsh.U64, + "decimals" / borsh.U8, + "is_initialized" / borsh.Bool, + "freeze_authority" / COption(BorshPubkey), + ) + mint_authority: typing.Optional[Pubkey] + supply: int + decimals: int + is_initialized: bool + freeze_authority: typing.Optional[Pubkey] + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["Mint"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["Mint"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["Mint"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "Mint": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = Mint.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + mint_authority=dec.mint_authority, + supply=dec.supply, + decimals=dec.decimals, + is_initialized=dec.is_initialized, + freeze_authority=dec.freeze_authority, + ) + + def to_json(self) -> MintJSON: + return { + "mint_authority": ( + None if self.mint_authority is None else str(self.mint_authority) + ), + "supply": self.supply, + "decimals": self.decimals, + "is_initialized": self.is_initialized, + "freeze_authority": ( + None if self.freeze_authority is None else str(self.freeze_authority) + ), + } + + @classmethod + def from_json(cls, obj: MintJSON) -> "Mint": + return cls( + mint_authority=( + None + if obj["mint_authority"] is None + else Pubkey.from_string(obj["mint_authority"]) + ), + supply=obj["supply"], + decimals=obj["decimals"], + is_initialized=obj["is_initialized"], + freeze_authority=( + None + if obj["freeze_authority"] is None + else Pubkey.from_string(obj["freeze_authority"]) + ), + ) diff --git a/basics/anchorpy-main/tests/client-gen/token/accounts/multisig.py b/basics/anchorpy-main/tests/client-gen/token/accounts/multisig.py new file mode 100644 index 0000000..3b63a5c --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/accounts/multisig.py @@ -0,0 +1,100 @@ +import typing +from dataclasses import dataclass +from solders.pubkey import Pubkey +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Commitment +import borsh_construct as borsh +from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE +from anchorpy.error import AccountInvalidDiscriminator +from anchorpy.utils.rpc import get_multiple_accounts +from anchorpy.borsh_extension import BorshPubkey +from ..program_id import PROGRAM_ID + + +class MultisigJSON(typing.TypedDict): + m: int + n: int + is_initialized: bool + signers: list[str] + + +@dataclass +class Multisig: + discriminator: typing.ClassVar = b"\xe0ty\xbaD\xa1O\xec" + layout: typing.ClassVar = borsh.CStruct( + "m" / borsh.U8, + "n" / borsh.U8, + "is_initialized" / borsh.Bool, + "signers" / BorshPubkey[11], + ) + m: int + n: int + is_initialized: bool + signers: list[Pubkey] + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["Multisig"]: + resp = await conn.get_account_info(address, commitment=commitment) + info = resp.value + if info is None: + return None + if info.owner != program_id: + raise ValueError("Account does not belong to this program") + bytes_data = info.data + return cls.decode(bytes_data) + + @classmethod + async def fetch_multiple( + cls, + conn: AsyncClient, + addresses: list[Pubkey], + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.List[typing.Optional["Multisig"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["Multisig"]] = [] + for info in infos: + if info is None: + res.append(None) + continue + if info.account.owner != program_id: + raise ValueError("Account does not belong to this program") + res.append(cls.decode(info.account.data)) + return res + + @classmethod + def decode(cls, data: bytes) -> "Multisig": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = Multisig.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + m=dec.m, + n=dec.n, + is_initialized=dec.is_initialized, + signers=dec.signers, + ) + + def to_json(self) -> MultisigJSON: + return { + "m": self.m, + "n": self.n, + "is_initialized": self.is_initialized, + "signers": list(map(lambda item: str(item), self.signers)), + } + + @classmethod + def from_json(cls, obj: MultisigJSON) -> "Multisig": + return cls( + m=obj["m"], + n=obj["n"], + is_initialized=obj["is_initialized"], + signers=list(map(lambda item: Pubkey.from_string(item), obj["signers"])), + ) diff --git a/basics/anchorpy-main/tests/client-gen/token/errors/__init__.py b/basics/anchorpy-main/tests/client-gen/token/errors/__init__.py new file mode 100644 index 0000000..421993d --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/errors/__init__.py @@ -0,0 +1,29 @@ +import typing +import re +from solders.transaction_status import ( + InstructionErrorCustom, + TransactionErrorInstructionError, +) +from solana.rpc.core import RPCException +from solders.rpc.errors import SendTransactionPreflightFailureMessage +from anchorpy.error import extract_code_and_logs +from ..program_id import PROGRAM_ID +from . import anchor +from . import custom + + +def from_code(code: int) -> typing.Union[custom.CustomError, anchor.AnchorError, None]: + return custom.from_code(code) if code >= 6000 else anchor.from_code(code) + + +error_re = re.compile(r"Program (\w+) failed: custom program error: (\w+)") + + +def from_tx_error( + error: RPCException, +) -> typing.Union[anchor.AnchorError, custom.CustomError, None]: + err_info = error.args[0] + extracted = extract_code_and_logs(err_info, PROGRAM_ID) + if extracted is None: + return None + return from_code(extracted[0]) diff --git a/basics/anchorpy-main/tests/client-gen/token/errors/anchor.py b/basics/anchorpy-main/tests/client-gen/token/errors/anchor.py new file mode 100644 index 0000000..3f266ef --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/errors/anchor.py @@ -0,0 +1,590 @@ +import typing +from anchorpy.error import ProgramError + + +class InstructionMissing(ProgramError): + def __init__(self): + super().__init__(100, "8 byte instruction identifier not provided") + + code = 100 + name = "InstructionMissing" + msg = "8 byte instruction identifier not provided" + + +class InstructionFallbackNotFound(ProgramError): + def __init__(self): + super().__init__(101, "Fallback functions are not supported") + + code = 101 + name = "InstructionFallbackNotFound" + msg = "Fallback functions are not supported" + + +class InstructionDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(102, "The program could not deserialize the given instruction") + + code = 102 + name = "InstructionDidNotDeserialize" + msg = "The program could not deserialize the given instruction" + + +class InstructionDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(103, "The program could not serialize the given instruction") + + code = 103 + name = "InstructionDidNotSerialize" + msg = "The program could not serialize the given instruction" + + +class IdlInstructionStub(ProgramError): + def __init__(self): + super().__init__(1000, "The program was compiled without idl instructions") + + code = 1000 + name = "IdlInstructionStub" + msg = "The program was compiled without idl instructions" + + +class IdlInstructionInvalidProgram(ProgramError): + def __init__(self): + super().__init__( + 1001, "The transaction was given an invalid program for the IDL instruction" + ) + + code = 1001 + name = "IdlInstructionInvalidProgram" + msg = "The transaction was given an invalid program for the IDL instruction" + + +class ConstraintMut(ProgramError): + def __init__(self): + super().__init__(2000, "A mut constraint was violated") + + code = 2000 + name = "ConstraintMut" + msg = "A mut constraint was violated" + + +class ConstraintHasOne(ProgramError): + def __init__(self): + super().__init__(2001, "A has_one constraint was violated") + + code = 2001 + name = "ConstraintHasOne" + msg = "A has_one constraint was violated" + + +class ConstraintSigner(ProgramError): + def __init__(self): + super().__init__(2002, "A signer constraint was violated") + + code = 2002 + name = "ConstraintSigner" + msg = "A signer constraint was violated" + + +class ConstraintRaw(ProgramError): + def __init__(self): + super().__init__(2003, "A raw constraint was violated") + + code = 2003 + name = "ConstraintRaw" + msg = "A raw constraint was violated" + + +class ConstraintOwner(ProgramError): + def __init__(self): + super().__init__(2004, "An owner constraint was violated") + + code = 2004 + name = "ConstraintOwner" + msg = "An owner constraint was violated" + + +class ConstraintRentExempt(ProgramError): + def __init__(self): + super().__init__(2005, "A rent exempt constraint was violated") + + code = 2005 + name = "ConstraintRentExempt" + msg = "A rent exempt constraint was violated" + + +class ConstraintSeeds(ProgramError): + def __init__(self): + super().__init__(2006, "A seeds constraint was violated") + + code = 2006 + name = "ConstraintSeeds" + msg = "A seeds constraint was violated" + + +class ConstraintExecutable(ProgramError): + def __init__(self): + super().__init__(2007, "An executable constraint was violated") + + code = 2007 + name = "ConstraintExecutable" + msg = "An executable constraint was violated" + + +class ConstraintState(ProgramError): + def __init__(self): + super().__init__(2008, "A state constraint was violated") + + code = 2008 + name = "ConstraintState" + msg = "A state constraint was violated" + + +class ConstraintAssociated(ProgramError): + def __init__(self): + super().__init__(2009, "An associated constraint was violated") + + code = 2009 + name = "ConstraintAssociated" + msg = "An associated constraint was violated" + + +class ConstraintAssociatedInit(ProgramError): + def __init__(self): + super().__init__(2010, "An associated init constraint was violated") + + code = 2010 + name = "ConstraintAssociatedInit" + msg = "An associated init constraint was violated" + + +class ConstraintClose(ProgramError): + def __init__(self): + super().__init__(2011, "A close constraint was violated") + + code = 2011 + name = "ConstraintClose" + msg = "A close constraint was violated" + + +class ConstraintAddress(ProgramError): + def __init__(self): + super().__init__(2012, "An address constraint was violated") + + code = 2012 + name = "ConstraintAddress" + msg = "An address constraint was violated" + + +class ConstraintZero(ProgramError): + def __init__(self): + super().__init__(2013, "Expected zero account discriminant") + + code = 2013 + name = "ConstraintZero" + msg = "Expected zero account discriminant" + + +class ConstraintTokenMint(ProgramError): + def __init__(self): + super().__init__(2014, "A token mint constraint was violated") + + code = 2014 + name = "ConstraintTokenMint" + msg = "A token mint constraint was violated" + + +class ConstraintTokenOwner(ProgramError): + def __init__(self): + super().__init__(2015, "A token owner constraint was violated") + + code = 2015 + name = "ConstraintTokenOwner" + msg = "A token owner constraint was violated" + + +class ConstraintMintMintAuthority(ProgramError): + def __init__(self): + super().__init__(2016, "A mint mint authority constraint was violated") + + code = 2016 + name = "ConstraintMintMintAuthority" + msg = "A mint mint authority constraint was violated" + + +class ConstraintMintFreezeAuthority(ProgramError): + def __init__(self): + super().__init__(2017, "A mint freeze authority constraint was violated") + + code = 2017 + name = "ConstraintMintFreezeAuthority" + msg = "A mint freeze authority constraint was violated" + + +class ConstraintMintDecimals(ProgramError): + def __init__(self): + super().__init__(2018, "A mint decimals constraint was violated") + + code = 2018 + name = "ConstraintMintDecimals" + msg = "A mint decimals constraint was violated" + + +class ConstraintSpace(ProgramError): + def __init__(self): + super().__init__(2019, "A space constraint was violated") + + code = 2019 + name = "ConstraintSpace" + msg = "A space constraint was violated" + + +class RequireViolated(ProgramError): + def __init__(self): + super().__init__(2500, "A require expression was violated") + + code = 2500 + name = "RequireViolated" + msg = "A require expression was violated" + + +class RequireEqViolated(ProgramError): + def __init__(self): + super().__init__(2501, "A require_eq expression was violated") + + code = 2501 + name = "RequireEqViolated" + msg = "A require_eq expression was violated" + + +class RequireKeysEqViolated(ProgramError): + def __init__(self): + super().__init__(2502, "A require_keys_eq expression was violated") + + code = 2502 + name = "RequireKeysEqViolated" + msg = "A require_keys_eq expression was violated" + + +class RequireNeqViolated(ProgramError): + def __init__(self): + super().__init__(2503, "A require_neq expression was violated") + + code = 2503 + name = "RequireNeqViolated" + msg = "A require_neq expression was violated" + + +class RequireKeysNeqViolated(ProgramError): + def __init__(self): + super().__init__(2504, "A require_keys_neq expression was violated") + + code = 2504 + name = "RequireKeysNeqViolated" + msg = "A require_keys_neq expression was violated" + + +class RequireGtViolated(ProgramError): + def __init__(self): + super().__init__(2505, "A require_gt expression was violated") + + code = 2505 + name = "RequireGtViolated" + msg = "A require_gt expression was violated" + + +class RequireGteViolated(ProgramError): + def __init__(self): + super().__init__(2506, "A require_gte expression was violated") + + code = 2506 + name = "RequireGteViolated" + msg = "A require_gte expression was violated" + + +class AccountDiscriminatorAlreadySet(ProgramError): + def __init__(self): + super().__init__( + 3000, "The account discriminator was already set on this account" + ) + + code = 3000 + name = "AccountDiscriminatorAlreadySet" + msg = "The account discriminator was already set on this account" + + +class AccountDiscriminatorNotFound(ProgramError): + def __init__(self): + super().__init__(3001, "No 8 byte discriminator was found on the account") + + code = 3001 + name = "AccountDiscriminatorNotFound" + msg = "No 8 byte discriminator was found on the account" + + +class AccountDiscriminatorMismatch(ProgramError): + def __init__(self): + super().__init__(3002, "8 byte discriminator did not match what was expected") + + code = 3002 + name = "AccountDiscriminatorMismatch" + msg = "8 byte discriminator did not match what was expected" + + +class AccountDidNotDeserialize(ProgramError): + def __init__(self): + super().__init__(3003, "Failed to deserialize the account") + + code = 3003 + name = "AccountDidNotDeserialize" + msg = "Failed to deserialize the account" + + +class AccountDidNotSerialize(ProgramError): + def __init__(self): + super().__init__(3004, "Failed to serialize the account") + + code = 3004 + name = "AccountDidNotSerialize" + msg = "Failed to serialize the account" + + +class AccountNotEnoughKeys(ProgramError): + def __init__(self): + super().__init__(3005, "Not enough account keys given to the instruction") + + code = 3005 + name = "AccountNotEnoughKeys" + msg = "Not enough account keys given to the instruction" + + +class AccountNotMutable(ProgramError): + def __init__(self): + super().__init__(3006, "The given account is not mutable") + + code = 3006 + name = "AccountNotMutable" + msg = "The given account is not mutable" + + +class AccountOwnedByWrongProgram(ProgramError): + def __init__(self): + super().__init__( + 3007, "The given account is owned by a different program than expected" + ) + + code = 3007 + name = "AccountOwnedByWrongProgram" + msg = "The given account is owned by a different program than expected" + + +class InvalidProgramId(ProgramError): + def __init__(self): + super().__init__(3008, "Program ID was not as expected") + + code = 3008 + name = "InvalidProgramId" + msg = "Program ID was not as expected" + + +class InvalidProgramExecutable(ProgramError): + def __init__(self): + super().__init__(3009, "Program account is not executable") + + code = 3009 + name = "InvalidProgramExecutable" + msg = "Program account is not executable" + + +class AccountNotSigner(ProgramError): + def __init__(self): + super().__init__(3010, "The given account did not sign") + + code = 3010 + name = "AccountNotSigner" + msg = "The given account did not sign" + + +class AccountNotSystemOwned(ProgramError): + def __init__(self): + super().__init__(3011, "The given account is not owned by the system program") + + code = 3011 + name = "AccountNotSystemOwned" + msg = "The given account is not owned by the system program" + + +class AccountNotInitialized(ProgramError): + def __init__(self): + super().__init__( + 3012, "The program expected this account to be already initialized" + ) + + code = 3012 + name = "AccountNotInitialized" + msg = "The program expected this account to be already initialized" + + +class AccountNotProgramData(ProgramError): + def __init__(self): + super().__init__(3013, "The given account is not a program data account") + + code = 3013 + name = "AccountNotProgramData" + msg = "The given account is not a program data account" + + +class AccountNotAssociatedTokenAccount(ProgramError): + def __init__(self): + super().__init__(3014, "The given account is not the associated token account") + + code = 3014 + name = "AccountNotAssociatedTokenAccount" + msg = "The given account is not the associated token account" + + +class AccountSysvarMismatch(ProgramError): + def __init__(self): + super().__init__( + 3015, "The given public key does not match the required sysvar" + ) + + code = 3015 + name = "AccountSysvarMismatch" + msg = "The given public key does not match the required sysvar" + + +class StateInvalidAddress(ProgramError): + def __init__(self): + super().__init__( + 4000, "The given state account does not have the correct address" + ) + + code = 4000 + name = "StateInvalidAddress" + msg = "The given state account does not have the correct address" + + +class Deprecated(ProgramError): + def __init__(self): + super().__init__( + 5000, "The API being used is deprecated and should no longer be used" + ) + + code = 5000 + name = "Deprecated" + msg = "The API being used is deprecated and should no longer be used" + + +AnchorError = typing.Union[ + InstructionMissing, + InstructionFallbackNotFound, + InstructionDidNotDeserialize, + InstructionDidNotSerialize, + IdlInstructionStub, + IdlInstructionInvalidProgram, + ConstraintMut, + ConstraintHasOne, + ConstraintSigner, + ConstraintRaw, + ConstraintOwner, + ConstraintRentExempt, + ConstraintSeeds, + ConstraintExecutable, + ConstraintState, + ConstraintAssociated, + ConstraintAssociatedInit, + ConstraintClose, + ConstraintAddress, + ConstraintZero, + ConstraintTokenMint, + ConstraintTokenOwner, + ConstraintMintMintAuthority, + ConstraintMintFreezeAuthority, + ConstraintMintDecimals, + ConstraintSpace, + RequireViolated, + RequireEqViolated, + RequireKeysEqViolated, + RequireNeqViolated, + RequireKeysNeqViolated, + RequireGtViolated, + RequireGteViolated, + AccountDiscriminatorAlreadySet, + AccountDiscriminatorNotFound, + AccountDiscriminatorMismatch, + AccountDidNotDeserialize, + AccountDidNotSerialize, + AccountNotEnoughKeys, + AccountNotMutable, + AccountOwnedByWrongProgram, + InvalidProgramId, + InvalidProgramExecutable, + AccountNotSigner, + AccountNotSystemOwned, + AccountNotInitialized, + AccountNotProgramData, + AccountNotAssociatedTokenAccount, + AccountSysvarMismatch, + StateInvalidAddress, + Deprecated, +] +ANCHOR_ERROR_MAP: dict[int, AnchorError] = { + 100: InstructionMissing(), + 101: InstructionFallbackNotFound(), + 102: InstructionDidNotDeserialize(), + 103: InstructionDidNotSerialize(), + 1000: IdlInstructionStub(), + 1001: IdlInstructionInvalidProgram(), + 2000: ConstraintMut(), + 2001: ConstraintHasOne(), + 2002: ConstraintSigner(), + 2003: ConstraintRaw(), + 2004: ConstraintOwner(), + 2005: ConstraintRentExempt(), + 2006: ConstraintSeeds(), + 2007: ConstraintExecutable(), + 2008: ConstraintState(), + 2009: ConstraintAssociated(), + 2010: ConstraintAssociatedInit(), + 2011: ConstraintClose(), + 2012: ConstraintAddress(), + 2013: ConstraintZero(), + 2014: ConstraintTokenMint(), + 2015: ConstraintTokenOwner(), + 2016: ConstraintMintMintAuthority(), + 2017: ConstraintMintFreezeAuthority(), + 2018: ConstraintMintDecimals(), + 2019: ConstraintSpace(), + 2500: RequireViolated(), + 2501: RequireEqViolated(), + 2502: RequireKeysEqViolated(), + 2503: RequireNeqViolated(), + 2504: RequireKeysNeqViolated(), + 2505: RequireGtViolated(), + 2506: RequireGteViolated(), + 3000: AccountDiscriminatorAlreadySet(), + 3001: AccountDiscriminatorNotFound(), + 3002: AccountDiscriminatorMismatch(), + 3003: AccountDidNotDeserialize(), + 3004: AccountDidNotSerialize(), + 3005: AccountNotEnoughKeys(), + 3006: AccountNotMutable(), + 3007: AccountOwnedByWrongProgram(), + 3008: InvalidProgramId(), + 3009: InvalidProgramExecutable(), + 3010: AccountNotSigner(), + 3011: AccountNotSystemOwned(), + 3012: AccountNotInitialized(), + 3013: AccountNotProgramData(), + 3014: AccountNotAssociatedTokenAccount(), + 3015: AccountSysvarMismatch(), + 4000: StateInvalidAddress(), + 5000: Deprecated(), +} + + +def from_code(code: int) -> typing.Optional[AnchorError]: + maybe_err = ANCHOR_ERROR_MAP.get(code) + if maybe_err is None: + return None + return maybe_err diff --git a/basics/anchorpy-main/tests/client-gen/token/errors/custom.py b/basics/anchorpy-main/tests/client-gen/token/errors/custom.py new file mode 100644 index 0000000..15cabe4 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/errors/custom.py @@ -0,0 +1,239 @@ +import typing +from anchorpy.error import ProgramError + + +class NotRentExempt(ProgramError): + def __init__(self) -> None: + super().__init__(0, "Lamport balance below rent-exempt threshold") + + code = 0 + name = "NotRentExempt" + msg = "Lamport balance below rent-exempt threshold" + + +class InsufficientFunds(ProgramError): + def __init__(self) -> None: + super().__init__(1, "Insufficient funds") + + code = 1 + name = "InsufficientFunds" + msg = "Insufficient funds" + + +class InvalidMint(ProgramError): + def __init__(self) -> None: + super().__init__(2, "Invalid Mint") + + code = 2 + name = "InvalidMint" + msg = "Invalid Mint" + + +class MintMismatch(ProgramError): + def __init__(self) -> None: + super().__init__(3, "Account not associated with this Mint") + + code = 3 + name = "MintMismatch" + msg = "Account not associated with this Mint" + + +class OwnerMismatch(ProgramError): + def __init__(self) -> None: + super().__init__(4, "Owner does not match") + + code = 4 + name = "OwnerMismatch" + msg = "Owner does not match" + + +class FixedSupply(ProgramError): + def __init__(self) -> None: + super().__init__(5, "Fixed supply") + + code = 5 + name = "FixedSupply" + msg = "Fixed supply" + + +class AlreadyInUse(ProgramError): + def __init__(self) -> None: + super().__init__(6, "Already in use") + + code = 6 + name = "AlreadyInUse" + msg = "Already in use" + + +class InvalidNumberOfProvidedSigners(ProgramError): + def __init__(self) -> None: + super().__init__(7, "Invalid number of provided signers") + + code = 7 + name = "InvalidNumberOfProvidedSigners" + msg = "Invalid number of provided signers" + + +class InvalidNumberOfRequiredSigners(ProgramError): + def __init__(self) -> None: + super().__init__(8, "Invalid number of required signers") + + code = 8 + name = "InvalidNumberOfRequiredSigners" + msg = "Invalid number of required signers" + + +class UninitializedState(ProgramError): + def __init__(self) -> None: + super().__init__(9, "State is unititialized") + + code = 9 + name = "UninitializedState" + msg = "State is unititialized" + + +class NativeNotSupported(ProgramError): + def __init__(self) -> None: + super().__init__(10, "Instruction does not support native tokens") + + code = 10 + name = "NativeNotSupported" + msg = "Instruction does not support native tokens" + + +class NonNativeHasBalance(ProgramError): + def __init__(self) -> None: + super().__init__( + 11, "Non-native account can only be closed if its balance is zero" + ) + + code = 11 + name = "NonNativeHasBalance" + msg = "Non-native account can only be closed if its balance is zero" + + +class InvalidInstruction(ProgramError): + def __init__(self) -> None: + super().__init__(12, "Invalid instruction") + + code = 12 + name = "InvalidInstruction" + msg = "Invalid instruction" + + +class InvalidState(ProgramError): + def __init__(self) -> None: + super().__init__(13, "State is invalid for requested operation") + + code = 13 + name = "InvalidState" + msg = "State is invalid for requested operation" + + +class Overflow(ProgramError): + def __init__(self) -> None: + super().__init__(14, "Operation overflowed") + + code = 14 + name = "Overflow" + msg = "Operation overflowed" + + +class AuthorityTypeNotSupported(ProgramError): + def __init__(self) -> None: + super().__init__(15, "Account does not support specified authority type") + + code = 15 + name = "AuthorityTypeNotSupported" + msg = "Account does not support specified authority type" + + +class MintCannotFreeze(ProgramError): + def __init__(self) -> None: + super().__init__(16, "This token mint cannot freeze accounts") + + code = 16 + name = "MintCannotFreeze" + msg = "This token mint cannot freeze accounts" + + +class AccountFrozen(ProgramError): + def __init__(self) -> None: + super().__init__(17, "Account is frozen") + + code = 17 + name = "AccountFrozen" + msg = "Account is frozen" + + +class MintDecimalsMismatch(ProgramError): + def __init__(self) -> None: + super().__init__( + 18, "The provided decimals value different from the Mint decimals" + ) + + code = 18 + name = "MintDecimalsMismatch" + msg = "The provided decimals value different from the Mint decimals" + + +class NonNativeNotSupported(ProgramError): + def __init__(self) -> None: + super().__init__(19, "Instruction does not support non-native tokens") + + code = 19 + name = "NonNativeNotSupported" + msg = "Instruction does not support non-native tokens" + + +CustomError = typing.Union[ + NotRentExempt, + InsufficientFunds, + InvalidMint, + MintMismatch, + OwnerMismatch, + FixedSupply, + AlreadyInUse, + InvalidNumberOfProvidedSigners, + InvalidNumberOfRequiredSigners, + UninitializedState, + NativeNotSupported, + NonNativeHasBalance, + InvalidInstruction, + InvalidState, + Overflow, + AuthorityTypeNotSupported, + MintCannotFreeze, + AccountFrozen, + MintDecimalsMismatch, + NonNativeNotSupported, +] +CUSTOM_ERROR_MAP: dict[int, CustomError] = { + 0: NotRentExempt(), + 1: InsufficientFunds(), + 2: InvalidMint(), + 3: MintMismatch(), + 4: OwnerMismatch(), + 5: FixedSupply(), + 6: AlreadyInUse(), + 7: InvalidNumberOfProvidedSigners(), + 8: InvalidNumberOfRequiredSigners(), + 9: UninitializedState(), + 10: NativeNotSupported(), + 11: NonNativeHasBalance(), + 12: InvalidInstruction(), + 13: InvalidState(), + 14: Overflow(), + 15: AuthorityTypeNotSupported(), + 16: MintCannotFreeze(), + 17: AccountFrozen(), + 18: MintDecimalsMismatch(), + 19: NonNativeNotSupported(), +} + + +def from_code(code: int) -> typing.Optional[CustomError]: + maybe_err = CUSTOM_ERROR_MAP.get(code) + if maybe_err is None: + return None + return maybe_err diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/__init__.py b/basics/anchorpy-main/tests/client-gen/token/instructions/__init__.py new file mode 100644 index 0000000..7167c3b --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/__init__.py @@ -0,0 +1,60 @@ +from .initialize_mint import initialize_mint, InitializeMintArgs, InitializeMintAccounts +from .initialize_account import initialize_account, InitializeAccountAccounts +from .initialize_multisig import ( + initialize_multisig, + InitializeMultisigArgs, + InitializeMultisigAccounts, +) +from .transfer import transfer, TransferArgs, TransferAccounts +from .approve import approve, ApproveArgs, ApproveAccounts +from .revoke import revoke, RevokeAccounts +from .set_authority import set_authority, SetAuthorityArgs, SetAuthorityAccounts +from .mint_to import mint_to, MintToArgs, MintToAccounts +from .burn import burn, BurnArgs, BurnAccounts +from .close_account import close_account, CloseAccountAccounts +from .freeze_account import freeze_account, FreezeAccountAccounts +from .thaw_account import thaw_account, ThawAccountAccounts +from .transfer_checked import ( + transfer_checked, + TransferCheckedArgs, + TransferCheckedAccounts, +) +from .approve_checked import approve_checked, ApproveCheckedArgs, ApproveCheckedAccounts +from .mint_to_checked import mint_to_checked, MintToCheckedArgs, MintToCheckedAccounts +from .burn_checked import burn_checked, BurnCheckedArgs, BurnCheckedAccounts +from .initialize_account2 import ( + initialize_account2, + InitializeAccount2Args, + InitializeAccount2Accounts, +) +from .sync_native import sync_native, SyncNativeAccounts +from .initialize_account3 import ( + initialize_account3, + InitializeAccount3Args, + InitializeAccount3Accounts, +) +from .initialize_multisig2 import ( + initialize_multisig2, + InitializeMultisig2Args, + InitializeMultisig2Accounts, +) +from .initialize_mint2 import ( + initialize_mint2, + InitializeMint2Args, + InitializeMint2Accounts, +) +from .get_account_data_size import get_account_data_size, GetAccountDataSizeAccounts +from .initialize_immutable_owner import ( + initialize_immutable_owner, + InitializeImmutableOwnerAccounts, +) +from .amount_to_ui_amount import ( + amount_to_ui_amount, + AmountToUiAmountArgs, + AmountToUiAmountAccounts, +) +from .ui_amount_to_amount import ( + ui_amount_to_amount, + UiAmountToAmountArgs, + UiAmountToAmountAccounts, +) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/amount_to_ui_amount.py b/basics/anchorpy-main/tests/client-gen/token/instructions/amount_to_ui_amount.py new file mode 100644 index 0000000..a19f397 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/amount_to_ui_amount.py @@ -0,0 +1,38 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class AmountToUiAmountArgs(typing.TypedDict): + amount: int + + +layout = borsh.CStruct("amount" / borsh.U64) + + +class AmountToUiAmountAccounts(typing.TypedDict): + mint: Pubkey + + +def amount_to_ui_amount( + args: AmountToUiAmountArgs, + accounts: AmountToUiAmountAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False) + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xa0\x91\xc8b\xf2\x9c\x1eZ" + encoded_args = layout.build( + { + "amount": args["amount"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/approve.py b/basics/anchorpy-main/tests/client-gen/token/instructions/approve.py new file mode 100644 index 0000000..2916385 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/approve.py @@ -0,0 +1,42 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class ApproveArgs(typing.TypedDict): + amount: int + + +layout = borsh.CStruct("amount" / borsh.U64) + + +class ApproveAccounts(typing.TypedDict): + source: Pubkey + delegate: Pubkey + owner: Pubkey + + +def approve( + args: ApproveArgs, + accounts: ApproveAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["source"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["delegate"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"EJ\xd9$suaL" + encoded_args = layout.build( + { + "amount": args["amount"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/approve_checked.py b/basics/anchorpy-main/tests/client-gen/token/instructions/approve_checked.py new file mode 100644 index 0000000..b734d0a --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/approve_checked.py @@ -0,0 +1,46 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class ApproveCheckedArgs(typing.TypedDict): + amount: int + decimals: int + + +layout = borsh.CStruct("amount" / borsh.U64, "decimals" / borsh.U8) + + +class ApproveCheckedAccounts(typing.TypedDict): + source: Pubkey + mint: Pubkey + delegate: Pubkey + owner: Pubkey + + +def approve_checked( + args: ApproveCheckedArgs, + accounts: ApproveCheckedAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["source"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["delegate"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"/\xc5\xfe*:\xc9:m" + encoded_args = layout.build( + { + "amount": args["amount"], + "decimals": args["decimals"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/burn.py b/basics/anchorpy-main/tests/client-gen/token/instructions/burn.py new file mode 100644 index 0000000..be55863 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/burn.py @@ -0,0 +1,42 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class BurnArgs(typing.TypedDict): + amount: int + + +layout = borsh.CStruct("amount" / borsh.U64) + + +class BurnAccounts(typing.TypedDict): + account: Pubkey + mint: Pubkey + authority: Pubkey + + +def burn( + args: BurnArgs, + accounts: BurnAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["authority"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"tn\x1d8k\xdb*]" + encoded_args = layout.build( + { + "amount": args["amount"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/burn_checked.py b/basics/anchorpy-main/tests/client-gen/token/instructions/burn_checked.py new file mode 100644 index 0000000..913224a --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/burn_checked.py @@ -0,0 +1,44 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class BurnCheckedArgs(typing.TypedDict): + amount: int + decimals: int + + +layout = borsh.CStruct("amount" / borsh.U64, "decimals" / borsh.U8) + + +class BurnCheckedAccounts(typing.TypedDict): + account: Pubkey + mint: Pubkey + authority: Pubkey + + +def burn_checked( + args: BurnCheckedArgs, + accounts: BurnCheckedAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["authority"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xc6y\xc8fx\xd0\x9b\xb2" + encoded_args = layout.build( + { + "amount": args["amount"], + "decimals": args["decimals"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/close_account.py b/basics/anchorpy-main/tests/client-gen/token/instructions/close_account.py new file mode 100644 index 0000000..c6bf6de --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/close_account.py @@ -0,0 +1,29 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class CloseAccountAccounts(typing.TypedDict): + account: Pubkey + destination: Pubkey + owner: Pubkey + + +def close_account( + accounts: CloseAccountAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["destination"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b'}\xff\x95\x0en"H\x18' + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/freeze_account.py b/basics/anchorpy-main/tests/client-gen/token/instructions/freeze_account.py new file mode 100644 index 0000000..921cded --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/freeze_account.py @@ -0,0 +1,29 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class FreezeAccountAccounts(typing.TypedDict): + account: Pubkey + mint: Pubkey + owner: Pubkey + + +def freeze_account( + accounts: FreezeAccountAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xfdKR\x85\xa7\xee+\x82" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/get_account_data_size.py b/basics/anchorpy-main/tests/client-gen/token/instructions/get_account_data_size.py new file mode 100644 index 0000000..f5a55f4 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/get_account_data_size.py @@ -0,0 +1,25 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class GetAccountDataSizeAccounts(typing.TypedDict): + mint: Pubkey + + +def get_account_data_size( + accounts: GetAccountDataSizeAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False) + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x10\xb1\xd2\x80\x15-o\x1f" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account.py new file mode 100644 index 0000000..288bef6 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account.py @@ -0,0 +1,31 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.sysvar import RENT +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class InitializeAccountAccounts(typing.TypedDict): + account: Pubkey + mint: Pubkey + owner: Pubkey + + +def initialize_account( + accounts: InitializeAccountAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["owner"], is_signer=False, is_writable=False), + AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"Jsc]\xc5Eg\x07" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account2.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account2.py new file mode 100644 index 0000000..b3257fb --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account2.py @@ -0,0 +1,43 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.sysvar import RENT +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitializeAccount2Args(typing.TypedDict): + owner: Pubkey + + +layout = borsh.CStruct("owner" / BorshPubkey) + + +class InitializeAccount2Accounts(typing.TypedDict): + account: Pubkey + mint: Pubkey + + +def initialize_account2( + args: InitializeAccount2Args, + accounts: InitializeAccount2Accounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False), + AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x08\xb6\x95\x90\xb9\x1f\xd1i" + encoded_args = layout.build( + { + "owner": args["owner"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account3.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account3.py new file mode 100644 index 0000000..83427fb --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_account3.py @@ -0,0 +1,41 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitializeAccount3Args(typing.TypedDict): + owner: Pubkey + + +layout = borsh.CStruct("owner" / BorshPubkey) + + +class InitializeAccount3Accounts(typing.TypedDict): + account: Pubkey + mint: Pubkey + + +def initialize_account3( + args: InitializeAccount3Args, + accounts: InitializeAccount3Accounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x17\x8e\x8c\x87\x15\xa0\x85@" + encoded_args = layout.build( + { + "owner": args["owner"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_immutable_owner.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_immutable_owner.py new file mode 100644 index 0000000..ffea985 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_immutable_owner.py @@ -0,0 +1,25 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class InitializeImmutableOwnerAccounts(typing.TypedDict): + account: Pubkey + + +def initialize_immutable_owner( + accounts: InitializeImmutableOwnerAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True) + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b'\x8d2\x0f,\xc3\xf7"<' + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_mint.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_mint.py new file mode 100644 index 0000000..c2b94af --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_mint.py @@ -0,0 +1,49 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.sysvar import RENT +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey, COption +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitializeMintArgs(typing.TypedDict): + decimals: int + mint_authority: Pubkey + freeze_authority: typing.Optional[Pubkey] + + +layout = borsh.CStruct( + "decimals" / borsh.U8, + "mint_authority" / BorshPubkey, + "freeze_authority" / COption(BorshPubkey), +) + + +class InitializeMintAccounts(typing.TypedDict): + mint: Pubkey + + +def initialize_mint( + args: InitializeMintArgs, + accounts: InitializeMintAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=True), + AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xd1*\xc3\x04\x81U\xd1," + encoded_args = layout.build( + { + "decimals": args["decimals"], + "mint_authority": args["mint_authority"], + "freeze_authority": args["freeze_authority"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_mint2.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_mint2.py new file mode 100644 index 0000000..ef12ee6 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_mint2.py @@ -0,0 +1,47 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey, COption +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitializeMint2Args(typing.TypedDict): + decimals: int + mint_authority: Pubkey + freeze_authority: typing.Optional[Pubkey] + + +layout = borsh.CStruct( + "decimals" / borsh.U8, + "mint_authority" / BorshPubkey, + "freeze_authority" / COption(BorshPubkey), +) + + +class InitializeMint2Accounts(typing.TypedDict): + mint: Pubkey + + +def initialize_mint2( + args: InitializeMint2Args, + accounts: InitializeMint2Accounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=True) + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"_l\xc6\xd2H\xf3\x8f\xeb" + encoded_args = layout.build( + { + "decimals": args["decimals"], + "mint_authority": args["mint_authority"], + "freeze_authority": args["freeze_authority"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_multisig.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_multisig.py new file mode 100644 index 0000000..e5a7374 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_multisig.py @@ -0,0 +1,40 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.sysvar import RENT +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitializeMultisigArgs(typing.TypedDict): + m: int + + +layout = borsh.CStruct("m" / borsh.U8) + + +class InitializeMultisigAccounts(typing.TypedDict): + multisig: Pubkey + + +def initialize_multisig( + args: InitializeMultisigArgs, + accounts: InitializeMultisigAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["multisig"], is_signer=False, is_writable=True), + AccountMeta(pubkey=RENT, is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xdc\x82u\x15\x1b\xe3N\xd5" + encoded_args = layout.build( + { + "m": args["m"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_multisig2.py b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_multisig2.py new file mode 100644 index 0000000..2d77574 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/initialize_multisig2.py @@ -0,0 +1,40 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class InitializeMultisig2Args(typing.TypedDict): + m: int + + +layout = borsh.CStruct("m" / borsh.U8) + + +class InitializeMultisig2Accounts(typing.TypedDict): + multisig: Pubkey + signer: Pubkey + + +def initialize_multisig2( + args: InitializeMultisig2Args, + accounts: InitializeMultisig2Accounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["multisig"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["signer"], is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"Q\xefI'\x1b\x94\x02\x92" + encoded_args = layout.build( + { + "m": args["m"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/mint_to.py b/basics/anchorpy-main/tests/client-gen/token/instructions/mint_to.py new file mode 100644 index 0000000..947566c --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/mint_to.py @@ -0,0 +1,42 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class MintToArgs(typing.TypedDict): + amount: int + + +layout = borsh.CStruct("amount" / borsh.U64) + + +class MintToAccounts(typing.TypedDict): + mint: Pubkey + account: Pubkey + owner: Pubkey + + +def mint_to( + args: MintToArgs, + accounts: MintToAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b'\xf1"0\xba%\xb3{\xc0' + encoded_args = layout.build( + { + "amount": args["amount"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/mint_to_checked.py b/basics/anchorpy-main/tests/client-gen/token/instructions/mint_to_checked.py new file mode 100644 index 0000000..f4ba48c --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/mint_to_checked.py @@ -0,0 +1,44 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class MintToCheckedArgs(typing.TypedDict): + amount: int + decimals: int + + +layout = borsh.CStruct("amount" / borsh.U64, "decimals" / borsh.U8) + + +class MintToCheckedAccounts(typing.TypedDict): + mint: Pubkey + account: Pubkey + owner: Pubkey + + +def mint_to_checked( + args: MintToCheckedArgs, + accounts: MintToCheckedAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xe5\xec$\xf0v\xe1-}" + encoded_args = layout.build( + { + "amount": args["amount"], + "decimals": args["decimals"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/revoke.py b/basics/anchorpy-main/tests/client-gen/token/instructions/revoke.py new file mode 100644 index 0000000..54009f8 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/revoke.py @@ -0,0 +1,27 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class RevokeAccounts(typing.TypedDict): + source: Pubkey + owner: Pubkey + + +def revoke( + accounts: RevokeAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["source"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b'\xaa\x17\x1f"\x85\xad]\xf2' + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/set_authority.py b/basics/anchorpy-main/tests/client-gen/token/instructions/set_authority.py new file mode 100644 index 0000000..51ad91c --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/set_authority.py @@ -0,0 +1,49 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from anchorpy.borsh_extension import BorshPubkey, COption +import borsh_construct as borsh +from .. import types +from ..program_id import PROGRAM_ID + + +class SetAuthorityArgs(typing.TypedDict): + authority_type: types.authority_type.AuthorityTypeKind + new_authority: typing.Optional[Pubkey] + + +layout = borsh.CStruct( + "authority_type" / types.authority_type.layout, + "new_authority" / COption(BorshPubkey), +) + + +class SetAuthorityAccounts(typing.TypedDict): + owned: Pubkey + owner: Pubkey + signer: Pubkey + + +def set_authority( + args: SetAuthorityArgs, + accounts: SetAuthorityAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["owned"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + AccountMeta(pubkey=accounts["signer"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x85\xfa%\x15n\xa3\x1ay" + encoded_args = layout.build( + { + "authority_type": args["authority_type"].to_encodable(), + "new_authority": args["new_authority"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/sync_native.py b/basics/anchorpy-main/tests/client-gen/token/instructions/sync_native.py new file mode 100644 index 0000000..d615229 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/sync_native.py @@ -0,0 +1,25 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class SyncNativeAccounts(typing.TypedDict): + account: Pubkey + + +def sync_native( + accounts: SyncNativeAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True) + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x9b\xdb$$\xef\x80\x15A" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/thaw_account.py b/basics/anchorpy-main/tests/client-gen/token/instructions/thaw_account.py new file mode 100644 index 0000000..fab2d9c --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/thaw_account.py @@ -0,0 +1,29 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class ThawAccountAccounts(typing.TypedDict): + account: Pubkey + mint: Pubkey + owner: Pubkey + + +def thaw_account( + accounts: ThawAccountAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"s\x98O\xd5\xd5\xa9\xb8#" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/transfer.py b/basics/anchorpy-main/tests/client-gen/token/instructions/transfer.py new file mode 100644 index 0000000..a24edfb --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/transfer.py @@ -0,0 +1,42 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class TransferArgs(typing.TypedDict): + amount: int + + +layout = borsh.CStruct("amount" / borsh.U64) + + +class TransferAccounts(typing.TypedDict): + source: Pubkey + destination: Pubkey + authority: Pubkey + + +def transfer( + args: TransferArgs, + accounts: TransferAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["source"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["destination"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["authority"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xa34\xc8\xe7\x8c\x03E\xba" + encoded_args = layout.build( + { + "amount": args["amount"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/transfer_checked.py b/basics/anchorpy-main/tests/client-gen/token/instructions/transfer_checked.py new file mode 100644 index 0000000..429e631 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/transfer_checked.py @@ -0,0 +1,46 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class TransferCheckedArgs(typing.TypedDict): + amount: int + decimals: int + + +layout = borsh.CStruct("amount" / borsh.U64, "decimals" / borsh.U8) + + +class TransferCheckedAccounts(typing.TypedDict): + source: Pubkey + mint: Pubkey + destination: Pubkey + authority: Pubkey + + +def transfer_checked( + args: TransferCheckedArgs, + accounts: TransferCheckedAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["source"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["destination"], is_signer=False, is_writable=True), + AccountMeta(pubkey=accounts["authority"], is_signer=True, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"w\xfa\xca\x18\xfd\x87\xf4y" + encoded_args = layout.build( + { + "amount": args["amount"], + "decimals": args["decimals"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/instructions/ui_amount_to_amount.py b/basics/anchorpy-main/tests/client-gen/token/instructions/ui_amount_to_amount.py new file mode 100644 index 0000000..bc72ac8 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/instructions/ui_amount_to_amount.py @@ -0,0 +1,38 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +import borsh_construct as borsh +from ..program_id import PROGRAM_ID + + +class UiAmountToAmountArgs(typing.TypedDict): + ui_amount: str + + +layout = borsh.CStruct(borsh.String) + + +class UiAmountToAmountAccounts(typing.TypedDict): + mint: Pubkey + + +def ui_amount_to_amount( + args: UiAmountToAmountArgs, + accounts: UiAmountToAmountAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False) + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xad\xf3@\x04g\x1f84" + encoded_args = layout.build( + { + "ui_amount": args["ui_amount"], + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/basics/anchorpy-main/tests/client-gen/token/program_id.py b/basics/anchorpy-main/tests/client-gen/token/program_id.py new file mode 100644 index 0000000..6f3e9ff --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/program_id.py @@ -0,0 +1,3 @@ +from solders.pubkey import Pubkey + +PROGRAM_ID = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") diff --git a/basics/anchorpy-main/tests/client-gen/token/types/__init__.py b/basics/anchorpy-main/tests/client-gen/token/types/__init__.py new file mode 100644 index 0000000..a0a21a6 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/types/__init__.py @@ -0,0 +1,5 @@ +import typing +from . import account_state +from .account_state import AccountStateKind, AccountStateJSON +from . import authority_type +from .authority_type import AuthorityTypeKind, AuthorityTypeJSON diff --git a/basics/anchorpy-main/tests/client-gen/token/types/account_state.py b/basics/anchorpy-main/tests/client-gen/token/types/account_state.py new file mode 100644 index 0000000..29e8464 --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/types/account_state.py @@ -0,0 +1,105 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from anchorpy.borsh_extension import EnumForCodegen +import borsh_construct as borsh + + +class UninitializedJSON(typing.TypedDict): + kind: typing.Literal["Uninitialized"] + + +class InitializedJSON(typing.TypedDict): + kind: typing.Literal["Initialized"] + + +class FrozenJSON(typing.TypedDict): + kind: typing.Literal["Frozen"] + + +@dataclass +class Uninitialized: + discriminator: typing.ClassVar = 0 + kind: typing.ClassVar = "Uninitialized" + + @classmethod + def to_json(cls) -> UninitializedJSON: + return UninitializedJSON( + kind="Uninitialized", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "Uninitialized": {}, + } + + +@dataclass +class Initialized: + discriminator: typing.ClassVar = 1 + kind: typing.ClassVar = "Initialized" + + @classmethod + def to_json(cls) -> InitializedJSON: + return InitializedJSON( + kind="Initialized", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "Initialized": {}, + } + + +@dataclass +class Frozen: + discriminator: typing.ClassVar = 2 + kind: typing.ClassVar = "Frozen" + + @classmethod + def to_json(cls) -> FrozenJSON: + return FrozenJSON( + kind="Frozen", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "Frozen": {}, + } + + +AccountStateKind = typing.Union[Uninitialized, Initialized, Frozen] +AccountStateJSON = typing.Union[UninitializedJSON, InitializedJSON, FrozenJSON] + + +def from_decoded(obj: dict) -> AccountStateKind: + if not isinstance(obj, dict): + raise ValueError("Invalid enum object") + if "Uninitialized" in obj: + return Uninitialized() + if "Initialized" in obj: + return Initialized() + if "Frozen" in obj: + return Frozen() + raise ValueError("Invalid enum object") + + +def from_json(obj: AccountStateJSON) -> AccountStateKind: + if obj["kind"] == "Uninitialized": + return Uninitialized() + if obj["kind"] == "Initialized": + return Initialized() + if obj["kind"] == "Frozen": + return Frozen() + kind = obj["kind"] + raise ValueError(f"Unrecognized enum kind: {kind}") + + +layout = EnumForCodegen( + "Uninitialized" / borsh.CStruct(), + "Initialized" / borsh.CStruct(), + "Frozen" / borsh.CStruct(), +) diff --git a/basics/anchorpy-main/tests/client-gen/token/types/authority_type.py b/basics/anchorpy-main/tests/client-gen/token/types/authority_type.py new file mode 100644 index 0000000..b77138e --- /dev/null +++ b/basics/anchorpy-main/tests/client-gen/token/types/authority_type.py @@ -0,0 +1,134 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from anchorpy.borsh_extension import EnumForCodegen +import borsh_construct as borsh + + +class MintTokensJSON(typing.TypedDict): + kind: typing.Literal["MintTokens"] + + +class FreezeAccountJSON(typing.TypedDict): + kind: typing.Literal["FreezeAccount"] + + +class AccountOwnerJSON(typing.TypedDict): + kind: typing.Literal["AccountOwner"] + + +class CloseAccountJSON(typing.TypedDict): + kind: typing.Literal["CloseAccount"] + + +@dataclass +class MintTokens: + discriminator: typing.ClassVar = 0 + kind: typing.ClassVar = "MintTokens" + + @classmethod + def to_json(cls) -> MintTokensJSON: + return MintTokensJSON( + kind="MintTokens", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "MintTokens": {}, + } + + +@dataclass +class FreezeAccount: + discriminator: typing.ClassVar = 1 + kind: typing.ClassVar = "FreezeAccount" + + @classmethod + def to_json(cls) -> FreezeAccountJSON: + return FreezeAccountJSON( + kind="FreezeAccount", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "FreezeAccount": {}, + } + + +@dataclass +class AccountOwner: + discriminator: typing.ClassVar = 2 + kind: typing.ClassVar = "AccountOwner" + + @classmethod + def to_json(cls) -> AccountOwnerJSON: + return AccountOwnerJSON( + kind="AccountOwner", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "AccountOwner": {}, + } + + +@dataclass +class CloseAccount: + discriminator: typing.ClassVar = 3 + kind: typing.ClassVar = "CloseAccount" + + @classmethod + def to_json(cls) -> CloseAccountJSON: + return CloseAccountJSON( + kind="CloseAccount", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "CloseAccount": {}, + } + + +AuthorityTypeKind = typing.Union[MintTokens, FreezeAccount, AccountOwner, CloseAccount] +AuthorityTypeJSON = typing.Union[ + MintTokensJSON, FreezeAccountJSON, AccountOwnerJSON, CloseAccountJSON +] + + +def from_decoded(obj: dict) -> AuthorityTypeKind: + if not isinstance(obj, dict): + raise ValueError("Invalid enum object") + if "MintTokens" in obj: + return MintTokens() + if "FreezeAccount" in obj: + return FreezeAccount() + if "AccountOwner" in obj: + return AccountOwner() + if "CloseAccount" in obj: + return CloseAccount() + raise ValueError("Invalid enum object") + + +def from_json(obj: AuthorityTypeJSON) -> AuthorityTypeKind: + if obj["kind"] == "MintTokens": + return MintTokens() + if obj["kind"] == "FreezeAccount": + return FreezeAccount() + if obj["kind"] == "AccountOwner": + return AccountOwner() + if obj["kind"] == "CloseAccount": + return CloseAccount() + kind = obj["kind"] + raise ValueError(f"Unrecognized enum kind: {kind}") + + +layout = EnumForCodegen( + "MintTokens" / borsh.CStruct(), + "FreezeAccount" / borsh.CStruct(), + "AccountOwner" / borsh.CStruct(), + "CloseAccount" / borsh.CStruct(), +) diff --git a/basics/anchorpy-main/tests/conftest.py b/basics/anchorpy-main/tests/conftest.py new file mode 100644 index 0000000..7030338 --- /dev/null +++ b/basics/anchorpy-main/tests/conftest.py @@ -0,0 +1,38 @@ +"""Pytest config.""" +import asyncio +import subprocess +from pathlib import Path + +from pytest import fixture + +# Since our other fixtures have module scope, we need to define +# this event_loop fixture and give it module scope otherwise +# pytest-asyncio will break. + + +@fixture(scope="module") +def event_loop(): + """Create an instance of the default event loop for each test case.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + +@fixture(scope="session") +def project_parent_dir(tmpdir_factory) -> Path: + return Path(tmpdir_factory.mktemp("temp")) + + +@fixture(scope="session") +def project_dir(project_parent_dir: Path) -> Path: + proj_dir = project_parent_dir / "tmp" + command = ( + f"anchorpy client-gen tests/idls/clientgen_example_program.json {proj_dir} " + "--program-id 3rTQ3R4B2PxZrAyx7EUefySPgZY8RhJf16cZajbmrzp8 --pdas" + ) + subprocess.run( + command, + shell=True, + check=True, + ) + return proj_dir diff --git a/basics/anchorpy-main/tests/idls/basic_0.json b/basics/anchorpy-main/tests/idls/basic_0.json new file mode 100644 index 0000000..6eb8507 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/basic_0.json @@ -0,0 +1,14 @@ +{ + "version": "0.0.0", + "name": "basic_0", + "instructions": [ + { + "name": "initialize", + "accounts": [], + "args": [] + } + ], + "metadata": { + "address": "8nA4T4UFdYz1sKuEFdnj2mYcJ6hp79Tw14sPvTQVWwVb" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/basic_1.json b/basics/anchorpy-main/tests/idls/basic_1.json new file mode 100644 index 0000000..810ed34 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/basic_1.json @@ -0,0 +1,57 @@ +{ + "version": "0.0.0", + "name": "basic_1", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "myAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "data", + "type": "u64" + } + ] + }, + { + "name": "update", + "accounts": [ + { + "name": "myAccount", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "data", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "MyAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": "u64" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/basic_2.json b/basics/anchorpy-main/tests/idls/basic_2.json new file mode 100644 index 0000000..7777c45 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/basic_2.json @@ -0,0 +1,64 @@ +{ + "version": "0.0.0", + "name": "basic_2", + "instructions": [ + { + "name": "create", + "accounts": [ + { + "name": "counter", + "isMut": true, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "authority", + "type": "publicKey" + } + ] + }, + { + "name": "increment", + "accounts": [ + { + "name": "counter", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "Counter", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "count", + "type": "u64" + } + ] + } + } + ], + "metadata": { + "address": "4V6T2muqU1mHSg5XfK3SMgxZWQRSEUh72LzwGTLHGzsY" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/basic_5.json b/basics/anchorpy-main/tests/idls/basic_5.json new file mode 100644 index 0000000..ecde024 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/basic_5.json @@ -0,0 +1,80 @@ +{ + "version": "0.0.0", + "name": "basic_5", + "instructions": [ + { + "name": "createMint", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "createToken", + "accounts": [ + { + "name": "token", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "Mint", + "type": { + "kind": "struct", + "fields": [ + { + "name": "supply", + "type": "u32" + } + ] + } + }, + { + "name": "Token", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u32" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "mint", + "type": "publicKey" + } + ] + } + } + ], + "metadata": { + "address": "99cGumFqPFhCLTUxs9BoyhXAV6c19Ca44BYZVn6KG1Pu" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/candy_machine.json b/basics/anchorpy-main/tests/idls/candy_machine.json new file mode 100644 index 0000000..dcae308 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/candy_machine.json @@ -0,0 +1,915 @@ +{ + "version": "4.0.2", + "name": "candy_machine", + "instructions": [ + { + "name": "initializeCandyMachine", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "wallet", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "data", + "type": { + "defined": "CandyMachineData" + } + } + ] + }, + { + "name": "updateCandyMachine", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "wallet", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "data", + "type": { + "defined": "CandyMachineData" + } + } + ] + }, + { + "name": "updateAuthority", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "wallet", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "newAuthority", + "type": { + "option": "publicKey" + } + } + ] + }, + { + "name": "addConfigLines", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "index", + "type": "u32" + }, + { + "name": "configLines", + "type": { + "vec": { + "defined": "ConfigLine" + } + } + } + ] + }, + { + "name": "setCollection", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "collectionPda", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "metadata", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "edition", + "isMut": false, + "isSigner": false + }, + { + "name": "collectionAuthorityRecord", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenMetadataProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "removeCollection", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "collectionPda", + "isMut": true, + "isSigner": false + }, + { + "name": "metadata", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "collectionAuthorityRecord", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenMetadataProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "mintNft", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "candyMachineCreator", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "wallet", + "isMut": true, + "isSigner": false + }, + { + "name": "metadata", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "mintAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "updateAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "masterEdition", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenMetadataProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false, + "docs": [ + "Account not actually used." + ] + }, + { + "name": "recentBlockhashes", + "isMut": false, + "isSigner": false + }, + { + "name": "instructionSysvarAccount", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "creatorBump", + "type": "u8" + } + ] + }, + { + "name": "setCollectionDuringMint", + "accounts": [ + { + "name": "candyMachine", + "isMut": false, + "isSigner": false + }, + { + "name": "metadata", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "collectionPda", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenMetadataProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "instructions", + "isMut": false, + "isSigner": false + }, + { + "name": "collectionMint", + "isMut": false, + "isSigner": false + }, + { + "name": "collectionMetadata", + "isMut": false, + "isSigner": false + }, + { + "name": "collectionMasterEdition", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "collectionAuthorityRecord", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "withdrawFunds", + "accounts": [ + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "CandyMachine", + "docs": [ + "Candy machine state and config data." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "wallet", + "type": "publicKey" + }, + { + "name": "tokenMint", + "type": { + "option": "publicKey" + } + }, + { + "name": "itemsRedeemed", + "type": "u64" + }, + { + "name": "data", + "type": { + "defined": "CandyMachineData" + } + } + ] + } + }, + { + "name": "CollectionPDA", + "docs": [ + "Collection PDA account" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "mint", + "type": "publicKey" + }, + { + "name": "candyMachine", + "type": "publicKey" + } + ] + } + } + ], + "types": [ + { + "name": "CandyMachineData", + "docs": [ + "Candy machine settings data." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "price", + "type": "u64" + }, + { + "name": "symbol", + "docs": [ + "The symbol for the asset" + ], + "type": "string" + }, + { + "name": "sellerFeeBasisPoints", + "docs": [ + "Royalty basis points that goes to creators in secondary sales (0-10000)" + ], + "type": "u16" + }, + { + "name": "maxSupply", + "type": "u64" + }, + { + "name": "isMutable", + "type": "bool" + }, + { + "name": "retainAuthority", + "type": "bool" + }, + { + "name": "goLiveDate", + "type": { + "option": "i64" + } + }, + { + "name": "endSettings", + "type": { + "option": { + "defined": "EndSettings" + } + } + }, + { + "name": "creators", + "type": { + "vec": { + "defined": "Creator" + } + } + }, + { + "name": "hiddenSettings", + "type": { + "option": { + "defined": "HiddenSettings" + } + } + }, + { + "name": "whitelistMintSettings", + "type": { + "option": { + "defined": "WhitelistMintSettings" + } + } + }, + { + "name": "itemsAvailable", + "type": "u64" + }, + { + "name": "gatekeeper", + "docs": [ + "If [`Some`] requires gateway tokens on mint" + ], + "type": { + "option": { + "defined": "GatekeeperConfig" + } + } + } + ] + } + }, + { + "name": "ConfigLine", + "docs": [ + "Individual config line for storing NFT data pre-mint." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "uri", + "docs": [ + "URI pointing to JSON representing the asset" + ], + "type": "string" + } + ] + } + }, + { + "name": "EndSettings", + "type": { + "kind": "struct", + "fields": [ + { + "name": "endSettingType", + "type": { + "defined": "EndSettingType" + } + }, + { + "name": "number", + "type": "u64" + } + ] + } + }, + { + "name": "Creator", + "type": { + "kind": "struct", + "fields": [ + { + "name": "address", + "type": "publicKey" + }, + { + "name": "verified", + "type": "bool" + }, + { + "name": "share", + "type": "u8" + } + ] + } + }, + { + "name": "HiddenSettings", + "docs": [ + "Hidden Settings for large mints used with offline data." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "uri", + "type": "string" + }, + { + "name": "hash", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "WhitelistMintSettings", + "type": { + "kind": "struct", + "fields": [ + { + "name": "mode", + "type": { + "defined": "WhitelistMintMode" + } + }, + { + "name": "mint", + "type": "publicKey" + }, + { + "name": "presale", + "type": "bool" + }, + { + "name": "discountPrice", + "type": { + "option": "u64" + } + } + ] + } + }, + { + "name": "GatekeeperConfig", + "docs": [ + "Configurations options for the gatekeeper." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "gatekeeperNetwork", + "docs": [ + "The network for the gateway token required" + ], + "type": "publicKey" + }, + { + "name": "expireOnUse", + "docs": [ + "Whether or not the token should expire after minting.", + "The gatekeeper network must support this if true." + ], + "type": "bool" + } + ] + } + }, + { + "name": "EndSettingType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Date" + }, + { + "name": "Amount" + } + ] + } + }, + { + "name": "WhitelistMintMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "BurnEveryTime" + }, + { + "name": "NeverBurn" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "IncorrectOwner", + "msg": "Account does not have correct owner!" + }, + { + "code": 6001, + "name": "Uninitialized", + "msg": "Account is not initialized!" + }, + { + "code": 6002, + "name": "MintMismatch", + "msg": "Mint Mismatch!" + }, + { + "code": 6003, + "name": "IndexGreaterThanLength", + "msg": "Index greater than length!" + }, + { + "code": 6004, + "name": "NumericalOverflowError", + "msg": "Numerical overflow error!" + }, + { + "code": 6005, + "name": "TooManyCreators", + "msg": "Can only provide up to 4 creators to candy machine (because candy machine is one)!" + }, + { + "code": 6006, + "name": "UuidMustBeExactly6Length", + "msg": "Uuid must be exactly of 6 length" + }, + { + "code": 6007, + "name": "NotEnoughTokens", + "msg": "Not enough tokens to pay for this minting" + }, + { + "code": 6008, + "name": "NotEnoughSOL", + "msg": "Not enough SOL to pay for this minting" + }, + { + "code": 6009, + "name": "TokenTransferFailed", + "msg": "Token transfer failed" + }, + { + "code": 6010, + "name": "CandyMachineEmpty", + "msg": "Candy machine is empty!" + }, + { + "code": 6011, + "name": "CandyMachineNotLive", + "msg": "Candy machine is not live!" + }, + { + "code": 6012, + "name": "HiddenSettingsConfigsDoNotHaveConfigLines", + "msg": "Configs that are using hidden uris do not have config lines, they have a single hash representing hashed order" + }, + { + "code": 6013, + "name": "CannotChangeNumberOfLines", + "msg": "Cannot change number of lines unless is a hidden config" + }, + { + "code": 6014, + "name": "DerivedKeyInvalid", + "msg": "Derived key invalid" + }, + { + "code": 6015, + "name": "PublicKeyMismatch", + "msg": "Public key mismatch" + }, + { + "code": 6016, + "name": "NoWhitelistToken", + "msg": "No whitelist token present" + }, + { + "code": 6017, + "name": "TokenBurnFailed", + "msg": "Token burn failed" + }, + { + "code": 6018, + "name": "GatewayAppMissing", + "msg": "Missing gateway app when required" + }, + { + "code": 6019, + "name": "GatewayTokenMissing", + "msg": "Missing gateway token when required" + }, + { + "code": 6020, + "name": "GatewayTokenExpireTimeInvalid", + "msg": "Invalid gateway token expire time" + }, + { + "code": 6021, + "name": "NetworkExpireFeatureMissing", + "msg": "Missing gateway network expire feature when required" + }, + { + "code": 6022, + "name": "CannotFindUsableConfigLine", + "msg": "Unable to find an unused config line near your random number index" + }, + { + "code": 6023, + "name": "InvalidString", + "msg": "Invalid string" + }, + { + "code": 6024, + "name": "SuspiciousTransaction", + "msg": "Suspicious transaction detected" + }, + { + "code": 6025, + "name": "CannotSwitchToHiddenSettings", + "msg": "Cannot Switch to Hidden Settings after items available is greater than 0" + }, + { + "code": 6026, + "name": "IncorrectSlotHashesPubkey", + "msg": "Incorrect SlotHashes PubKey" + }, + { + "code": 6027, + "name": "IncorrectCollectionAuthority", + "msg": "Incorrect collection NFT authority" + }, + { + "code": 6028, + "name": "MismatchedCollectionPDA", + "msg": "Collection PDA address is invalid" + }, + { + "code": 6029, + "name": "MismatchedCollectionMint", + "msg": "Provided mint account doesn't match collection PDA mint" + }, + { + "code": 6030, + "name": "SlotHashesEmpty", + "msg": "Slot hashes Sysvar is empty" + }, + { + "code": 6031, + "name": "MetadataAccountMustBeEmpty", + "msg": "The metadata account has data in it, and this must be empty to mint a new NFT" + }, + { + "code": 6032, + "name": "MissingSetCollectionDuringMint", + "msg": "Missing set collection during mint IX for Candy Machine with collection set" + }, + { + "code": 6033, + "name": "NoChangingCollectionDuringMint", + "msg": "Can't change collection settings after items have begun to be minted" + }, + { + "code": 6034, + "name": "CandyCollectionRequiresRetainAuthority", + "msg": "Retain authority must be true for Candy Machines with a collection set" + }, + { + "code": 6035, + "name": "GatewayProgramError", + "msg": "Error within Gateway program" + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/cashiers_check.json b/basics/anchorpy-main/tests/idls/cashiers_check.json new file mode 100644 index 0000000..0b24577 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/cashiers_check.json @@ -0,0 +1,191 @@ +{ + "version": "0.0.0", + "name": "cashiers_check", + "instructions": [ + { + "name": "createCheck", + "accounts": [ + { + "name": "check", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "checkSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false + }, + { + "name": "to", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "memo", + "type": { + "option": "string" + } + }, + { + "name": "nonce", + "type": "u8" + } + ] + }, + { + "name": "cashCheck", + "accounts": [ + { + "name": "check", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "checkSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "to", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "cancelCheck", + "accounts": [ + { + "name": "check", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "checkSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "Check", + "type": { + "kind": "struct", + "fields": [ + { + "name": "from", + "type": "publicKey" + }, + { + "name": "to", + "type": "publicKey" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "memo", + "type": { + "option": "string" + } + }, + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "nonce", + "type": "u8" + }, + { + "name": "burned", + "type": "bool" + } + ] + } + } + ], + "errors": [ + { + "code": 300, + "name": "InvalidCheckNonce", + "msg": "The given nonce does not create a valid program derived address." + }, + { + "code": 301, + "name": "InvalidCheckSigner", + "msg": "The derived check signer does not match that which was given." + }, + { + "code": 302, + "name": "AlreadyBurned", + "msg": "The given check has already been burned." + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/chat.json b/basics/anchorpy-main/tests/idls/chat.json new file mode 100644 index 0000000..c911efa --- /dev/null +++ b/basics/anchorpy-main/tests/idls/chat.json @@ -0,0 +1,157 @@ +{ + "version": "0.0.0", + "name": "chat", + "instructions": [ + { + "name": "createUser", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": "string" + } + ] + }, + { + "name": "createChatRoom", + "accounts": [ + { + "name": "chatRoom", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": "string" + } + ] + }, + { + "name": "sendMessage", + "accounts": [ + { + "name": "user", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "chatRoom", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "msg", + "type": "string" + } + ] + } + ], + "accounts": [ + { + "name": "User", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "authority", + "type": "publicKey" + } + ] + } + }, + { + "name": "ChatRoom", + "type": { + "kind": "struct", + "fields": [ + { + "name": "head", + "type": "u64" + }, + { + "name": "tail", + "type": "u64" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 280 + ] + } + }, + { + "name": "messages", + "type": { + "array": [ + { + "defined": "Message" + }, + 33607 + ] + } + } + ] + } + } + ], + "types": [ + { + "name": "Message", + "type": { + "kind": "struct", + "fields": [ + { + "name": "from", + "type": "publicKey" + }, + { + "name": "data", + "type": { + "array": [ + "u8", + 280 + ] + } + } + ] + } + } + ], + "errors": [ + { + "code": 300, + "name": "Unknown" + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/clientgen_example_program.json b/basics/anchorpy-main/tests/idls/clientgen_example_program.json new file mode 100644 index 0000000..f5b322d --- /dev/null +++ b/basics/anchorpy-main/tests/idls/clientgen_example_program.json @@ -0,0 +1,737 @@ +{ + "version": "0.1.0", + "name": "example_program", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": true + }, + { + "name": "nested", + "accounts": [ + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeWithValues", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": true + }, + { + "name": "nested", + "accounts": [ + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "boolField", + "type": "bool" + }, + { + "name": "u8Field", + "type": "u8" + }, + { + "name": "i8Field", + "type": "i8" + }, + { + "name": "u16Field", + "type": "u16" + }, + { + "name": "i16Field", + "type": "i16" + }, + { + "name": "u32Field", + "type": "u32" + }, + { + "name": "i32Field", + "type": "i32" + }, + { + "name": "f32Field", + "type": "f32" + }, + { + "name": "u64Field", + "type": "u64" + }, + { + "name": "i64Field", + "type": "i64" + }, + { + "name": "f64Field", + "type": "f64" + }, + { + "name": "u128Field", + "type": "u128" + }, + { + "name": "i128Field", + "type": "i128" + }, + { + "name": "bytesField", + "type": "bytes" + }, + { + "name": "stringField", + "type": "string" + }, + { + "name": "pubkeyField", + "type": "publicKey" + }, + { + "name": "vecField", + "type": { + "vec": "u64" + } + }, + { + "name": "vecStructField", + "type": { + "vec": { + "defined": "FooStruct" + } + } + }, + { + "name": "optionField", + "type": { + "option": "bool" + } + }, + { + "name": "optionStructField", + "type": { + "option": { + "defined": "FooStruct" + } + } + }, + { + "name": "structField", + "type": { + "defined": "FooStruct" + } + }, + { + "name": "arrayField", + "type": { + "array": [ + "bool", + 3 + ] + } + }, + { + "name": "enumField1", + "type": { + "defined": "FooEnum" + } + }, + { + "name": "enumField2", + "type": { + "defined": "FooEnum" + } + }, + { + "name": "enumField3", + "type": { + "defined": "FooEnum" + } + }, + { + "name": "enumField4", + "type": { + "defined": "FooEnum" + } + } + ] + }, + { + "name": "initializeWithValues2", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "vecOfOption", + "type": { + "vec": { + "option": "u64" + } + } + } + ] + }, + { + "name": "causeError", + "accounts": [], + "args": [] + }, + { + "name": "initMyAccount", + "accounts": [ + { + "name": "base", + "isMut": false, + "isSigner": false + }, + { + "name": "base2", + "isMut": false, + "isSigner": false + }, + { + "name": "account", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "another-seed" + }, + { + "kind": "const", + "type": "string", + "value": "test" + }, + { + "kind": "const", + "type": { + "array": [ + "u8", + 2 + ] + }, + "value": [ + 104, + 105 + ] + }, + { + "kind": "const", + "type": "string", + "value": "hi" + }, + { + "kind": "const", + "type": "u8", + "value": 1 + }, + { + "kind": "const", + "type": "u32", + "value": 2 + }, + { + "kind": "const", + "type": "u64", + "value": 3 + } + ] + } + }, + { + "name": "nested", + "accounts": [ + { + "name": "accountNested", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "nested-seed" + }, + { + "kind": "const", + "type": "string", + "value": "test" + }, + { + "kind": "const", + "type": { + "array": [ + "u8", + 2 + ] + }, + "value": [ + 104, + 105 + ] + }, + { + "kind": "const", + "type": "string", + "value": "hi" + }, + { + "kind": "const", + "type": "u8", + "value": 1 + }, + { + "kind": "const", + "type": "u32", + "value": 2 + }, + { + "kind": "const", + "type": "u64", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "seedA", + "type": "u8" + } + ] + }, + { + "name": "incrementStateWhenPresent", + "accounts": [ + { + "name": "firstState", + "isMut": true, + "isSigner": false, + "isOptional": true + }, + { + "name": "secondState", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "MyAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": "u64" + } + ] + } + }, + { + "name": "BaseAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "baseData", + "type": "u64" + }, + { + "name": "baseDataKey", + "type": "publicKey" + } + ] + } + }, + { + "name": "State", + "type": { + "kind": "struct", + "fields": [ + { + "name": "boolField", + "type": "bool" + }, + { + "name": "u8Field", + "type": "u8" + }, + { + "name": "i8Field", + "type": "i8" + }, + { + "name": "u16Field", + "type": "u16" + }, + { + "name": "i16Field", + "type": "i16" + }, + { + "name": "u32Field", + "type": "u32" + }, + { + "name": "i32Field", + "type": "i32" + }, + { + "name": "f32Field", + "type": "f32" + }, + { + "name": "u64Field", + "type": "u64" + }, + { + "name": "i64Field", + "type": "i64" + }, + { + "name": "f64Field", + "type": "f64" + }, + { + "name": "u128Field", + "type": "u128" + }, + { + "name": "i128Field", + "type": "i128" + }, + { + "name": "bytesField", + "type": "bytes" + }, + { + "name": "stringField", + "type": "string" + }, + { + "name": "pubkeyField", + "type": "publicKey" + }, + { + "name": "vecField", + "type": { + "vec": "u64" + } + }, + { + "name": "vecStructField", + "type": { + "vec": { + "defined": "FooStruct" + } + } + }, + { + "name": "optionField", + "type": { + "option": "bool" + } + }, + { + "name": "optionStructField", + "type": { + "option": { + "defined": "FooStruct" + } + } + }, + { + "name": "structField", + "type": { + "defined": "FooStruct" + } + }, + { + "name": "arrayField", + "type": { + "array": [ + "bool", + 3 + ] + } + }, + { + "name": "enumField1", + "type": { + "defined": "FooEnum" + } + }, + { + "name": "enumField2", + "type": { + "defined": "FooEnum" + } + }, + { + "name": "enumField3", + "type": { + "defined": "FooEnum" + } + }, + { + "name": "enumField4", + "type": { + "defined": "FooEnum" + } + } + ] + } + }, + { + "name": "State2", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vecOfOption", + "type": { + "vec": { + "option": "u64" + } + } + } + ] + } + } + ], + "types": [ + { + "name": "BarStruct", + "type": { + "kind": "struct", + "fields": [ + { + "name": "someField", + "type": "bool" + }, + { + "name": "otherField", + "type": "u8" + } + ] + } + }, + { + "name": "FooStruct", + "type": { + "kind": "struct", + "fields": [ + { + "name": "field1", + "type": "u8" + }, + { + "name": "field2", + "type": "u16" + }, + { + "name": "nested", + "type": { + "defined": "BarStruct" + } + }, + { + "name": "vecNested", + "type": { + "vec": { + "defined": "BarStruct" + } + } + }, + { + "name": "optionNested", + "type": { + "option": { + "defined": "BarStruct" + } + } + }, + { + "name": "enumField", + "type": { + "defined": "FooEnum" + } + } + ] + } + }, + { + "name": "FooEnum", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Unnamed", + "fields": [ + "bool", + "u8", + { + "defined": "BarStruct" + } + ] + }, + { + "name": "UnnamedSingle", + "fields": [ + { + "defined": "BarStruct" + } + ] + }, + { + "name": "Named", + "fields": [ + { + "name": "bool_field", + "type": "bool" + }, + { + "name": "u8_field", + "type": "u8" + }, + { + "name": "nested", + "type": { + "defined": "BarStruct" + } + } + ] + }, + { + "name": "Struct", + "fields": [ + { + "defined": "BarStruct" + } + ] + }, + { + "name": "OptionStruct", + "fields": [ + { + "option": { + "defined": "BarStruct" + } + } + ] + }, + { + "name": "VecStruct", + "fields": [ + { + "vec": { + "defined": "BarStruct" + } + } + ] + }, + { + "name": "NoFields" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "SomeError", + "msg": "Example error." + }, + { + "code": 6001, + "name": "OtherError", + "msg": "Another error." + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/composite.json b/basics/anchorpy-main/tests/idls/composite.json new file mode 100644 index 0000000..e8d15b7 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/composite.json @@ -0,0 +1,86 @@ +{ + "version": "0.0.0", + "name": "composite", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "dummyA", + "isMut": true, + "isSigner": false + }, + { + "name": "dummyB", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "compositeUpdate", + "accounts": [ + { + "name": "foo", + "accounts": [ + { + "name": "dummyA", + "isMut": true, + "isSigner": false + } + ] + }, + { + "name": "bar", + "accounts": [ + { + "name": "dummyB", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "dummyA", + "type": "u64" + }, + { + "name": "dummyB", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "DummyA", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": "u64" + } + ] + } + }, + { + "name": "DummyB", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": "u64" + } + ] + } + } + ], + "metadata": { + "address": "FYuVUPk3hmpT44GjCTL6w8Z3kYQoYBAWZMXEi4P63xto" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/counter_auth.json b/basics/anchorpy-main/tests/idls/counter_auth.json new file mode 100644 index 0000000..4ad926a --- /dev/null +++ b/basics/anchorpy-main/tests/idls/counter_auth.json @@ -0,0 +1,5 @@ +{ + "version": "0.0.0", + "name": "counter_auth", + "instructions": [] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/errors.json b/basics/anchorpy-main/tests/idls/errors.json new file mode 100644 index 0000000..346f8a4 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/errors.json @@ -0,0 +1,88 @@ +{ + "version": "0.0.0", + "name": "errors", + "instructions": [ + { + "name": "hello", + "accounts": [], + "args": [] + }, + { + "name": "helloNoMsg", + "accounts": [], + "args": [] + }, + { + "name": "helloNext", + "accounts": [], + "args": [] + }, + { + "name": "mutError", + "accounts": [ + { + "name": "myAccount", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "hasOneError", + "accounts": [ + { + "name": "myAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "signerError", + "accounts": [ + { + "name": "myAccount", + "isMut": false, + "isSigner": true + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "HasOneAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "owner", + "type": "publicKey" + } + ] + } + } + ], + "errors": [ + { + "code": 300, + "name": "Hello", + "msg": "This is an error message clients will automatically display" + }, + { + "code": 423, + "name": "HelloNoMsg" + }, + { + "code": 424, + "name": "HelloNext" + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/escrow.json b/basics/anchorpy-main/tests/idls/escrow.json new file mode 100644 index 0000000..5d7c733 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/escrow.json @@ -0,0 +1,161 @@ +{ + "version": "0.0.0", + "name": "escrow", + "instructions": [ + { + "name": "initializeEscrow", + "accounts": [ + { + "name": "initializer", + "isMut": false, + "isSigner": true + }, + { + "name": "initializerDepositTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "initializerReceiveTokenAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "escrowAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "initializerAmount", + "type": "u64" + }, + { + "name": "takerAmount", + "type": "u64" + } + ] + }, + { + "name": "cancelEscrow", + "accounts": [ + { + "name": "initializer", + "isMut": false, + "isSigner": false + }, + { + "name": "pdaDepositTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "pdaAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "escrowAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "exchange", + "accounts": [ + { + "name": "taker", + "isMut": false, + "isSigner": true + }, + { + "name": "takerDepositTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "takerReceiveTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "pdaDepositTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "initializerReceiveTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "initializerMainAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "escrowAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "pdaAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "EscrowAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "initializerKey", + "type": "publicKey" + }, + { + "name": "initializerDepositTokenAccount", + "type": "publicKey" + }, + { + "name": "initializerReceiveTokenAccount", + "type": "publicKey" + }, + { + "name": "initializerAmount", + "type": "u64" + }, + { + "name": "takerAmount", + "type": "u64" + } + ] + } + } + ], + "metadata": { + "address": "38VPDKPpsXerxe7oWCXGQtm5usFGXrf65tbF3A7cs518" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/events.json b/basics/anchorpy-main/tests/idls/events.json new file mode 100644 index 0000000..3de103d --- /dev/null +++ b/basics/anchorpy-main/tests/idls/events.json @@ -0,0 +1,28 @@ +{ + "version": "0.0.0", + "name": "events", + "instructions": [ + { + "name": "initialize", + "accounts": [], + "args": [] + } + ], + "events": [ + { + "name": "MyEvent", + "fields": [ + { + "name": "data", + "type": "u64", + "index": false + }, + { + "name": "label", + "type": "string", + "index": true + } + ] + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/ido_pool.json b/basics/anchorpy-main/tests/idls/ido_pool.json new file mode 100644 index 0000000..430c4d2 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/ido_pool.json @@ -0,0 +1,397 @@ +{ + "version": "0.0.0", + "name": "ido_pool", + "instructions": [ + { + "name": "initializePool", + "accounts": [ + { + "name": "poolAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": false, + "isSigner": false + }, + { + "name": "usdcMint", + "isMut": false, + "isSigner": false + }, + { + "name": "poolWatermelon", + "isMut": true, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": false, + "isSigner": false + }, + { + "name": "distributionAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "creatorWatermelon", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "numIdoTokens", + "type": "u64" + }, + { + "name": "nonce", + "type": "u8" + }, + { + "name": "startIdoTs", + "type": "i64" + }, + { + "name": "endDepositsTs", + "type": "i64" + }, + { + "name": "endIdoTs", + "type": "i64" + } + ] + }, + { + "name": "exchangeUsdcForRedeemable", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": true, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userRedeemable", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "exchangeRedeemableForUsdc", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": true, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "userRedeemable", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "exchangeRedeemableForWatermelon", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "redeemableMint", + "isMut": true, + "isSigner": false + }, + { + "name": "poolWatermelon", + "isMut": true, + "isSigner": false + }, + { + "name": "userAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userWatermelon", + "isMut": true, + "isSigner": false + }, + { + "name": "userRedeemable", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "withdrawPoolUsdc", + "accounts": [ + { + "name": "poolAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "poolSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "poolUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "distributionAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "creatorUsdc", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "PoolAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "redeemableMint", + "type": "publicKey" + }, + { + "name": "poolWatermelon", + "type": "publicKey" + }, + { + "name": "watermelonMint", + "type": "publicKey" + }, + { + "name": "poolUsdc", + "type": "publicKey" + }, + { + "name": "distributionAuthority", + "type": "publicKey" + }, + { + "name": "nonce", + "type": "u8" + }, + { + "name": "numIdoTokens", + "type": "u64" + }, + { + "name": "startIdoTs", + "type": "i64" + }, + { + "name": "endDepositsTs", + "type": "i64" + }, + { + "name": "endIdoTs", + "type": "i64" + } + ] + } + } + ], + "errors": [ + { + "code": 300, + "name": "IdoFuture", + "msg": "IDO must start in the future" + }, + { + "code": 301, + "name": "SeqTimes", + "msg": "IDO times are non-sequential" + }, + { + "code": 302, + "name": "StartIdoTime", + "msg": "IDO has not started" + }, + { + "code": 303, + "name": "EndDepositsTime", + "msg": "Deposits period has ended" + }, + { + "code": 304, + "name": "EndIdoTime", + "msg": "IDO has ended" + }, + { + "code": 305, + "name": "IdoNotOver", + "msg": "IDO has not finished yet" + }, + { + "code": 306, + "name": "LowUsdc", + "msg": "Insufficient USDC" + }, + { + "code": 307, + "name": "LowRedeemable", + "msg": "Insufficient redeemable tokens" + }, + { + "code": 308, + "name": "UsdcNotEqRedeem", + "msg": "USDC total and redeemable total don't match" + }, + { + "code": 309, + "name": "InvalidNonce", + "msg": "Given nonce is invalid" + } + ], + "metadata": { + "address": "6iQsUPMA3k453npuvqbgARkSudA8YEtuDersUW7J5Ak1" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/jet.json b/basics/anchorpy-main/tests/idls/jet.json new file mode 100644 index 0000000..9269654 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/jet.json @@ -0,0 +1,1905 @@ +{ + "version": "0.0.0", + "name": "jet", + "instructions": [ + { + "name": "initMarket", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "quoteCurrency", + "type": "string" + }, + { + "name": "quoteTokenMint", + "type": "publicKey" + } + ] + }, + { + "name": "initReserve", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "feeNoteVault", + "isMut": true, + "isSigner": false + }, + { + "name": "dexSwapTokens", + "isMut": true, + "isSigner": false + }, + { + "name": "dexOpenOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "dexMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "dexProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "oraclePrice", + "isMut": false, + "isSigner": false + }, + { + "name": "oracleProduct", + "isMut": false, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "loanNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "quoteTokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": { + "defined": "InitReserveBumpSeeds" + } + }, + { + "name": "config", + "type": { + "defined": "ReserveConfig" + } + } + ] + }, + { + "name": "updateReserveConfig", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "newConfig", + "type": { + "defined": "ReserveConfig" + } + } + ] + }, + { + "name": "initDepositAccount", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": false, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": false, + "isSigner": false + }, + { + "name": "depositor", + "isMut": true, + "isSigner": true + }, + { + "name": "depositAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "initCollateralAccount", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "reserve", + "isMut": false, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "collateralAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "initLoanAccount", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "reserve", + "isMut": false, + "isSigner": false + }, + { + "name": "loanNoteMint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "loanAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "initObligation", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "borrower", + "isMut": true, + "isSigner": true + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "setMarketOwner", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "newOwner", + "type": "publicKey" + } + ] + }, + { + "name": "setMarketFlags", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "flags", + "type": "u64" + } + ] + }, + { + "name": "closeDepositAccount", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "depositor", + "isMut": true, + "isSigner": true + }, + { + "name": "depositAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "receiverAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "deposit", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "depositor", + "isMut": false, + "isSigner": true + }, + { + "name": "depositAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "depositSource", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "amount", + "type": { + "defined": "Amount" + } + } + ] + }, + { + "name": "withdraw", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "depositor", + "isMut": false, + "isSigner": true + }, + { + "name": "depositAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "withdrawAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "amount", + "type": { + "defined": "Amount" + } + } + ] + }, + { + "name": "depositCollateral", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "depositAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "collateralAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": { + "defined": "DepositCollateralBumpSeeds" + } + }, + { + "name": "amount", + "type": { + "defined": "Amount" + } + } + ] + }, + { + "name": "withdrawCollateral", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "depositAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "collateralAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": { + "defined": "WithdrawCollateralBumpSeeds" + } + }, + { + "name": "amount", + "type": { + "defined": "Amount" + } + } + ] + }, + { + "name": "borrow", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "loanNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "borrower", + "isMut": false, + "isSigner": true + }, + { + "name": "loanAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "receiverAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "amount", + "type": { + "defined": "Amount" + } + } + ] + }, + { + "name": "repay", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "loanNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "loanAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "payerAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": { + "defined": "Amount" + } + } + ] + }, + { + "name": "liquidate", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "collateralReserve", + "isMut": false, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "loanNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "loanAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "collateralAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "payerAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "receiverAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": { + "defined": "Amount" + } + }, + { + "name": "minCollateral", + "type": "u64" + } + ] + }, + { + "name": "mockLiquidateDex", + "accounts": [ + { + "name": "sourceMarket", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "openOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "requestQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "coinVault", + "isMut": true, + "isSigner": false + }, + { + "name": "pcVault", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultSigner", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "targetMarket", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "openOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "requestQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "coinVault", + "isMut": true, + "isSigner": false + }, + { + "name": "pcVault", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultSigner", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "toLiquidate", + "accounts": [ + { + "name": "market", + "isMut": false, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "obligation", + "isMut": true, + "isSigner": false + }, + { + "name": "loanReserve", + "isMut": true, + "isSigner": false + }, + { + "name": "loanReserveVault", + "isMut": true, + "isSigner": false + }, + { + "name": "loanNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "loanAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "collateralReserve", + "isMut": false, + "isSigner": false + }, + { + "name": "collateralReserveVault", + "isMut": true, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "collateralAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "dexSwapTokens", + "isMut": true, + "isSigner": false + }, + { + "name": "dexProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "refreshReserve", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "marketAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "reserve", + "isMut": true, + "isSigner": false + }, + { + "name": "feeNoteVault", + "isMut": true, + "isSigner": false + }, + { + "name": "depositNoteMint", + "isMut": true, + "isSigner": false + }, + { + "name": "pythOraclePrice", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "Market", + "type": { + "kind": "struct", + "fields": [ + { + "name": "version", + "type": "u32" + }, + { + "name": "quoteExponent", + "type": "i32" + }, + { + "name": "quoteCurrency", + "type": { + "array": [ + "u8", + 15 + ] + } + }, + { + "name": "authorityBumpSeed", + "type": { + "array": [ + "u8", + 1 + ] + } + }, + { + "name": "authoritySeed", + "type": "publicKey" + }, + { + "name": "marketAuthority", + "type": "publicKey" + }, + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "quoteTokenMint", + "type": "publicKey" + }, + { + "name": "flags", + "type": "u64" + }, + { + "name": "reserved", + "type": { + "array": [ + "u8", + 352 + ] + } + }, + { + "name": "reserves", + "type": { + "array": [ + "u8", + 12288 + ] + } + } + ] + } + }, + { + "name": "Obligation", + "type": { + "kind": "struct", + "fields": [ + { + "name": "version", + "type": "u32" + }, + { + "name": "reserved0", + "type": "u32" + }, + { + "name": "market", + "type": "publicKey" + }, + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "reserved1", + "type": { + "array": [ + "u8", + 184 + ] + } + }, + { + "name": "cached", + "type": { + "array": [ + "u8", + 256 + ] + } + }, + { + "name": "collateral", + "type": { + "array": [ + "u8", + 2048 + ] + } + }, + { + "name": "loans", + "type": { + "array": [ + "u8", + 2048 + ] + } + } + ] + } + }, + { + "name": "Reserve", + "type": { + "kind": "struct", + "fields": [ + { + "name": "version", + "type": "u16" + }, + { + "name": "index", + "type": "u16" + }, + { + "name": "exponent", + "type": "i32" + }, + { + "name": "market", + "type": "publicKey" + }, + { + "name": "pythOraclePrice", + "type": "publicKey" + }, + { + "name": "pythOracleProduct", + "type": "publicKey" + }, + { + "name": "tokenMint", + "type": "publicKey" + }, + { + "name": "depositNoteMint", + "type": "publicKey" + }, + { + "name": "loanNoteMint", + "type": "publicKey" + }, + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "feeNoteVault", + "type": "publicKey" + }, + { + "name": "dexSwapTokens", + "type": "publicKey" + }, + { + "name": "dexOpenOrders", + "type": "publicKey" + }, + { + "name": "dexMarket", + "type": "publicKey" + }, + { + "name": "reserved0", + "type": { + "array": [ + "u8", + 408 + ] + } + }, + { + "name": "config", + "type": { + "defined": "ReserveConfig" + } + }, + { + "name": "reserved1", + "type": { + "array": [ + "u8", + 704 + ] + } + }, + { + "name": "state", + "type": { + "array": [ + "u8", + 512 + ] + } + } + ] + } + } + ], + "types": [ + { + "name": "Amount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "units", + "type": { + "defined": "AmountUnits" + } + }, + { + "name": "value", + "type": "u64" + } + ] + } + }, + { + "name": "DepositCollateralBumpSeeds", + "type": { + "kind": "struct", + "fields": [ + { + "name": "collateralAccount", + "type": "u8" + }, + { + "name": "depositAccount", + "type": "u8" + } + ] + } + }, + { + "name": "InitReserveBumpSeeds", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vault", + "type": "u8" + }, + { + "name": "feeNoteVault", + "type": "u8" + }, + { + "name": "dexOpenOrders", + "type": "u8" + }, + { + "name": "dexSwapTokens", + "type": "u8" + }, + { + "name": "depositNoteMint", + "type": "u8" + }, + { + "name": "loanNoteMint", + "type": "u8" + } + ] + } + }, + { + "name": "ReserveConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "utilizationRate1", + "type": "u16" + }, + { + "name": "utilizationRate2", + "type": "u16" + }, + { + "name": "borrowRate0", + "type": "u16" + }, + { + "name": "borrowRate1", + "type": "u16" + }, + { + "name": "borrowRate2", + "type": "u16" + }, + { + "name": "borrowRate3", + "type": "u16" + }, + { + "name": "minCollateralRatio", + "type": "u16" + }, + { + "name": "liquidationPremium", + "type": "u16" + }, + { + "name": "manageFeeCollectionThreshold", + "type": "u64" + }, + { + "name": "manageFeeRate", + "type": "u16" + }, + { + "name": "loanOriginationFee", + "type": "u16" + }, + { + "name": "liquidationSlippage", + "type": "u16" + }, + { + "name": "reserved0", + "type": "u16" + }, + { + "name": "liquidationDexTradeMax", + "type": "u64" + }, + { + "name": "reserved1", + "type": { + "array": [ + "u8", + 24 + ] + } + } + ] + } + }, + { + "name": "WithdrawCollateralBumpSeeds", + "type": { + "kind": "struct", + "fields": [ + { + "name": "collateralAccount", + "type": "u8" + }, + { + "name": "depositAccount", + "type": "u8" + } + ] + } + }, + { + "name": "CacheInvalidError", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Expired", + "fields": [ + { + "name": "msg", + "type": "string" + } + ] + }, + { + "name": "TooNew", + "fields": [ + { + "name": "msg", + "type": "string" + } + ] + }, + { + "name": "Invalidated" + } + ] + } + }, + { + "name": "AmountUnits", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Tokens" + }, + { + "name": "DepositNotes" + }, + { + "name": "LoanNotes" + } + ] + } + }, + { + "name": "Rounding", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Up" + }, + { + "name": "Down" + } + ] + } + }, + { + "name": "DexSide", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Bid" + }, + { + "name": "Ask" + } + ] + } + }, + { + "name": "Side", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Collateral" + }, + { + "name": "Loan" + } + ] + } + }, + { + "name": "JobCompletion", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Partial" + }, + { + "name": "Full" + } + ] + } + } + ], + "events": [ + { + "name": "BorrowEvent", + "fields": [ + { + "name": "borrower", + "type": "publicKey", + "index": false + }, + { + "name": "reserve", + "type": "publicKey", + "index": false + }, + { + "name": "debt", + "type": "u64", + "index": false + } + ] + }, + { + "name": "DepositCollateralEvent", + "fields": [ + { + "name": "depositor", + "type": "publicKey", + "index": false + }, + { + "name": "reserve", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": { + "defined": "Amount" + }, + "index": false + } + ] + }, + { + "name": "LiquidateEvent", + "fields": [ + { + "name": "borrower", + "type": "publicKey", + "index": false + }, + { + "name": "debtReserve", + "type": "publicKey", + "index": false + }, + { + "name": "collateralReserve", + "type": "publicKey", + "index": false + }, + { + "name": "paidAmount", + "type": { + "defined": "Amount" + }, + "index": false + }, + { + "name": "collateralAmount", + "type": "u64", + "index": false + } + ] + }, + { + "name": "RepayEvent", + "fields": [ + { + "name": "borrower", + "type": "publicKey", + "index": false + }, + { + "name": "reserve", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": { + "defined": "Amount" + }, + "index": false + } + ] + }, + { + "name": "WithdrawCollateralEvent", + "fields": [ + { + "name": "depositor", + "type": "publicKey", + "index": false + }, + { + "name": "reserve", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": { + "defined": "Amount" + }, + "index": false + } + ] + } + ], + "errors": [ + { + "code": 300, + "name": "ArithmeticError", + "msg": "failed to perform some math operation safely" + }, + { + "code": 301, + "name": "InvalidOracle", + "msg": "oracle account provided is not valid" + }, + { + "code": 302, + "name": "NoFreeReserves", + "msg": "no free space left to add a new reserve in the market" + }, + { + "code": 303, + "name": "NoFreeObligation", + "msg": "no free space left to add the new loan or collateral in an obligation" + }, + { + "code": 304, + "name": "UnregisteredPosition", + "msg": "the obligation account doesn't have any record of the loan or collateral account" + }, + { + "code": 305, + "name": "InvalidOraclePrice", + "msg": "the oracle price account has an invalid price value" + }, + { + "code": 306, + "name": "InsufficientCollateral", + "msg": "there is not enough collateral deposited to borrow against" + }, + { + "code": 307, + "name": "SimultaneousDepositAndBorrow", + "msg": "cannot both deposit collateral to and borrow from the same reserve" + }, + { + "code": 308, + "name": "ObligationHealthy", + "msg": "cannot liquidate a healthy position" + }, + { + "code": 309, + "name": "ObligationUnhealthy", + "msg": "cannot perform an action that would leave the obligation unhealthy" + }, + { + "code": 310, + "name": "ExceptionalReserveState", + "msg": "reserve requires special action; call refresh_reserve until up to date" + }, + { + "code": 311, + "name": "InvalidAmountUnits", + "msg": "the units provided in the amount are not valid for the instruction" + }, + { + "code": 312, + "name": "InvalidDexMarketMints", + "msg": "the tokens in the DEX market don't match the reserve and lending market quote token" + }, + { + "code": 313, + "name": "InvalidMarketAuthority", + "msg": "the market authority provided doesn't match the market account" + }, + { + "code": 314, + "name": "InvalidLiquidationQuoteTokenAccount", + "msg": "the quote token account provided cannot be used for liquidations" + }, + { + "code": 315, + "name": "ObligationAccountMismatch", + "msg": "the obligation account doesn't have the collateral/loan registered" + }, + { + "code": 316, + "name": "UnknownInstruction", + "msg": "unknown instruction" + }, + { + "code": 317, + "name": "Disallowed", + "msg": "current conditions prevent an action from being performed" + }, + { + "code": 318, + "name": "LiquidationSwapSlipped", + "msg": "the actual slipped amount on the DEX trade exceeded the threshold configured" + }, + { + "code": 319, + "name": "CollateralValueTooSmall", + "msg": "the collateral value is too small for a DEX trade" + }, + { + "code": 320, + "name": "LiquidationLowCollateral", + "msg": "the collateral returned by the liquidation is smaller than requested" + }, + { + "code": 321, + "name": "NotSupported", + "msg": "this action is currently not supported by this version of the program" + }, + { + "code": 322, + "name": "MarketHalted", + "msg": "the market has currently halted this kind of operation" + }, + { + "code": 323, + "name": "InvalidParameter", + "msg": "a given parameter is not valid" + } + ], + "metadata": { + "address": "JPv1rCqrhagNNmJVM5J1he7msQ5ybtvE1nNuHpDHMNU" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/jet_auth.json b/basics/anchorpy-main/tests/idls/jet_auth.json new file mode 100644 index 0000000..337d251 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/jet_auth.json @@ -0,0 +1,99 @@ +{ + "version": "1.0.0", + "name": "jet_auth", + "instructions": [ + { + "name": "createUserAuth", + "accounts": [ + { + "name": "user", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "auth", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + }, + { + "name": "authenticate", + "accounts": [ + { + "name": "auth", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + } + ], + "accounts": [ + { + "name": "UserAuthentication", + "type": { + "kind": "struct", + "fields": [ + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "complete", + "type": "bool" + }, + { + "name": "allowed", + "type": "bool" + } + ] + } + } + ], + "events": [ + { + "name": "AuthAccountCreated", + "fields": [ + { + "name": "user", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "Authenticated", + "fields": [ + { + "name": "user", + "type": "publicKey", + "index": false + } + ] + } + ] +} diff --git a/basics/anchorpy-main/tests/idls/jet_rewards.json b/basics/anchorpy-main/tests/idls/jet_rewards.json new file mode 100644 index 0000000..6894a17 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/jet_rewards.json @@ -0,0 +1,1177 @@ +{ + "version": "1.0.0", + "name": "jet_rewards", + "constants": [ + { + "name": "AWARD", + "type": { + "defined": "&[u8]" + }, + "value": "b\"award\"" + }, + { + "name": "DISTRIBUTION", + "type": { + "defined": "&[u8]" + }, + "value": "b\"distribution\"" + }, + { + "name": "VAULT", + "type": { + "defined": "&[u8]" + }, + "value": "b\"vault\"" + } + ], + "instructions": [ + { + "name": "airdropCreate", + "accounts": [ + { + "name": "airdrop", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "rewardVault", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "tokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AirdropCreateParams" + } + } + ], + "returns": null + }, + { + "name": "airdropAddRecipients", + "accounts": [ + { + "name": "airdrop", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AirdropAddRecipientsParams" + } + } + ], + "returns": null + }, + { + "name": "airdropFinalize", + "accounts": [ + { + "name": "airdrop", + "isMut": true, + "isSigner": false + }, + { + "name": "rewardVault", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [], + "returns": null + }, + { + "name": "airdropClose", + "accounts": [ + { + "name": "airdrop", + "isMut": true, + "isSigner": false + }, + { + "name": "rewardVault", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "receiver", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenReceiver", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + }, + { + "name": "airdropClaim", + "accounts": [ + { + "name": "airdrop", + "isMut": true, + "isSigner": false + }, + { + "name": "rewardVault", + "isMut": true, + "isSigner": false + }, + { + "name": "recipient", + "isMut": false, + "isSigner": true + }, + { + "name": "receiver", + "isMut": true, + "isSigner": false + }, + { + "name": "stakePool", + "isMut": true, + "isSigner": false + }, + { + "name": "stakePoolVault", + "isMut": true, + "isSigner": false + }, + { + "name": "stakeAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "voterWeightRecord", + "isMut": true, + "isSigner": false + }, + { + "name": "maxVoterWeightRecord", + "isMut": true, + "isSigner": false + }, + { + "name": "stakingProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + }, + { + "name": "distributionCreate", + "accounts": [ + { + "name": "distribution", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "payerRent", + "isMut": true, + "isSigner": true + }, + { + "name": "payerTokenAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "payerTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "DistributionCreateParams" + } + } + ], + "returns": null + }, + { + "name": "distributionRelease", + "accounts": [ + { + "name": "distribution", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "targetAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + }, + { + "name": "distributionClose", + "accounts": [ + { + "name": "distribution", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "receiver", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + }, + { + "name": "awardCreate", + "accounts": [ + { + "name": "award", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenSource", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenSourceAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "payerRent", + "isMut": true, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AwardCreateParams" + } + } + ], + "returns": null + }, + { + "name": "awardRelease", + "accounts": [ + { + "name": "award", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "stakeAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "voterWeightRecord", + "isMut": true, + "isSigner": false + }, + { + "name": "maxVoterWeightRecord", + "isMut": true, + "isSigner": false + }, + { + "name": "stakePool", + "isMut": true, + "isSigner": false + }, + { + "name": "stakePoolVault", + "isMut": true, + "isSigner": false + }, + { + "name": "stakingProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + }, + { + "name": "awardClose", + "accounts": [ + { + "name": "award", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "receiver", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + }, + { + "name": "awardRevoke", + "accounts": [ + { + "name": "award", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "receiver", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenReceiver", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": null + } + ], + "accounts": [ + { + "name": "Airdrop", + "type": { + "kind": "struct", + "fields": [ + { + "name": "address", + "type": "publicKey" + }, + { + "name": "rewardVault", + "type": "publicKey" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "expireAt", + "type": "i64" + }, + { + "name": "stakePool", + "type": "publicKey" + }, + { + "name": "flags", + "type": "u64" + }, + { + "name": "shortDesc", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "longDesc", + "type": { + "array": ["u8", 255] + } + }, + { + "name": "vaultBump", + "type": { + "array": ["u8", 1] + } + }, + { + "name": "targetInfo", + "type": { + "array": ["u8", 400024] + } + } + ] + } + }, + { + "name": "Award", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "seed", + "type": { + "array": ["u8", 30] + } + }, + { + "name": "seedLen", + "type": "u8" + }, + { + "name": "bumpSeed", + "type": { + "array": ["u8", 1] + } + }, + { + "name": "stakeAccount", + "type": "publicKey" + }, + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "tokenDistribution", + "type": { + "defined": "TokenDistribution" + } + } + ] + } + }, + { + "name": "Distribution", + "type": { + "kind": "struct", + "fields": [ + { + "name": "address", + "type": "publicKey" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "seed", + "type": { + "array": ["u8", 30] + } + }, + { + "name": "seedLen", + "type": "u8" + }, + { + "name": "bumpSeed", + "type": { + "array": ["u8", 1] + } + }, + { + "name": "targetAccount", + "type": "publicKey" + }, + { + "name": "tokenDistribution", + "type": { + "defined": "TokenDistribution" + } + } + ] + } + } + ], + "types": [ + { + "name": "AirdropAddRecipientsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "startIndex", + "type": "u64" + }, + { + "name": "recipients", + "type": { + "vec": { + "defined": "AirdropRecipientParam" + } + } + } + ] + } + }, + { + "name": "AirdropRecipientParam", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "recipient", + "type": "publicKey" + } + ] + } + }, + { + "name": "AirdropCreateParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "expireAt", + "type": "i64" + }, + { + "name": "stakePool", + "type": "publicKey" + }, + { + "name": "shortDesc", + "type": "string" + }, + { + "name": "longDesc", + "type": "string" + }, + { + "name": "flags", + "type": "u64" + } + ] + } + }, + { + "name": "AwardCreateParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "seed", + "type": "string" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "stakeAccount", + "type": "publicKey" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "beginAt", + "type": "u64" + }, + { + "name": "endAt", + "type": "u64" + } + ] + } + }, + { + "name": "DistributionCreateParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "seed", + "type": "string" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "targetAccount", + "type": "publicKey" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "beginAt", + "type": "u64" + }, + { + "name": "endAt", + "type": "u64" + } + ] + } + }, + { + "name": "TokenDistribution", + "type": { + "kind": "struct", + "fields": [ + { + "name": "targetAmount", + "type": "u64" + }, + { + "name": "distributed", + "type": "u64" + }, + { + "name": "beginAt", + "type": "u64" + }, + { + "name": "endAt", + "type": "u64" + }, + { + "name": "kind", + "type": { + "defined": "DistributionKind" + } + } + ] + } + }, + { + "name": "DistributionKind", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Linear" + } + ] + } + } + ], + "events": [ + { + "name": "AirdropCreated", + "fields": [ + { + "name": "airdrop", + "type": "publicKey", + "index": false + }, + { + "name": "authority", + "type": "publicKey", + "index": false + }, + { + "name": "tokenMint", + "type": "publicKey", + "index": false + }, + { + "name": "params", + "type": { + "defined": "AirdropCreateParams" + }, + "index": false + } + ] + }, + { + "name": "AirdropRecipientsAdded", + "fields": [ + { + "name": "airdrop", + "type": "publicKey", + "index": false + }, + { + "name": "rewardAdditional", + "type": "u64", + "index": false + }, + { + "name": "rewardTotal", + "type": "u64", + "index": false + }, + { + "name": "recipientsAdditional", + "type": "u64", + "index": false + }, + { + "name": "recipientsTotal", + "type": "u64", + "index": false + }, + { + "name": "recipients", + "type": { + "vec": { + "defined": "AirdropRecipientParam" + } + }, + "index": false + } + ] + }, + { + "name": "AirdropFinalized", + "fields": [ + { + "name": "airdrop", + "type": "publicKey", + "index": false + }, + { + "name": "rewardTotal", + "type": "u64", + "index": false + }, + { + "name": "recipientsTotal", + "type": "u64", + "index": false + }, + { + "name": "vaultBalance", + "type": "u64", + "index": false + } + ] + }, + { + "name": "AirdropClaimed", + "fields": [ + { + "name": "airdrop", + "type": "publicKey", + "index": false + }, + { + "name": "recipient", + "type": "publicKey", + "index": false + }, + { + "name": "claimedAmount", + "type": "u64", + "index": false + }, + { + "name": "remainingAmount", + "type": "u64", + "index": false + }, + { + "name": "vaultBalance", + "type": "u64", + "index": false + } + ] + }, + { + "name": "AirdropClosed", + "fields": [ + { + "name": "airdrop", + "type": "publicKey", + "index": false + }, + { + "name": "vaultAmount", + "type": "u64", + "index": false + } + ] + }, + { + "name": "AwardCreated", + "fields": [ + { + "name": "award", + "type": "publicKey", + "index": false + }, + { + "name": "tokenMint", + "type": "publicKey", + "index": false + }, + { + "name": "params", + "type": { + "defined": "AwardCreateParams" + }, + "index": false + }, + { + "name": "distributionKind", + "type": { + "defined": "DistributionKind" + }, + "index": false + } + ] + }, + { + "name": "AwardReleased", + "fields": [ + { + "name": "award", + "type": "publicKey", + "index": false + }, + { + "name": "amountReleased", + "type": "u64", + "index": false + }, + { + "name": "totalReleased", + "type": "u64", + "index": false + }, + { + "name": "vaultBalance", + "type": "u64", + "index": false + } + ] + }, + { + "name": "AwardRevoked", + "fields": [ + { + "name": "award", + "type": "publicKey", + "index": false + }, + { + "name": "unreleasedAmount", + "type": "u64", + "index": false + }, + { + "name": "totalReleased", + "type": "u64", + "index": false + }, + { + "name": "vaultAmount", + "type": "u64", + "index": false + } + ] + }, + { + "name": "AwardClosed", + "fields": [ + { + "name": "award", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "DistributionCreated", + "fields": [ + { + "name": "distribution", + "type": "publicKey", + "index": false + }, + { + "name": "authority", + "type": "publicKey", + "index": false + }, + { + "name": "tokenMint", + "type": "publicKey", + "index": false + }, + { + "name": "params", + "type": { + "defined": "DistributionCreateParams" + }, + "index": false + }, + { + "name": "distributionKind", + "type": { + "defined": "DistributionKind" + }, + "index": false + } + ] + }, + { + "name": "DistributionReleased", + "fields": [ + { + "name": "distribution", + "type": "publicKey", + "index": false + }, + { + "name": "amountReleased", + "type": "u64", + "index": false + }, + { + "name": "totalDistributed", + "type": "u64", + "index": false + }, + { + "name": "vaultBalance", + "type": "u64", + "index": false + } + ] + }, + { + "name": "DistributionClosed", + "fields": [ + { + "name": "distribution", + "type": "publicKey", + "index": false + } + ] + } + ], + "errors": [ + { + "code": 13000, + "name": "RecipientNotFound" + }, + { + "code": 13001, + "name": "AddOutOfOrder" + }, + { + "code": 13002, + "name": "AirdropFinal" + }, + { + "code": 13003, + "name": "AirdropInsufficientRewardBalance" + }, + { + "code": 13004, + "name": "AirdropExpired" + }, + { + "code": 13005, + "name": "AirdropNotFinal" + }, + { + "code": 13006, + "name": "RecipientsNotSorted" + }, + { + "code": 13007, + "name": "DistributionNotEnded" + }, + { + "code": 13008, + "name": "AwardNotFullyVested" + } + ] +} diff --git a/basics/anchorpy-main/tests/idls/merkle_distributor.json b/basics/anchorpy-main/tests/idls/merkle_distributor.json new file mode 100644 index 0000000..d68ecc8 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/merkle_distributor.json @@ -0,0 +1,480 @@ +{ + "version": "0.0.0", + "name": "merkle_distributor", + "instructions": [ + { + "name": "newDistributor", + "accounts": [ + { + "name": "base", + "isMut": false, + "isSigner": true + }, + { + "name": "distributor", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "root", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "temporal", + "type": "publicKey" + } + ] + }, + { + "name": "closeDistributor", + "accounts": [ + { + "name": "base", + "isMut": false, + "isSigner": true + }, + { + "name": "distributor", + "isMut": true, + "isSigner": false + }, + { + "name": "distributorWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "receiver", + "isMut": false, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "walletBump", + "type": "u8" + } + ] + }, + { + "name": "claim", + "accounts": [ + { + "name": "distributor", + "isMut": true, + "isSigner": false + }, + { + "name": "claimStatus", + "isMut": true, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false + }, + { + "name": "to", + "isMut": true, + "isSigner": false + }, + { + "name": "temporal", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "index", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "claimantSecret", + "type": "publicKey" + }, + { + "name": "proof", + "type": { + "vec": { + "array": [ + "u8", + 32 + ] + } + } + } + ] + }, + { + "name": "claimCandy", + "accounts": [ + { + "name": "distributor", + "isMut": true, + "isSigner": false + }, + { + "name": "distributorWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "claimCount", + "isMut": true, + "isSigner": false + }, + { + "name": "temporal", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": false, + "isSigner": true + }, + { + "name": "candyMachineConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "candyMachine", + "isMut": true, + "isSigner": false + }, + { + "name": "candyMachineWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "candyMachineMint", + "isMut": true, + "isSigner": false + }, + { + "name": "candyMachineMetadata", + "isMut": true, + "isSigner": false + }, + { + "name": "candyMachineMasterEdition", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenMetadataProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "candyMachineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "walletBump", + "type": "u8" + }, + { + "name": "claimBump", + "type": "u8" + }, + { + "name": "index", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "claimantSecret", + "type": "publicKey" + }, + { + "name": "proof", + "type": { + "vec": { + "array": [ + "u8", + 32 + ] + } + } + } + ] + } + ], + "accounts": [ + { + "name": "MerkleDistributor", + "type": { + "kind": "struct", + "fields": [ + { + "name": "base", + "type": "publicKey" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "root", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "temporal", + "type": "publicKey" + } + ] + } + }, + { + "name": "ClaimStatus", + "type": { + "kind": "struct", + "fields": [ + { + "name": "isClaimed", + "type": "bool" + }, + { + "name": "claimant", + "type": "publicKey" + }, + { + "name": "claimedAt", + "type": "i64" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "ClaimCount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "count", + "type": "u64" + }, + { + "name": "claimant", + "type": "publicKey" + } + ] + } + }, + { + "name": "CandyMachine", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "wallet", + "type": "publicKey" + }, + { + "name": "tokenMint", + "type": { + "option": "publicKey" + } + }, + { + "name": "config", + "type": "publicKey" + }, + { + "name": "data", + "type": { + "defined": "CandyMachineData" + } + }, + { + "name": "itemsRedeemed", + "type": "u64" + }, + { + "name": "bump", + "type": "u8" + } + ] + } + } + ], + "types": [ + { + "name": "CandyMachineData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "price", + "type": "u64" + }, + { + "name": "itemsAvailable", + "type": "u64" + }, + { + "name": "goLiveDate", + "type": { + "option": "i64" + } + } + ] + } + } + ], + "events": [ + { + "name": "ClaimedEvent", + "fields": [ + { + "name": "index", + "type": "u64", + "index": false + }, + { + "name": "claimant", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + } + ] + } + ], + "errors": [ + { + "code": 300, + "name": "InvalidProof", + "msg": "Invalid Merkle proof." + }, + { + "code": 301, + "name": "DropAlreadyClaimed", + "msg": "Drop already claimed." + }, + { + "code": 302, + "name": "Unauthorized", + "msg": "Account is not authorized to execute this instruction" + }, + { + "code": 303, + "name": "OwnerMismatch", + "msg": "Token account owner did not match intended owner" + }, + { + "code": 304, + "name": "TemporalMismatch", + "msg": "Temporal signer did not match distributor" + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/multisig.json b/basics/anchorpy-main/tests/idls/multisig.json new file mode 100644 index 0000000..8b825b9 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/multisig.json @@ -0,0 +1,277 @@ +{ + "version": "0.0.0", + "name": "multisig", + "instructions": [ + { + "name": "createMultisig", + "accounts": [ + { + "name": "multisig", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "owners", + "type": { + "vec": "publicKey" + } + }, + { + "name": "threshold", + "type": "u64" + }, + { + "name": "nonce", + "type": "u8" + } + ] + }, + { + "name": "createTransaction", + "accounts": [ + { + "name": "multisig", + "isMut": false, + "isSigner": false + }, + { + "name": "transaction", + "isMut": true, + "isSigner": false + }, + { + "name": "proposer", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "pid", + "type": "publicKey" + }, + { + "name": "accs", + "type": { + "vec": { + "defined": "TransactionAccount" + } + } + }, + { + "name": "data", + "type": "bytes" + } + ] + }, + { + "name": "approve", + "accounts": [ + { + "name": "multisig", + "isMut": false, + "isSigner": false + }, + { + "name": "transaction", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "setOwners", + "accounts": [ + { + "name": "multisig", + "isMut": true, + "isSigner": false + }, + { + "name": "multisigSigner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "owners", + "type": { + "vec": "publicKey" + } + } + ] + }, + { + "name": "changeThreshold", + "accounts": [ + { + "name": "multisig", + "isMut": true, + "isSigner": false + }, + { + "name": "multisigSigner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "threshold", + "type": "u64" + } + ] + }, + { + "name": "executeTransaction", + "accounts": [ + { + "name": "multisig", + "isMut": false, + "isSigner": false + }, + { + "name": "multisigSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "transaction", + "isMut": true, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "Multisig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "owners", + "type": { + "vec": "publicKey" + } + }, + { + "name": "threshold", + "type": "u64" + }, + { + "name": "nonce", + "type": "u8" + } + ] + } + }, + { + "name": "Transaction", + "type": { + "kind": "struct", + "fields": [ + { + "name": "multisig", + "type": "publicKey" + }, + { + "name": "programId", + "type": "publicKey" + }, + { + "name": "accounts", + "type": { + "vec": { + "defined": "TransactionAccount" + } + } + }, + { + "name": "data", + "type": "bytes" + }, + { + "name": "signers", + "type": { + "vec": "bool" + } + }, + { + "name": "didExecute", + "type": "bool" + } + ] + } + } + ], + "types": [ + { + "name": "TransactionAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "isSigner", + "type": "bool" + }, + { + "name": "isWritable", + "type": "bool" + } + ] + } + } + ], + "errors": [ + { + "code": 300, + "name": "InvalidOwner", + "msg": "The given owner is not part of this multisig." + }, + { + "code": 301, + "name": "NotEnoughSigners", + "msg": "Not enough owners signed this transaction." + }, + { + "code": 302, + "name": "TransactionAlreadySigned", + "msg": "Cannot delete a transaction that has been signed by an owner." + }, + { + "code": 303, + "name": "Overflow", + "msg": "Overflow when adding." + }, + { + "code": 304, + "name": "UnableToDelete", + "msg": "Cannot delete a transaction the owner did not create." + }, + { + "code": 305, + "name": "AlreadyExecuted", + "msg": "The given transaction has already been executed." + }, + { + "code": 306, + "name": "InvalidThreshold", + "msg": "Threshold must be less than or equal to the number of owners." + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/puppet.json b/basics/anchorpy-main/tests/idls/puppet.json new file mode 100644 index 0000000..625b61e --- /dev/null +++ b/basics/anchorpy-main/tests/idls/puppet.json @@ -0,0 +1,55 @@ +{ + "version": "0.0.0", + "name": "puppet", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "puppet", + "isMut": true, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setData", + "accounts": [ + { + "name": "puppet", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "data", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "Puppet", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": "u64" + } + ] + } + } + ], + "metadata": { + "address": "61Q5bAAha3NF2gowifnZxaRttM1eyCs4Y3j9YjgMWrqb" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/puppet_master.json b/basics/anchorpy-main/tests/idls/puppet_master.json new file mode 100644 index 0000000..186d86e --- /dev/null +++ b/basics/anchorpy-main/tests/idls/puppet_master.json @@ -0,0 +1,30 @@ +{ + "version": "0.0.0", + "name": "puppet_master", + "instructions": [ + { + "name": "pullStrings", + "accounts": [ + { + "name": "puppet", + "isMut": true, + "isSigner": false + }, + { + "name": "puppetProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "data", + "type": "u64" + } + ] + } + ], + "metadata": { + "address": "3UDzsDD9WWPAgHASFHyFdqZz1hFmWpWVCZzLPZabDJxe" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/pyth.json b/basics/anchorpy-main/tests/idls/pyth.json new file mode 100644 index 0000000..0516aaf --- /dev/null +++ b/basics/anchorpy-main/tests/idls/pyth.json @@ -0,0 +1,99 @@ +{ + "version": "0.0.0", + "name": "pyth", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "price", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "price", + "type": "i64" + }, + { + "name": "expo", + "type": "i32" + }, + { + "name": "conf", + "type": "u64" + } + ] + }, + { + "name": "setPrice", + "accounts": [ + { + "name": "price", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "price", + "type": "i64" + } + ] + } + ], + "types": [ + { + "name": "PriceStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Unknown" + }, + { + "name": "Trading" + }, + { + "name": "Halted" + }, + { + "name": "Auction" + } + ] + } + }, + { + "name": "CorpAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "NoCorpAct" + } + ] + } + }, + { + "name": "PriceType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Unknown" + }, + { + "name": "Price" + }, + { + "name": "TWAP" + }, + { + "name": "Volatility" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/quarry_mine.json b/basics/anchorpy-main/tests/idls/quarry_mine.json new file mode 100644 index 0000000..0d5b494 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/quarry_mine.json @@ -0,0 +1,980 @@ +{ + "version": "0.0.0", + "name": "quarry_mine", + "instructions": [ + { + "name": "newRewarder", + "accounts": [ + { + "name": "base", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "unusedClock", + "isMut": false, + "isSigner": false + }, + { + "name": "mintWrapper", + "isMut": false, + "isSigner": false + }, + { + "name": "rewardsTokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "claimFeeTokenAccount", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "setPauseAuthority", + "accounts": [ + { + "name": "auth", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ] + }, + { + "name": "pauseAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "pause", + "accounts": [ + { + "name": "pauseAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "unpause", + "accounts": [ + { + "name": "pauseAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "transferAuthority", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "newAuthority", + "type": "publicKey" + } + ] + }, + { + "name": "acceptAuthority", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setAnnualRewards", + "accounts": [ + { + "name": "auth", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "newRate", + "type": "u64" + } + ] + }, + { + "name": "createQuarry", + "accounts": [ + { + "name": "quarry", + "isMut": true, + "isSigner": false + }, + { + "name": "auth", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ] + }, + { + "name": "tokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "unusedClock", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "setRewardsShare", + "accounts": [ + { + "name": "auth", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": true, + "isSigner": false + } + ] + }, + { + "name": "quarry", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "newShare", + "type": "u64" + } + ] + }, + { + "name": "setFamine", + "accounts": [ + { + "name": "auth", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rewarder", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "quarry", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "famineTs", + "type": "i64" + } + ] + }, + { + "name": "updateQuarryRewards", + "accounts": [ + { + "name": "quarry", + "isMut": true, + "isSigner": false + }, + { + "name": "rewarder", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "createMiner", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "miner", + "isMut": true, + "isSigner": false + }, + { + "name": "quarry", + "isMut": true, + "isSigner": false + }, + { + "name": "rewarder", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "tokenMint", + "isMut": false, + "isSigner": false + }, + { + "name": "minerVault", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "claimRewards", + "accounts": [ + { + "name": "mintWrapper", + "isMut": true, + "isSigner": false + }, + { + "name": "mintWrapperProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "minter", + "isMut": true, + "isSigner": false + }, + { + "name": "rewardsTokenMint", + "isMut": true, + "isSigner": false + }, + { + "name": "rewardsTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "claimFeeTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "stake", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "miner", + "isMut": true, + "isSigner": false + }, + { + "name": "quarry", + "isMut": true, + "isSigner": false + }, + { + "name": "unusedMinerVault", + "isMut": true, + "isSigner": false + }, + { + "name": "unusedTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rewarder", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "stakeTokens", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "miner", + "isMut": true, + "isSigner": false + }, + { + "name": "quarry", + "isMut": true, + "isSigner": false + }, + { + "name": "minerVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rewarder", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "withdrawTokens", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "miner", + "isMut": true, + "isSigner": false + }, + { + "name": "quarry", + "isMut": true, + "isSigner": false + }, + { + "name": "minerVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rewarder", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "extractFees", + "accounts": [ + { + "name": "rewarder", + "isMut": false, + "isSigner": false + }, + { + "name": "claimFeeTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "feeToTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "Rewarder", + "type": { + "kind": "struct", + "fields": [ + { + "name": "base", + "type": "publicKey" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "pendingAuthority", + "type": "publicKey" + }, + { + "name": "numQuarries", + "type": "u16" + }, + { + "name": "annualRewardsRate", + "type": "u64" + }, + { + "name": "totalRewardsShares", + "type": "u64" + }, + { + "name": "mintWrapper", + "type": "publicKey" + }, + { + "name": "rewardsTokenMint", + "type": "publicKey" + }, + { + "name": "claimFeeTokenAccount", + "type": "publicKey" + }, + { + "name": "maxClaimFeeMillibps", + "type": "u64" + }, + { + "name": "pauseAuthority", + "type": "publicKey" + }, + { + "name": "isPaused", + "type": "bool" + } + ] + } + }, + { + "name": "Quarry", + "type": { + "kind": "struct", + "fields": [ + { + "name": "rewarderKey", + "type": "publicKey" + }, + { + "name": "tokenMintKey", + "type": "publicKey" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "index", + "type": "u16" + }, + { + "name": "tokenMintDecimals", + "type": "u8" + }, + { + "name": "famineTs", + "type": "i64" + }, + { + "name": "lastUpdateTs", + "type": "i64" + }, + { + "name": "rewardsPerTokenStored", + "type": "u128" + }, + { + "name": "annualRewardsRate", + "type": "u64" + }, + { + "name": "rewardsShare", + "type": "u64" + }, + { + "name": "totalTokensDeposited", + "type": "u64" + }, + { + "name": "numMiners", + "type": "u64" + } + ] + } + }, + { + "name": "Miner", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quarryKey", + "type": "publicKey" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "tokenVaultKey", + "type": "publicKey" + }, + { + "name": "rewardsEarned", + "type": "u64" + }, + { + "name": "rewardsPerTokenPaid", + "type": "u128" + }, + { + "name": "balance", + "type": "u64" + }, + { + "name": "index", + "type": "u64" + } + ] + } + } + ], + "types": [ + { + "name": "StakeAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Stake" + }, + { + "name": "Withdraw" + } + ] + } + } + ], + "events": [ + { + "name": "NewRewarderEvent", + "fields": [ + { + "name": "authority", + "type": "publicKey", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "ClaimEvent", + "fields": [ + { + "name": "authority", + "type": "publicKey", + "index": false + }, + { + "name": "stakedToken", + "type": "publicKey", + "index": false + }, + { + "name": "rewardsToken", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "fees", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "StakeEvent", + "fields": [ + { + "name": "authority", + "type": "publicKey", + "index": false + }, + { + "name": "token", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "WithdrawEvent", + "fields": [ + { + "name": "authority", + "type": "publicKey", + "index": false + }, + { + "name": "token", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "RewarderAnnualRewardsUpdateEvent", + "fields": [ + { + "name": "previousRate", + "type": "u64", + "index": false + }, + { + "name": "newRate", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "MinerCreateEvent", + "fields": [ + { + "name": "authority", + "type": "publicKey", + "index": false + }, + { + "name": "quarry", + "type": "publicKey", + "index": false + }, + { + "name": "miner", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "QuarryCreateEvent", + "fields": [ + { + "name": "tokenMint", + "type": "publicKey", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "QuarryRewardsUpdateEvent", + "fields": [ + { + "name": "tokenMint", + "type": "publicKey", + "index": false + }, + { + "name": "annualRewardsRate", + "type": "u64", + "index": false + }, + { + "name": "rewardsShare", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + } + ], + "errors": [ + { + "code": 300, + "name": "Unauthorized", + "msg": "You are not authorized to perform this action." + }, + { + "code": 301, + "name": "InsufficientBalance", + "msg": "Insufficient staked balance for withdraw request." + }, + { + "code": 302, + "name": "PendingAuthorityNotSet", + "msg": "Pending authority not set" + }, + { + "code": 303, + "name": "InvalidRewardsShare", + "msg": "Invalid quarry rewards share" + }, + { + "code": 304, + "name": "InsufficientAllowance", + "msg": "Insufficient allowance." + }, + { + "code": 305, + "name": "NewVaultNotEmpty", + "msg": "New vault not empty." + }, + { + "code": 306, + "name": "NotEnoughTokens", + "msg": "Not enough tokens." + }, + { + "code": 307, + "name": "InvalidTimestamp", + "msg": "Invalid timestamp." + }, + { + "code": 308, + "name": "InvalidMaxClaimFee", + "msg": "Invalid max claim fee." + }, + { + "code": 309, + "name": "MaxAnnualRewardsRateExceeded", + "msg": "Max annual rewards rate exceeded." + }, + { + "code": 310, + "name": "Paused", + "msg": "Rewarder is paused." + }, + { + "code": 311, + "name": "UpperboundExceeded", + "msg": "Rewards earned exceeded quarry's upper bound." + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/sol_cerberus.json b/basics/anchorpy-main/tests/idls/sol_cerberus.json new file mode 100644 index 0000000..5c4cbdc --- /dev/null +++ b/basics/anchorpy-main/tests/idls/sol_cerberus.json @@ -0,0 +1,1464 @@ +{ + "version": "0.1.7", + "name": "sol_cerberus", + "instructions": [ + { + "name": "initializeApp", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "app", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "app" + }, + { + "kind": "arg", + "type": { + "defined": "AppData" + }, + "path": "app_data.id" + } + ] + } + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "appData", + "type": { + "defined": "AppData" + } + } + ] + }, + { + "name": "updateApp", + "accounts": [ + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "app", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "app" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "app.id" + } + ] + } + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "appData", + "type": { + "defined": "UpdateAppData" + } + } + ] + }, + { + "name": "deleteApp", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "app", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "app" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "app.id" + } + ] + } + }, + { + "name": "collector", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "addRule", + "accounts": [ + { + "name": "signer", + "isMut": true, + "isSigner": true + }, + { + "name": "rule", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "arg", + "type": { + "defined": "RuleData" + }, + "path": "rule_data.namespace" + }, + { + "kind": "arg", + "type": { + "defined": "RuleData" + }, + "path": "rule_data.role" + }, + { + "kind": "arg", + "type": { + "defined": "RuleData" + }, + "path": "rule_data.resource" + }, + { + "kind": "arg", + "type": { + "defined": "RuleData" + }, + "path": "rule_data.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "sol_cerberus_app.id" + } + ] + } + }, + { + "name": "solCerberusApp", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "app" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "sol_cerberus_app.id" + } + ] + } + }, + { + "name": "solCerberusRole", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusRule", + "isMut": false, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "sol_cerberus_rule.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Rule", + "path": "sol_cerberus_rule.app_id" + } + ] + } + }, + { + "name": "solCerberusRule2", + "isMut": false, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "sol_cerberus_rule2.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule2.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule2.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule2.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Rule", + "path": "sol_cerberus_rule2.app_id" + } + ] + } + }, + { + "name": "solCerberusToken", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusMetadata", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusSeed", + "isMut": true, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "seed" + }, + { + "kind": "account", + "type": "publicKey", + "path": "signer" + } + ] + } + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "ruleData", + "type": { + "defined": "RuleData" + } + } + ] + }, + { + "name": "deleteRule", + "accounts": [ + { + "name": "signer", + "isMut": true, + "isSigner": true + }, + { + "name": "rule", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "rule.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "rule.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "rule.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "rule.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "sol_cerberus_app.id" + } + ] + } + }, + { + "name": "solCerberusApp", + "isMut": false, + "isSigner": false + }, + { + "name": "solCerberusRole", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusRule", + "isMut": false, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "sol_cerberus_rule.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Rule", + "path": "sol_cerberus_rule.app_id" + } + ] + } + }, + { + "name": "solCerberusRule2", + "isMut": false, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "sol_cerberus_rule2.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule2.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule2.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule2.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Rule", + "path": "sol_cerberus_rule2.app_id" + } + ] + } + }, + { + "name": "solCerberusToken", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusMetadata", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusSeed", + "isMut": true, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "seed" + }, + { + "kind": "account", + "type": "publicKey", + "path": "signer" + } + ] + } + }, + { + "name": "collector", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "assignRole", + "accounts": [ + { + "name": "signer", + "isMut": true, + "isSigner": true + }, + { + "name": "role", + "isMut": true, + "isSigner": false + }, + { + "name": "solCerberusApp", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "app" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "sol_cerberus_app.id" + } + ] + } + }, + { + "name": "solCerberusRole", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusRule", + "isMut": false, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "sol_cerberus_rule.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Rule", + "path": "sol_cerberus_rule.app_id" + } + ] + } + }, + { + "name": "solCerberusToken", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusMetadata", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusSeed", + "isMut": true, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "seed" + }, + { + "kind": "account", + "type": "publicKey", + "path": "signer" + } + ] + } + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "assignRoleData", + "type": { + "defined": "AssignRoleData" + } + } + ] + }, + { + "name": "deleteAssignedRole", + "accounts": [ + { + "name": "signer", + "isMut": true, + "isSigner": true + }, + { + "name": "role", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "string", + "account": "Role", + "path": "role.role" + }, + { + "kind": "account", + "type": { + "option": "publicKey" + }, + "account": "Role", + "path": "role.address" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "sol_cerberus_app.id" + } + ] + } + }, + { + "name": "solCerberusApp", + "isMut": false, + "isSigner": false + }, + { + "name": "solCerberusRole", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusRule", + "isMut": false, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "sol_cerberus_rule.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Rule", + "path": "sol_cerberus_rule.app_id" + } + ] + } + }, + { + "name": "solCerberusToken", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusMetadata", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusSeed", + "isMut": true, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "seed" + }, + { + "kind": "account", + "type": "publicKey", + "path": "signer" + } + ] + } + }, + { + "name": "collector", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateCache", + "docs": [ + "* Updates either app.roles_updated_at or app.rules_updated_at fields, so clients\n * can keep track and cache roles & rules accordingly." + ], + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "app", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "app" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "app.id" + } + ] + }, + "relations": [ + "authority" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "cacheUpdated", + "type": "u8" + } + ] + }, + { + "name": "allowed", + "docs": [ + "* Checks if the current user is authorized to run the instruction,\n * throwing \"Unauthorized\" error otherwise." + ], + "accounts": [ + { + "name": "signer", + "isMut": true, + "isSigner": true + }, + { + "name": "solCerberusApp", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "app" + }, + { + "kind": "account", + "type": "publicKey", + "account": "App", + "path": "sol_cerberus_app.id" + } + ] + } + }, + { + "name": "solCerberusRule", + "isMut": false, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "u8", + "account": "Rule", + "path": "sol_cerberus_rule.namespace" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.role" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.resource" + }, + { + "kind": "account", + "type": "string", + "account": "Rule", + "path": "sol_cerberus_rule.permission" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Rule", + "path": "sol_cerberus_rule.app_id" + } + ] + } + }, + { + "name": "solCerberusRole", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusToken", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusMetadata", + "isMut": false, + "isSigner": false, + "isOptional": true + }, + { + "name": "solCerberusSeed", + "isMut": true, + "isSigner": false, + "isOptional": true, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "seed" + }, + { + "kind": "account", + "type": "publicKey", + "path": "signer" + } + ] + } + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "allowedRule", + "type": { + "defined": "AllowedRule" + } + } + ] + } + ], + "accounts": [ + { + "name": "App", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "publicKey" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "recovery", + "type": { + "option": "publicKey" + } + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "rolesUpdatedAt", + "type": "i64" + }, + { + "name": "rulesUpdatedAt", + "type": "i64" + }, + { + "name": "cached", + "type": "bool" + }, + { + "name": "fee", + "type": { + "option": "u64" + } + }, + { + "name": "class", + "type": "u8" + }, + { + "name": "expiresAt", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "Seed", + "type": { + "kind": "struct", + "fields": [ + { + "name": "initialized", + "type": "bool" + } + ] + } + }, + { + "name": "Role", + "type": { + "kind": "struct", + "fields": [ + { + "name": "appId", + "type": "publicKey" + }, + { + "name": "address", + "type": { + "option": "publicKey" + } + }, + { + "name": "role", + "type": "string" + }, + { + "name": "addressType", + "type": { + "defined": "AddressType" + } + }, + { + "name": "expiresAt", + "type": { + "option": "i64" + } + }, + { + "name": "bump", + "type": "u8" + } + ] + } + }, + { + "name": "Rule", + "type": { + "kind": "struct", + "fields": [ + { + "name": "appId", + "type": "publicKey" + }, + { + "name": "namespace", + "type": "u8" + }, + { + "name": "role", + "type": "string" + }, + { + "name": "resource", + "type": "string" + }, + { + "name": "permission", + "type": "string" + }, + { + "name": "expiresAt", + "type": { + "option": "i64" + } + }, + { + "name": "bump", + "type": "u8" + } + ] + } + } + ], + "types": [ + { + "name": "AllowedRule", + "type": { + "kind": "struct", + "fields": [ + { + "name": "appId", + "type": "publicKey" + }, + { + "name": "namespace", + "type": "u8" + }, + { + "name": "resource", + "type": "string" + }, + { + "name": "permission", + "type": "string" + } + ] + } + }, + { + "name": "AppData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "publicKey" + }, + { + "name": "recovery", + "type": { + "option": "publicKey" + } + }, + { + "name": "name", + "type": "string" + }, + { + "name": "cached", + "type": "bool" + } + ] + } + }, + { + "name": "UpdateAppData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "recovery", + "type": { + "option": "publicKey" + } + }, + { + "name": "name", + "type": "string" + }, + { + "name": "cached", + "type": "bool" + }, + { + "name": "fee", + "type": { + "option": "u64" + } + }, + { + "name": "class", + "type": "u8" + }, + { + "name": "expiresAt", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "AssignRoleData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "address", + "type": { + "option": "publicKey" + } + }, + { + "name": "role", + "type": "string" + }, + { + "name": "addressType", + "type": { + "defined": "AddressType" + } + }, + { + "name": "expiresAt", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "RuleData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "namespace", + "type": "u8" + }, + { + "name": "role", + "type": "string" + }, + { + "name": "resource", + "type": "string" + }, + { + "name": "permission", + "type": "string" + }, + { + "name": "expiresAt", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "Classes", + "docs": [ + "Classes:", + "0 => Trial (Apps with default fees)", + "1 => Free (Apps with no fees)" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Trial" + }, + { + "name": "Free" + } + ] + } + }, + { + "name": "CacheUpdated", + "docs": [ + "CacheUpdated:", + "0 => Roles (When roles change)", + "1 => Rules (When rules change)" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Roles" + }, + { + "name": "Rules" + } + ] + } + }, + { + "name": "AddressType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Wallet" + }, + { + "name": "Nft" + }, + { + "name": "Collection" + } + ] + } + }, + { + "name": "Namespaces", + "docs": [ + "Namespaces:", + "0 => Rule (Normal permissions)", + "1 => AssignRole (White list of roles that can be assigned by certain role)", + "2 => DeleteAssignRole (White list of roles that can be deleted by certain role)", + "3 => AddRuleNSRole (White list of namespaces and roles that can be created by certain role)", + "4 => AddRuleResourcePerm (White list of resources and permissions that can be created by certain role)", + "5 => DeleteRuleNSRole (White list of namespaces and roles that can be deleted by certain role)", + "6 => DeleteRuleResourcePerm (White list of resources and permissions that can be deleted by certain role)" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Rule" + }, + { + "name": "AssignRole" + }, + { + "name": "DeleteAssignRole" + }, + { + "name": "AddRuleNSRole" + }, + { + "name": "AddRuleResourcePerm" + }, + { + "name": "DeleteRuleNSRole" + }, + { + "name": "DeleteRuleResourcePerm" + } + ] + } + } + ], + "events": [ + { + "name": "AppChanged", + "fields": [ + { + "name": "time", + "type": "i64", + "index": false + }, + { + "name": "appId", + "type": "publicKey", + "index": true + }, + { + "name": "authority", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "RolesChanged", + "fields": [ + { + "name": "time", + "type": "i64", + "index": false + }, + { + "name": "appId", + "type": "publicKey", + "index": true + } + ] + }, + { + "name": "RulesChanged", + "fields": [ + { + "name": "time", + "type": "i64", + "index": false + }, + { + "name": "appId", + "type": "publicKey", + "index": true + } + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "UnauthorizedAuthorityUpdate", + "msg": "Only current Authority or Recovery accounts can update the App authority" + }, + { + "code": 6001, + "name": "InvalidRule", + "msg": "Role, Resource or Permission must be betwen 1 and 16 alphanumeric characters long" + }, + { + "code": 6002, + "name": "InvalidRole", + "msg": "Role must be between 1 and 16 alphanumeric characters long" + }, + { + "code": 6003, + "name": "StringTooShort", + "msg": "The provided string is too short" + }, + { + "code": 6004, + "name": "StringTooLong", + "msg": "The provided string is too long" + }, + { + "code": 6005, + "name": "Unauthorized", + "msg": "The user does not have enough privileges to perform this action" + }, + { + "code": 6006, + "name": "InvalidAppID", + "msg": "The Sol Cerberus APP ID does not match the one defined in the program" + }, + { + "code": 6007, + "name": "InvalidAddressType", + "msg": "Invalid address type, mus be either 'Wallet', 'Nft', 'Collection' or a wildcard '*'" + }, + { + "code": 6008, + "name": "InvalidNamespace", + "msg": "Invalid namespace, must be either an u8 number (0-255) or a wildcard '*'" + }, + { + "code": 6009, + "name": "MissingSolCerberusAppId", + "msg": "SOL_CERBERUS_APP_ID is missing on lib.rs" + }, + { + "code": 6010, + "name": "MissingSeedAccount", + "msg": "The Sol Cerberus Seed account is missing" + }, + { + "code": 6011, + "name": "UnauthorizedProgramAuthority", + "msg": "Only program authority can perform this action" + }, + { + "code": 6012, + "name": "InsufficientFunds", + "msg": "Insufficient funds for transaction" + } + ], + "metadata": { + "address": "SCERbrcgSPwgkrJ7j4TABr17dhYzdgiwPZUSSfFPt8x" + } +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/spl_token.json b/basics/anchorpy-main/tests/idls/spl_token.json new file mode 100644 index 0000000..773e470 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/spl_token.json @@ -0,0 +1,844 @@ +{ + "version": "3.3.0", + "name": "spl_token", + "instructions": [ + { + "name": "initializeMint", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "decimals", + "type": "u8" + }, + { + "name": "mintAuthority", + "type": "publicKey" + }, + { + "name": "freezeAuthority", + "type": { + "defined": "COption" + } + } + ] + }, + { + "name": "initializeAccount", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeMultisig", + "accounts": [ + { + "name": "multisig", + "isMut": true, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "m", + "type": "u8" + } + ] + }, + { + "name": "transfer", + "accounts": [ + { + "name": "source", + "isMut": true, + "isSigner": false + }, + { + "name": "destination", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "approve", + "accounts": [ + { + "name": "source", + "isMut": true, + "isSigner": false + }, + { + "name": "delegate", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "revoke", + "accounts": [ + { + "name": "source", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "setAuthority", + "accounts": [ + { + "name": "owned", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "signer", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "authorityType", + "type": { + "defined": "AuthorityType" + } + }, + { + "name": "newAuthority", + "type": { + "defined": "COption" + } + } + ] + }, + { + "name": "mintTo", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "burn", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "closeAccount", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "destination", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "freezeAccount", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "thawAccount", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "transferChecked", + "accounts": [ + { + "name": "source", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "destination", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + }, + { + "name": "approveChecked", + "accounts": [ + { + "name": "source", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "delegate", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + }, + { + "name": "mintToChecked", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + }, + { + "name": "burnChecked", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + }, + { + "name": "initializeAccount2", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "owner", + "type": "publicKey" + } + ] + }, + { + "name": "syncNative", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeAccount3", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "owner", + "type": "publicKey" + } + ] + }, + { + "name": "initializeMultisig2", + "accounts": [ + { + "name": "multisig", + "isMut": true, + "isSigner": false + }, + { + "name": "signer", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "m", + "type": "u8" + } + ] + }, + { + "name": "initializeMint2", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "decimals", + "type": "u8" + }, + { + "name": "mintAuthority", + "type": "publicKey" + }, + { + "name": "freezeAuthority", + "type": { + "defined": "COption" + } + } + ] + }, + { + "name": "getAccountDataSize", + "accounts": [ + { + "name": "mint", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeImmutableOwner", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "amountToUiAmount", + "accounts": [ + { + "name": "mint", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "uiAmountToAmount", + "accounts": [ + { + "name": "mint", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "uiAmount", + "type": { + "defined": "&'astr" + } + } + ] + } + ], + "accounts": [ + { + "name": "Mint", + "type": { + "kind": "struct", + "fields": [ + { + "name": "mintAuthority", + "type": { + "defined": "COption" + } + }, + { + "name": "supply", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + }, + { + "name": "isInitialized", + "type": "bool" + }, + { + "name": "freezeAuthority", + "type": { + "defined": "COption" + } + } + ] + } + }, + { + "name": "Account", + "type": { + "kind": "struct", + "fields": [ + { + "name": "mint", + "type": "publicKey" + }, + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "delegate", + "type": { + "defined": "COption" + } + }, + { + "name": "state", + "type": { + "defined": "AccountState" + } + }, + { + "name": "isNative", + "type": { + "defined": "COption" + } + }, + { + "name": "delegatedAmount", + "type": "u64" + }, + { + "name": "closeAuthority", + "type": { + "defined": "COption" + } + } + ] + } + }, + { + "name": "Multisig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "m", + "type": "u8" + }, + { + "name": "n", + "type": "u8" + }, + { + "name": "isInitialized", + "type": "bool" + }, + { + "name": "signers", + "type": { + "array": [ + "publicKey", + 11 + ] + } + } + ] + } + } + ], + "types": [ + { + "name": "AccountState", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Uninitialized" + }, + { + "name": "Initialized" + }, + { + "name": "Frozen" + } + ] + } + }, + { + "name": "AuthorityType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "MintTokens" + }, + { + "name": "FreezeAccount" + }, + { + "name": "AccountOwner" + }, + { + "name": "CloseAccount" + } + ] + } + } + ], + "errors": [ + { + "code": 0, + "name": "NotRentExempt", + "msg": "Lamport balance below rent-exempt threshold" + }, + { + "code": 1, + "name": "InsufficientFunds", + "msg": "Insufficient funds" + }, + { + "code": 2, + "name": "InvalidMint", + "msg": "Invalid Mint" + }, + { + "code": 3, + "name": "MintMismatch", + "msg": "Account not associated with this Mint" + }, + { + "code": 4, + "name": "OwnerMismatch", + "msg": "Owner does not match" + }, + { + "code": 5, + "name": "FixedSupply", + "msg": "Fixed supply" + }, + { + "code": 6, + "name": "AlreadyInUse", + "msg": "Already in use" + }, + { + "code": 7, + "name": "InvalidNumberOfProvidedSigners", + "msg": "Invalid number of provided signers" + }, + { + "code": 8, + "name": "InvalidNumberOfRequiredSigners", + "msg": "Invalid number of required signers" + }, + { + "code": 9, + "name": "UninitializedState", + "msg": "State is unititialized" + }, + { + "code": 10, + "name": "NativeNotSupported", + "msg": "Instruction does not support native tokens" + }, + { + "code": 11, + "name": "NonNativeHasBalance", + "msg": "Non-native account can only be closed if its balance is zero" + }, + { + "code": 12, + "name": "InvalidInstruction", + "msg": "Invalid instruction" + }, + { + "code": 13, + "name": "InvalidState", + "msg": "State is invalid for requested operation" + }, + { + "code": 14, + "name": "Overflow", + "msg": "Operation overflowed" + }, + { + "code": 15, + "name": "AuthorityTypeNotSupported", + "msg": "Account does not support specified authority type" + }, + { + "code": 16, + "name": "MintCannotFreeze", + "msg": "This token mint cannot freeze accounts" + }, + { + "code": 17, + "name": "AccountFrozen", + "msg": "Account is frozen" + }, + { + "code": 18, + "name": "MintDecimalsMismatch", + "msg": "The provided decimals value different from the Mint decimals" + }, + { + "code": 19, + "name": "NonNativeNotSupported", + "msg": "Instruction does not support non-native tokens" + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/swap.json b/basics/anchorpy-main/tests/idls/swap.json new file mode 100644 index 0000000..6ea31d0 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/swap.json @@ -0,0 +1,352 @@ +{ + "version": "0.0.0", + "name": "swap", + "instructions": [ + { + "name": "swap", + "accounts": [ + { + "name": "market", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "openOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "requestQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "orderPayerTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "coinVault", + "isMut": true, + "isSigner": false + }, + { + "name": "pcVault", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "coinWallet", + "isMut": true, + "isSigner": false + } + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "pcWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "dexProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "minExpectedSwapAmount", + "type": "u64" + } + ] + }, + { + "name": "swapTransitive", + "accounts": [ + { + "name": "from", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "openOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "requestQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "orderPayerTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "coinVault", + "isMut": true, + "isSigner": false + }, + { + "name": "pcVault", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "coinWallet", + "isMut": true, + "isSigner": false + } + ] + }, + { + "name": "to", + "accounts": [ + { + "name": "market", + "isMut": true, + "isSigner": false + }, + { + "name": "openOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "requestQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "orderPayerTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "coinVault", + "isMut": true, + "isSigner": false + }, + { + "name": "pcVault", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "coinWallet", + "isMut": true, + "isSigner": false + } + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "pcWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "dexProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "minExpectedSwapAmount", + "type": "u64" + } + ] + } + ], + "types": [ + { + "name": "Side", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Bid" + }, + { + "name": "Ask" + } + ] + } + } + ], + "events": [ + { + "name": "DidSwap", + "fields": [ + { + "name": "givenAmount", + "type": "u64", + "index": false + }, + { + "name": "minExpectedSwapAmount", + "type": "u64", + "index": false + }, + { + "name": "fromAmount", + "type": "u64", + "index": false + }, + { + "name": "toAmount", + "type": "u64", + "index": false + }, + { + "name": "spillAmount", + "type": "u64", + "index": false + }, + { + "name": "fromMint", + "type": "publicKey", + "index": false + }, + { + "name": "toMint", + "type": "publicKey", + "index": false + }, + { + "name": "quoteMint", + "type": "publicKey", + "index": false + }, + { + "name": "authority", + "type": "publicKey", + "index": false + } + ] + } + ], + "errors": [ + { + "code": 300, + "name": "SwapTokensCannotMatch", + "msg": "The tokens being swapped must have different mints" + }, + { + "code": 301, + "name": "SlippageExceeded", + "msg": "Slippage tolerance exceeded" + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/switchboard.json b/basics/anchorpy-main/tests/idls/switchboard.json new file mode 100644 index 0000000..c476c4a --- /dev/null +++ b/basics/anchorpy-main/tests/idls/switchboard.json @@ -0,0 +1 @@ +{"version": "0.1.0", "name": "switchboard_v2", "instructions": [{"name": "vaultTransfer", "accounts": [{"name": "state", "isMut": false, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}, {"name": "to", "isMut": true, "isSigner": false}, {"name": "vault", "isMut": true, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "VaultTransferParams"}}]}, {"name": "programInit", "accounts": [{"name": "state", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": false}, {"name": "tokenMint", "isMut": true, "isSigner": false}, {"name": "vault", "isMut": true, "isSigner": false}, {"name": "payer", "isMut": true, "isSigner": false}, {"name": "systemProgram", "isMut": false, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "ProgramInitParams"}}]}, {"name": "programConfig", "accounts": [{"name": "authority", "isMut": false, "isSigner": true}, {"name": "programState", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "ProgramConfigParams"}}]}, {"name": "aggregatorInit", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": false}, {"name": "queue", "isMut": false, "isSigner": false}, {"name": "authorWallet", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorInitParams"}}]}, {"name": "aggregatorLock", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": true, "isSigner": true}], "args": [{"name": "params", "type": {"defined": "AggregatorLockParams"}}]}, {"name": "aggregatorSetAuthority", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}, {"name": "newAuthority", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorSetAuthorityParams"}}]}, {"name": "aggregatorSetBatchSize", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}], "args": [{"name": "params", "type": {"defined": "AggregatorSetBatchSizeParams"}}]}, {"name": "aggregatorSetMinJobs", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}], "args": [{"name": "params", "type": {"defined": "AggregatorSetMinJobsParams"}}]}, {"name": "aggregatorSetMinOracles", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}], "args": [{"name": "params", "type": {"defined": "AggregatorSetMinOraclesParams"}}]}, {"name": "aggregatorSetVarianceThreshold", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}], "args": [{"name": "params", "type": {"defined": "AggregatorSetVarianceThresholdParams"}}]}, {"name": "aggregatorSetHistoryBuffer", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}, {"name": "buffer", "isMut": true, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorSetHistoryBufferParams"}}]}, {"name": "aggregatorSetQueue", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}, {"name": "queue", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorSetQueueParams"}}]}, {"name": "aggregatorAddJob", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}, {"name": "job", "isMut": true, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorAddJobParams"}}]}, {"name": "aggregatorRemoveJob", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}, {"name": "job", "isMut": true, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorRemoveJobParams"}}]}, {"name": "aggregatorOpenRound", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "lease", "isMut": true, "isSigner": false}, {"name": "oracleQueue", "isMut": true, "isSigner": false}, {"name": "queueAuthority", "isMut": false, "isSigner": false}, {"name": "permission", "isMut": true, "isSigner": false}, {"name": "escrow", "isMut": true, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}, {"name": "payoutWallet", "isMut": true, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}, {"name": "dataBuffer", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorOpenRoundParams"}}]}, {"name": "aggregatorSaveResult", "accounts": [{"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "oracle", "isMut": true, "isSigner": false}, {"name": "oracleAuthority", "isMut": false, "isSigner": true}, {"name": "oracleQueue", "isMut": false, "isSigner": false}, {"name": "queueAuthority", "isMut": false, "isSigner": false}, {"name": "feedPermission", "isMut": true, "isSigner": false}, {"name": "oraclePermission", "isMut": false, "isSigner": false}, {"name": "lease", "isMut": true, "isSigner": false}, {"name": "escrow", "isMut": true, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}, {"name": "historyBuffer", "isMut": true, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "AggregatorSaveResultParams"}}]}, {"name": "jobInit", "accounts": [{"name": "job", "isMut": true, "isSigner": false}, {"name": "authorWallet", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "JobInitParams"}}]}, {"name": "permissionInit", "accounts": [{"name": "permission", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": false}, {"name": "granter", "isMut": false, "isSigner": false}, {"name": "grantee", "isMut": false, "isSigner": false}, {"name": "payer", "isMut": true, "isSigner": true}, {"name": "systemProgram", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "PermissionInitParams"}}]}, {"name": "permissionSet", "accounts": [{"name": "permission", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}], "args": [{"name": "params", "type": {"defined": "PermissionSetParams"}}]}, {"name": "oracleQueueInit", "accounts": [{"name": "oracleQueue", "isMut": true, "isSigner": true}, {"name": "authority", "isMut": false, "isSigner": false}, {"name": "buffer", "isMut": true, "isSigner": false}, {"name": "payer", "isMut": true, "isSigner": false}, {"name": "systemProgram", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "OracleQueueInitParams"}}]}, {"name": "oracleQueueSetRewards", "accounts": [{"name": "queue", "isMut": true, "isSigner": false}, {"name": "authority", "isMut": false, "isSigner": true}], "args": [{"name": "params", "type": {"defined": "OracleQueueSetRewardsParams"}}]}, {"name": "oracleInit", "accounts": [{"name": "oracle", "isMut": true, "isSigner": false}, {"name": "oracleAuthority", "isMut": false, "isSigner": false}, {"name": "wallet", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}, {"name": "queue", "isMut": false, "isSigner": false}, {"name": "payer", "isMut": false, "isSigner": false}, {"name": "systemProgram", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "OracleInitParams"}}]}, {"name": "oracleHeartbeat", "accounts": [{"name": "oracle", "isMut": true, "isSigner": false}, {"name": "oracleAuthority", "isMut": false, "isSigner": true}, {"name": "tokenAccount", "isMut": false, "isSigner": false}, {"name": "gcOracle", "isMut": true, "isSigner": false}, {"name": "oracleQueue", "isMut": true, "isSigner": false}, {"name": "permission", "isMut": false, "isSigner": false}, {"name": "dataBuffer", "isMut": true, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "OracleHeartbeatParams"}}]}, {"name": "oracleWithdraw", "accounts": [{"name": "oracle", "isMut": true, "isSigner": false}, {"name": "oracleAuthority", "isMut": false, "isSigner": true}, {"name": "tokenAccount", "isMut": true, "isSigner": false}, {"name": "withdrawAccount", "isMut": true, "isSigner": false}, {"name": "oracleQueue", "isMut": true, "isSigner": false}, {"name": "permission", "isMut": true, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}, {"name": "payer", "isMut": true, "isSigner": true}, {"name": "systemProgram", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "OracleWithdrawParams"}}]}, {"name": "leaseInit", "accounts": [{"name": "lease", "isMut": true, "isSigner": false}, {"name": "queue", "isMut": true, "isSigner": false}, {"name": "aggregator", "isMut": false, "isSigner": false}, {"name": "funder", "isMut": true, "isSigner": false}, {"name": "payer", "isMut": true, "isSigner": true}, {"name": "systemProgram", "isMut": false, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}, {"name": "owner", "isMut": true, "isSigner": true}, {"name": "escrow", "isMut": true, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "LeaseInitParams"}}]}, {"name": "leaseExtend", "accounts": [{"name": "lease", "isMut": true, "isSigner": false}, {"name": "aggregator", "isMut": false, "isSigner": false}, {"name": "queue", "isMut": false, "isSigner": false}, {"name": "funder", "isMut": true, "isSigner": false}, {"name": "owner", "isMut": true, "isSigner": true}, {"name": "escrow", "isMut": true, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "LeaseExtendParams"}}]}, {"name": "leaseWithdraw", "accounts": [{"name": "lease", "isMut": true, "isSigner": false}, {"name": "escrow", "isMut": true, "isSigner": false}, {"name": "aggregator", "isMut": false, "isSigner": false}, {"name": "queue", "isMut": false, "isSigner": false}, {"name": "withdrawAuthority", "isMut": false, "isSigner": true}, {"name": "withdrawAccount", "isMut": true, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "LeaseWithdrawParams"}}]}, {"name": "crankInit", "accounts": [{"name": "crank", "isMut": true, "isSigner": true}, {"name": "queue", "isMut": false, "isSigner": false}, {"name": "buffer", "isMut": true, "isSigner": false}, {"name": "payer", "isMut": true, "isSigner": false}, {"name": "systemProgram", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "CrankInitParams"}}]}, {"name": "crankPush", "accounts": [{"name": "crank", "isMut": true, "isSigner": false}, {"name": "aggregator", "isMut": true, "isSigner": false}, {"name": "oracleQueue", "isMut": true, "isSigner": false}, {"name": "queueAuthority", "isMut": false, "isSigner": false}, {"name": "permission", "isMut": false, "isSigner": false}, {"name": "lease", "isMut": true, "isSigner": false}, {"name": "escrow", "isMut": true, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}, {"name": "dataBuffer", "isMut": true, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "CrankPushParams"}}]}, {"name": "crankPop", "accounts": [{"name": "crank", "isMut": true, "isSigner": false}, {"name": "oracleQueue", "isMut": true, "isSigner": false}, {"name": "queueAuthority", "isMut": false, "isSigner": false}, {"name": "programState", "isMut": false, "isSigner": false}, {"name": "payoutWallet", "isMut": true, "isSigner": false}, {"name": "tokenProgram", "isMut": false, "isSigner": false}, {"name": "crankDataBuffer", "isMut": true, "isSigner": false}, {"name": "queueDataBuffer", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "CrankPopParams"}}]}, {"name": "ecvrfVerify", "accounts": [{"name": "randomnessProducer", "isMut": false, "isSigner": false}], "args": [{"name": "params", "type": {"defined": "EcvrfVerifyParams"}}]}], "accounts": [{"name": "SbState", "type": {"kind": "struct", "fields": [{"name": "authority", "type": "publicKey"}, {"name": "tokenMint", "type": "publicKey"}, {"name": "tokenVault", "type": "publicKey"}, {"name": "ebuf", "type": {"array": ["u8", 1024]}}]}}, {"name": "AggregatorAccountData", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "metadata", "type": {"array": ["u8", 128]}}, {"name": "authorWallet", "type": "publicKey"}, {"name": "queuePubkey", "type": "publicKey"}, {"name": "oracleRequestBatchSize", "type": "u32"}, {"name": "minOracleResults", "type": "u32"}, {"name": "minJobResults", "type": "u32"}, {"name": "minUpdateDelaySeconds", "type": "u32"}, {"name": "startAfter", "type": "i64"}, {"name": "varianceThreshold", "type": {"defined": "SwitchboardDecimal"}}, {"name": "forceReportPeriod", "type": "i64"}, {"name": "expiration", "type": "i64"}, {"name": "consecutiveFailureCount", "type": "u64"}, {"name": "nextAllowedUpdateTime", "type": "i64"}, {"name": "isLocked", "type": "bool"}, {"name": "crankPubkey", "type": "publicKey"}, {"name": "latestConfirmedRound", "type": {"defined": "AggregatorRound"}}, {"name": "currentRound", "type": {"defined": "AggregatorRound"}}, {"name": "jobPubkeysData", "type": {"array": ["publicKey", 16]}}, {"name": "jobHashes", "type": {"array": [{"defined": "Hash"}, 16]}}, {"name": "jobPubkeysSize", "type": "u32"}, {"name": "jobsChecksum", "type": {"array": ["u8", 32]}}, {"name": "authority", "type": "publicKey"}, {"name": "historyBuffer", "type": "publicKey"}, {"name": "ebuf", "type": {"array": ["u8", 192]}}]}}, {"name": "PermissionAccountData", "type": {"kind": "struct", "fields": [{"name": "authority", "type": "publicKey"}, {"name": "permissions", "type": "u32"}, {"name": "granter", "type": "publicKey"}, {"name": "grantee", "type": "publicKey"}, {"name": "expiration", "type": "i64"}, {"name": "ebuf", "type": {"array": ["u8", 256]}}]}}, {"name": "LeaseAccountData", "type": {"kind": "struct", "fields": [{"name": "escrow", "type": "publicKey"}, {"name": "queue", "type": "publicKey"}, {"name": "aggregator", "type": "publicKey"}, {"name": "tokenProgram", "type": "publicKey"}, {"name": "isActive", "type": "bool"}, {"name": "crankRowCount", "type": "u32"}, {"name": "createdAt", "type": "i64"}, {"name": "updateCount", "type": "u128"}, {"name": "withdrawAuthority", "type": "publicKey"}, {"name": "ebuf", "type": {"array": ["u8", 256]}}]}}, {"name": "OracleQueueAccountData", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "metadata", "type": {"array": ["u8", 64]}}, {"name": "authority", "type": "publicKey"}, {"name": "oracleTimeout", "type": "u32"}, {"name": "reward", "type": "u64"}, {"name": "minStake", "type": "u64"}, {"name": "slashingEnabled", "type": "bool"}, {"name": "varianceToleranceMultiplier", "type": {"defined": "SwitchboardDecimal"}}, {"name": "feedProbationPeriod", "type": "u32"}, {"name": "currIdx", "type": "u32"}, {"name": "size", "type": "u32"}, {"name": "gcIdx", "type": "u32"}, {"name": "consecutiveFeedFailureLimit", "type": "u64"}, {"name": "consecutiveOracleFailureLimit", "type": "u64"}, {"name": "unpermissionedFeedsEnabled", "type": "bool"}, {"name": "ebuf", "type": {"array": ["u8", 1023]}}, {"name": "maxSize", "type": "u32"}, {"name": "dataBuffer", "type": "publicKey"}]}}, {"name": "CrankAccountData", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "metadata", "type": {"array": ["u8", 64]}}, {"name": "queuePubkey", "type": "publicKey"}, {"name": "pqSize", "type": "u32"}, {"name": "maxRows", "type": "u32"}, {"name": "jitterModifier", "type": "u8"}, {"name": "ebuf", "type": {"array": ["u8", 255]}}, {"name": "dataBuffer", "type": "publicKey"}]}}, {"name": "VrfAccountData", "type": {"kind": "struct", "fields": [{"name": "counter", "type": "u128"}, {"name": "latestFinalizedRound", "type": {"defined": "VrfRound"}}, {"name": "currentRound", "type": {"defined": "VrfRound"}}, {"name": "ebuf", "type": {"array": ["u8", 255]}}]}}, {"name": "OracleAccountData", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "metadata", "type": {"array": ["u8", 128]}}, {"name": "oracleAuthority", "type": "publicKey"}, {"name": "lastHeartbeat", "type": "i64"}, {"name": "numInUse", "type": "u32"}, {"name": "tokenAccount", "type": "publicKey"}, {"name": "queuePubkey", "type": "publicKey"}, {"name": "metrics", "type": {"defined": "OracleMetrics"}}, {"name": "ebuf", "type": {"array": ["u8", 256]}}]}}, {"name": "JobAccountData", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "metadata", "type": {"array": ["u8", 64]}}, {"name": "authorWallet", "type": "publicKey"}, {"name": "expiration", "type": "i64"}, {"name": "hash", "type": {"array": ["u8", 32]}}, {"name": "data", "type": "bytes"}, {"name": "referenceCount", "type": "u32"}]}}], "types": [{"name": "AggregatorAddJobParams", "type": {"kind": "struct", "fields": []}}, {"name": "AggregatorInitParams", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "metadata", "type": {"array": ["u8", 128]}}, {"name": "batchSize", "type": "u32"}, {"name": "minOracleResults", "type": "u32"}, {"name": "minJobResults", "type": "u32"}, {"name": "minUpdateDelaySeconds", "type": "u32"}, {"name": "startAfter", "type": "i64"}, {"name": "varianceThreshold", "type": {"defined": "BorshDecimal"}}, {"name": "forceReportPeriod", "type": "i64"}, {"name": "expiration", "type": "i64"}, {"name": "stateBump", "type": "u8"}]}}, {"name": "AggregatorLockParams", "type": {"kind": "struct", "fields": []}}, {"name": "AggregatorOpenRoundParams", "type": {"kind": "struct", "fields": [{"name": "stateBump", "type": "u8"}, {"name": "leaseBump", "type": "u8"}, {"name": "permissionBump", "type": "u8"}, {"name": "jitter", "type": "u8"}]}}, {"name": "AggregatorRemoveJobParams", "type": {"kind": "struct", "fields": [{"name": "jobIdx", "type": "u32"}]}}, {"name": "AggregatorSaveResultParams", "type": {"kind": "struct", "fields": [{"name": "oracleIdx", "type": "u32"}, {"name": "error", "type": "bool"}, {"name": "value", "type": {"defined": "BorshDecimal"}}, {"name": "jobsChecksum", "type": {"array": ["u8", 32]}}, {"name": "minResponse", "type": {"defined": "BorshDecimal"}}, {"name": "maxResponse", "type": {"defined": "BorshDecimal"}}, {"name": "feedPermissionBump", "type": "u8"}, {"name": "oraclePermissionBump", "type": "u8"}, {"name": "leaseBump", "type": "u8"}, {"name": "stateBump", "type": "u8"}]}}, {"name": "AggregatorSetAuthorityParams", "type": {"kind": "struct", "fields": []}}, {"name": "AggregatorSetBatchSizeParams", "type": {"kind": "struct", "fields": [{"name": "batchSize", "type": "u32"}]}}, {"name": "AggregatorSetHistoryBufferParams", "type": {"kind": "struct", "fields": []}}, {"name": "AggregatorSetMinJobsParams", "type": {"kind": "struct", "fields": [{"name": "minJobResults", "type": "u32"}]}}, {"name": "AggregatorSetMinOraclesParams", "type": {"kind": "struct", "fields": [{"name": "minOracleResults", "type": "u32"}]}}, {"name": "AggregatorSetQueueParams", "type": {"kind": "struct", "fields": []}}, {"name": "AggregatorSetVarianceThresholdParams", "type": {"kind": "struct", "fields": [{"name": "varianceThreshold", "type": {"defined": "BorshDecimal"}}]}}, {"name": "CrankInitParams", "type": {"kind": "struct", "fields": [{"name": "name", "type": "bytes"}, {"name": "metadata", "type": "bytes"}, {"name": "crankSize", "type": "u32"}]}}, {"name": "CrankPopParams", "type": {"kind": "struct", "fields": [{"name": "stateBump", "type": "u8"}, {"name": "leaseBumps", "type": "bytes"}, {"name": "permissionBumps", "type": "bytes"}, {"name": "nonce", "type": {"option": "u32"}}, {"name": "failOpenOnAccountMismatch", "type": {"option": "bool"}}]}}, {"name": "CrankPushParams", "type": {"kind": "struct", "fields": [{"name": "stateBump", "type": "u8"}, {"name": "permissionBump", "type": "u8"}]}}, {"name": "EcvrfVerifyParams", "type": {"kind": "struct", "fields": [{"name": "proof", "type": "bytes"}, {"name": "alpha", "type": "bytes"}]}}, {"name": "JobInitParams", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "expiration", "type": "i64"}, {"name": "stateBump", "type": "u8"}, {"name": "data", "type": "bytes"}]}}, {"name": "LeaseExtendParams", "type": {"kind": "struct", "fields": [{"name": "loadAmount", "type": "u64"}, {"name": "leaseBump", "type": "u8"}, {"name": "stateBump", "type": "u8"}]}}, {"name": "LeaseInitParams", "type": {"kind": "struct", "fields": [{"name": "loadAmount", "type": "u64"}, {"name": "withdrawAuthority", "type": "publicKey"}, {"name": "leaseBump", "type": "u8"}, {"name": "stateBump", "type": "u8"}]}}, {"name": "LeaseWithdrawParams", "type": {"kind": "struct", "fields": [{"name": "stateBump", "type": "u8"}, {"name": "leaseBump", "type": "u8"}, {"name": "amount", "type": "u64"}]}}, {"name": "OracleHeartbeatParams", "type": {"kind": "struct", "fields": [{"name": "permissionBump", "type": "u8"}]}}, {"name": "OracleInitParams", "type": {"kind": "struct", "fields": [{"name": "name", "type": "bytes"}, {"name": "metadata", "type": "bytes"}, {"name": "stateBump", "type": "u8"}, {"name": "oracleBump", "type": "u8"}]}}, {"name": "OracleQueueInitParams", "type": {"kind": "struct", "fields": [{"name": "name", "type": {"array": ["u8", 32]}}, {"name": "metadata", "type": {"array": ["u8", 64]}}, {"name": "reward", "type": "u64"}, {"name": "minStake", "type": "u64"}, {"name": "feedProbationPeriod", "type": "u32"}, {"name": "oracleTimeout", "type": "u32"}, {"name": "slashingEnabled", "type": "bool"}, {"name": "varianceToleranceMultiplier", "type": {"defined": "BorshDecimal"}}, {"name": "consecutiveFeedFailureLimit", "type": "u64"}, {"name": "consecutiveOracleFailureLimit", "type": "u64"}, {"name": "queueSize", "type": "u32"}, {"name": "unpermissionedFeeds", "type": "bool"}]}}, {"name": "OracleQueueSetRewardsParams", "type": {"kind": "struct", "fields": [{"name": "rewards", "type": "u64"}]}}, {"name": "OracleWithdrawParams", "type": {"kind": "struct", "fields": [{"name": "stateBump", "type": "u8"}, {"name": "permissionBump", "type": "u8"}, {"name": "amount", "type": "u64"}]}}, {"name": "PermissionInitParams", "type": {"kind": "struct", "fields": [{"name": "permissionBump", "type": "u8"}]}}, {"name": "PermissionSetParams", "type": {"kind": "struct", "fields": [{"name": "permission", "type": {"defined": "SwitchboardPermission"}}, {"name": "enable", "type": "bool"}]}}, {"name": "ProgramConfigParams", "type": {"kind": "struct", "fields": [{"name": "token", "type": "publicKey"}, {"name": "bump", "type": "u8"}]}}, {"name": "ProgramInitParams", "type": {"kind": "struct", "fields": [{"name": "stateBump", "type": "u8"}]}}, {"name": "Hash", "type": {"kind": "struct", "fields": [{"name": "data", "type": {"array": ["u8", 32]}}]}}, {"name": "AggregatorRound", "type": {"kind": "struct", "fields": [{"name": "numSuccess", "type": "u32"}, {"name": "numError", "type": "u32"}, {"name": "isClosed", "type": "bool"}, {"name": "roundOpenSlot", "type": "u64"}, {"name": "roundOpenTimestamp", "type": "i64"}, {"name": "result", "type": {"defined": "SwitchboardDecimal"}}, {"name": "stdDeviation", "type": {"defined": "SwitchboardDecimal"}}, {"name": "minResponse", "type": {"defined": "SwitchboardDecimal"}}, {"name": "maxResponse", "type": {"defined": "SwitchboardDecimal"}}, {"name": "oraclePubkeysData", "type": {"array": ["publicKey", 16]}}, {"name": "mediansData", "type": {"array": [{"defined": "SwitchboardDecimal"}, 16]}}, {"name": "currentPayout", "type": {"array": ["i64", 16]}}, {"name": "mediansFulfilled", "type": {"array": ["bool", 16]}}, {"name": "errorsFulfilled", "type": {"array": ["bool", 16]}}]}}, {"name": "AggregatorHistoryRow", "type": {"kind": "struct", "fields": [{"name": "timestamp", "type": "i64"}, {"name": "value", "type": {"defined": "SwitchboardDecimal"}}]}}, {"name": "SwitchboardDecimal", "type": {"kind": "struct", "fields": [{"name": "mantissa", "type": "i128"}, {"name": "scale", "type": "u32"}]}}, {"name": "VrfRound", "type": {"kind": "struct", "fields": [{"name": "vrfProducer", "type": "publicKey"}, {"name": "reprProof", "type": {"array": ["u8", 224]}}, {"name": "proof", "type": {"array": ["u8", 80]}}, {"name": "alpha", "type": {"array": ["u8", 64]}}, {"name": "alphaLen", "type": "u32"}, {"name": "stage", "type": "u32"}, {"name": "ebuf", "type": {"array": ["u8", 255]}}]}}, {"name": "CrankRow", "type": {"kind": "struct", "fields": [{"name": "pubkey", "type": "publicKey"}, {"name": "nextTimestamp", "type": "i64"}]}}, {"name": "OracleMetrics", "type": {"kind": "struct", "fields": [{"name": "consecutiveSuccess", "type": "u64"}, {"name": "consecutiveError", "type": "u64"}, {"name": "consecutiveDisagreement", "type": "u64"}, {"name": "consecutiveLateResponse", "type": "u64"}, {"name": "consecutiveFailure", "type": "u64"}, {"name": "totalSuccess", "type": "u128"}, {"name": "totalError", "type": "u128"}, {"name": "totalDisagreement", "type": "u128"}, {"name": "totalLateResponse", "type": "u128"}]}}, {"name": "BorshDecimal", "type": {"kind": "struct", "fields": [{"name": "mantissa", "type": "i128"}, {"name": "scale", "type": "u32"}]}}, {"name": "VaultTransferParams", "type": {"kind": "struct", "fields": [{"name": "stateBump", "type": "u8"}, {"name": "amount", "type": "u64"}]}}, {"name": "SwitchboardPermission", "type": {"kind": "enum", "variants": [{"name": "PermitOracleHeartbeat"}, {"name": "PermitOracleQueueUsage"}]}}, {"name": "OracleResponseType", "type": {"kind": "enum", "variants": [{"name": "TypeSuccess"}, {"name": "TypeError"}, {"name": "TypeDisagreement"}, {"name": "TypeNoResponse"}]}}, {"name": "Error", "type": {"kind": "enum", "variants": [{"name": "InvalidPublicKey"}, {"name": "SerializationError", "fields": [{"defined": "bincode::Error"}]}, {"name": "DeserializationError", "fields": [{"defined": "bincode::Error"}]}, {"name": "InvalidDataError"}]}}], "events": [{"name": "AggregatorInitEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}]}, {"name": "AggregatorOpenRoundEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "oraclePubkeys", "type": {"vec": "publicKey"}, "index": false}, {"name": "jobPubkeys", "type": {"vec": "publicKey"}, "index": false}, {"name": "remainingFunds", "type": "u64", "index": false}, {"name": "queueAuthority", "type": "publicKey", "index": false}]}, {"name": "AggregatorValueUpdateEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "value", "type": {"defined": "BorshDecimal"}, "index": false}, {"name": "slot", "type": "u64", "index": false}, {"name": "timestamp", "type": "i64", "index": false}, {"name": "oraclePubkeys", "type": {"vec": "publicKey"}, "index": false}, {"name": "oracleValues", "type": {"vec": {"defined": "BorshDecimal"}}, "index": false}]}, {"name": "OracleRewardEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "leasePubkey", "type": "publicKey", "index": false}, {"name": "oraclePubkey", "type": "publicKey", "index": false}, {"name": "walletPubkey", "type": "publicKey", "index": false}, {"name": "amount", "type": "u64", "index": false}, {"name": "roundSlot", "type": "u64", "index": false}, {"name": "timestamp", "type": "i64", "index": false}]}, {"name": "OracleWithdrawEvent", "fields": [{"name": "oraclePubkey", "type": "publicKey", "index": false}, {"name": "walletPubkey", "type": "publicKey", "index": false}, {"name": "destinationWallet", "type": "publicKey", "index": false}, {"name": "previousAmount", "type": "u64", "index": false}, {"name": "newAmount", "type": "u64", "index": false}, {"name": "timestamp", "type": "i64", "index": false}]}, {"name": "LeaseWithdrawEvent", "fields": [{"name": "leasePubkey", "type": "publicKey", "index": false}, {"name": "walletPubkey", "type": "publicKey", "index": false}, {"name": "previousAmount", "type": "u64", "index": false}, {"name": "newAmount", "type": "u64", "index": false}, {"name": "timestamp", "type": "i64", "index": false}]}, {"name": "OracleSlashEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "leasePubkey", "type": "publicKey", "index": false}, {"name": "oraclePubkey", "type": "publicKey", "index": false}, {"name": "walletPubkey", "type": "publicKey", "index": false}, {"name": "amount", "type": "u64", "index": false}, {"name": "roundSlot", "type": "u64", "index": false}, {"name": "timestamp", "type": "i64", "index": false}]}, {"name": "LeaseFundEvent", "fields": [{"name": "leasePubkey", "type": "publicKey", "index": false}, {"name": "funder", "type": "publicKey", "index": false}, {"name": "amount", "type": "u64", "index": false}, {"name": "timestamp", "type": "i64", "index": false}]}, {"name": "ProbationBrokenEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "queuePubkey", "type": "publicKey", "index": false}, {"name": "timestamp", "type": "i64", "index": false}]}, {"name": "FeedPermissionRevokedEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "timestamp", "type": "i64", "index": false}]}, {"name": "GarbageCollectFailureEvent", "fields": [{"name": "queuePubkey", "type": "publicKey", "index": false}]}, {"name": "OracleBootedEvent", "fields": [{"name": "queuePubkey", "type": "publicKey", "index": false}, {"name": "oraclePubkey", "type": "publicKey", "index": false}]}, {"name": "CrankLeaseInsufficientFundsEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "leasePubkey", "type": "publicKey", "index": false}]}, {"name": "CrankPopExpectedFailureEvent", "fields": [{"name": "feedPubkey", "type": "publicKey", "index": false}, {"name": "leasePubkey", "type": "publicKey", "index": false}]}], "errors": [{"code": 6000, "name": "ArrayOperationError", "msg": "Illegal operation on a Switchboard array."}, {"code": 6001, "name": "QueueOperationError", "msg": "Illegal operation on a Switchboard queue."}, {"code": 6002, "name": "IncorrectProgramOwnerError", "msg": "An account required to be owned by the program has a different owner."}, {"code": 6003, "name": "InvalidAggregatorRound", "msg": "Aggregator is not currently populated with a valid round."}, {"code": 6004, "name": "TooManyAggregatorJobs", "msg": "Aggregator cannot fit any more jobs."}, {"code": 6005, "name": "AggregatorCurrentRoundClosed", "msg": "Aggregator's current round is closed. No results are being accepted."}, {"code": 6006, "name": "AggregatorInvalidSaveResult", "msg": "Aggregator received an invalid save result instruction."}, {"code": 6007, "name": "InvalidStrDecimalConversion", "msg": "Failed to convert string to decimal format."}, {"code": 6008, "name": "AccountLoaderMissingSignature", "msg": "AccountLoader account is missing a required signature."}, {"code": 6009, "name": "MissingRequiredSignature", "msg": "Account is missing a required signature."}, {"code": 6010, "name": "ArrayOverflowError", "msg": "The attempted action will overflow a zero-copy account array."}, {"code": 6011, "name": "ArrayUnderflowError", "msg": "The attempted action will underflow a zero-copy account array."}, {"code": 6012, "name": "PubkeyNotFoundError", "msg": "The queried public key was not found."}, {"code": 6013, "name": "AggregatorIllegalRoundOpenCall", "msg": "Aggregator round open called too early."}, {"code": 6014, "name": "AggregatorIllegalRoundCloseCall", "msg": "Aggregator round close called too early."}, {"code": 6015, "name": "AggregatorClosedError", "msg": "Aggregator is closed. Illegal aciton."}, {"code": 6016, "name": "IllegalOracleIdxError", "msg": "Illegal oracle index."}, {"code": 6017, "name": "OracleAlreadyRespondedError", "msg": "The provided oracle has already responded this round."}, {"code": 6018, "name": "ProtoDeserializeError", "msg": "Failed to deserialize protocol buffer."}, {"code": 6019, "name": "UnauthorizedStateUpdateError", "msg": "Unathorized program state modification attempted."}, {"code": 6020, "name": "MissingOracleAccountsError", "msg": "Not enough oracle accounts provided to closeRounds."}, {"code": 6021, "name": "OracleMismatchError", "msg": "An unexpected oracle account was provided for the transaction."}, {"code": 6022, "name": "CrankMaxCapacityError", "msg": "Attempted to push to a Crank that's at capacity"}, {"code": 6023, "name": "AggregatorLeaseInsufficientFunds", "msg": "Aggregator update call attempted but attached lease has insufficient funds."}, {"code": 6024, "name": "IncorrectTokenAccountMint", "msg": "The provided token account does not point to the Switchbaord token mint."}, {"code": 6025, "name": "InvalidEscrowAccount", "msg": "An invalid escrow account was provided."}, {"code": 6026, "name": "CrankEmptyError", "msg": "Crank empty. Pop failed."}, {"code": 6027, "name": "PdaDeriveError", "msg": "Failed to derive a PDA from the provided seed."}, {"code": 6028, "name": "AggregatorAccountNotFound", "msg": "Aggregator account missing from provided account list."}, {"code": 6029, "name": "PermissionAccountNotFound", "msg": "Permission account missing from provided account list."}, {"code": 6030, "name": "LeaseAccountDeriveFailure", "msg": "Failed to derive a lease account."}, {"code": 6031, "name": "PermissionAccountDeriveFailure", "msg": "Failed to derive a permission account."}, {"code": 6032, "name": "EscrowAccountNotFound", "msg": "Escrow account missing from provided account list."}, {"code": 6033, "name": "LeaseAccountNotFound", "msg": "Lease account missing from provided account list."}, {"code": 6034, "name": "DecimalConversionError", "msg": "Decimal conversion method failed."}, {"code": 6035, "name": "PermissionDenied", "msg": "Permission account is missing required flags for the given action."}, {"code": 6036, "name": "QueueAtCapacity", "msg": "Oracle queue is at lease capacity."}, {"code": 6037, "name": "ExcessiveCrankRowsError", "msg": "Data feed is already pushed on a crank."}, {"code": 6038, "name": "AggregatorLockedError", "msg": "Aggregator is locked, no setting modifications or job additions allowed."}, {"code": 6039, "name": "AggregatorInvalidBatchSizeError", "msg": "Aggregator invalid batch size."}, {"code": 6040, "name": "AggregatorJobChecksumMismatch", "msg": "Oracle provided an incorrect aggregator job checksum."}, {"code": 6041, "name": "IntegerOverflowError", "msg": "An integer overflow occurred."}, {"code": 6042, "name": "InvalidUpdatePeriodError", "msg": "Mimimum update period is 5 seconds."}, {"code": 6043, "name": "NoResultsError", "msg": "Aggregator round evaluation attempted with no results."}, {"code": 6044, "name": "InvalidExpirationError", "msg": "An expiration constraint was broken."}, {"code": 6045, "name": "InsufficientStakeError", "msg": "An account provided insufficient stake for aciton."}, {"code": 6046, "name": "LeaseInactiveError", "msg": "The provided lease account is not active."}, {"code": 6047, "name": "NoAggregatorJobsFound", "msg": "No jobs are currently included in the aggregator."}, {"code": 6048, "name": "IntegerUnderflowError", "msg": "An integer underflow occurred."}, {"code": 6049, "name": "OracleQueueMismatch", "msg": "An invalid oracle queue account was provided."}, {"code": 6050, "name": "OracleWalletMismatchError", "msg": "An unexpected oracle wallet account was provided for the transaction."}, {"code": 6051, "name": "InvalidBufferAccountError", "msg": "An invalid buffer account was provided."}, {"code": 6052, "name": "InsufficientOracleQueueError", "msg": "Insufficient oracle queue size."}, {"code": 6053, "name": "InvalidAuthorityError", "msg": "Invalid authority account provided."}, {"code": 6054, "name": "InvalidTokenAccountMintError", "msg": "A provided token wallet is associated with an incorrect mint."}, {"code": 6055, "name": "ExcessiveLeaseWithdrawlError", "msg": "You must leave enough funds to perform at least 1 update in the lease."}, {"code": 6056, "name": "InvalideHistoryAccountError", "msg": "Invalid history account provided."}, {"code": 6057, "name": "InvalidLeaseAccountEscrowError", "msg": "Invalid lease account escrow."}, {"code": 6058, "name": "InvalidCrankAccountError", "msg": "Invalid crank provided."}, {"code": 6059, "name": "CrankNoElementsReadyError", "msg": "No elements ready to be popped."}, {"code": 6060, "name": "VrfVerifyError", "msg": "Error in verifying vrf proof."}]} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/switchboard_v2.mainnet.06022022.json b/basics/anchorpy-main/tests/idls/switchboard_v2.mainnet.06022022.json new file mode 100644 index 0000000..1635cf8 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/switchboard_v2.mainnet.06022022.json @@ -0,0 +1,4601 @@ +{ + "version": "0.1.0", + "name": "switchboard_v2", + "instructions": [ + { + "name": "aggregatorAddJob", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "job", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorAddJobParams" + } + } + ] + }, + { + "name": "aggregatorInit", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "queue", + "isMut": false, + "isSigner": false + }, + { + "name": "authorWallet", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorInitParams" + } + } + ] + }, + { + "name": "aggregatorLock", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorLockParams" + } + } + ] + }, + { + "name": "aggregatorOpenRound", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "lease", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "queueAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "permission", + "isMut": true, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "payoutWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "dataBuffer", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorOpenRoundParams" + } + } + ] + }, + { + "name": "aggregatorRemoveJob", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "job", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorRemoveJobParams" + } + } + ] + }, + { + "name": "aggregatorSaveResult", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "oracleQueue", + "isMut": false, + "isSigner": false + }, + { + "name": "queueAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "feedPermission", + "isMut": true, + "isSigner": false + }, + { + "name": "oraclePermission", + "isMut": false, + "isSigner": false + }, + { + "name": "lease", + "isMut": true, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "historyBuffer", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSaveResultParams" + } + } + ] + }, + { + "name": "aggregatorSetAuthority", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "newAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetAuthorityParams" + } + } + ] + }, + { + "name": "aggregatorSetBatchSize", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetBatchSizeParams" + } + } + ] + }, + { + "name": "aggregatorSetHistoryBuffer", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "buffer", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetHistoryBufferParams" + } + } + ] + }, + { + "name": "aggregatorSetMinJobs", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetMinJobsParams" + } + } + ] + }, + { + "name": "aggregatorSetMinOracles", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetMinOraclesParams" + } + } + ] + }, + { + "name": "aggregatorSetQueue", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "queue", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetQueueParams" + } + } + ] + }, + { + "name": "aggregatorSetUpdateInterval", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetUpdateIntervalParams" + } + } + ] + }, + { + "name": "aggregatorSetVarianceThreshold", + "accounts": [ + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "AggregatorSetVarianceThresholdParams" + } + } + ] + }, + { + "name": "crankInit", + "accounts": [ + { + "name": "crank", + "isMut": true, + "isSigner": true + }, + { + "name": "queue", + "isMut": false, + "isSigner": false + }, + { + "name": "buffer", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "CrankInitParams" + } + } + ] + }, + { + "name": "crankPop", + "accounts": [ + { + "name": "crank", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "queueAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "payoutWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "crankDataBuffer", + "isMut": true, + "isSigner": false + }, + { + "name": "queueDataBuffer", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "CrankPopParams" + } + } + ] + }, + { + "name": "crankPush", + "accounts": [ + { + "name": "crank", + "isMut": true, + "isSigner": false + }, + { + "name": "aggregator", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "queueAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "permission", + "isMut": false, + "isSigner": false + }, + { + "name": "lease", + "isMut": true, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "dataBuffer", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "CrankPushParams" + } + } + ] + }, + { + "name": "jobInit", + "accounts": [ + { + "name": "job", + "isMut": true, + "isSigner": false + }, + { + "name": "authorWallet", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "JobInitParams" + } + } + ] + }, + { + "name": "leaseExtend", + "accounts": [ + { + "name": "lease", + "isMut": true, + "isSigner": false + }, + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "queue", + "isMut": false, + "isSigner": false + }, + { + "name": "funder", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LeaseExtendParams" + } + } + ] + }, + { + "name": "leaseInit", + "accounts": [ + { + "name": "lease", + "isMut": true, + "isSigner": false + }, + { + "name": "queue", + "isMut": true, + "isSigner": false + }, + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "funder", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LeaseInitParams" + } + } + ] + }, + { + "name": "leaseSetAuthority", + "accounts": [ + { + "name": "lease", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "newAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LeaseSetAuthorityParams" + } + } + ] + }, + { + "name": "leaseWithdraw", + "accounts": [ + { + "name": "lease", + "isMut": true, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "queue", + "isMut": false, + "isSigner": false + }, + { + "name": "withdrawAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "withdrawAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LeaseWithdrawParams" + } + } + ] + }, + { + "name": "oracleHeartbeat", + "accounts": [ + { + "name": "oracle", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenAccount", + "isMut": false, + "isSigner": false + }, + { + "name": "gcOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "permission", + "isMut": false, + "isSigner": false + }, + { + "name": "dataBuffer", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OracleHeartbeatParams" + } + } + ] + }, + { + "name": "oracleInit", + "accounts": [ + { + "name": "oracle", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "wallet", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "queue", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OracleInitParams" + } + } + ] + }, + { + "name": "oracleQueueInit", + "accounts": [ + { + "name": "oracleQueue", + "isMut": true, + "isSigner": true + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "buffer", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OracleQueueInitParams" + } + } + ] + }, + { + "name": "oracleQueueSetRewards", + "accounts": [ + { + "name": "queue", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OracleQueueSetRewardsParams" + } + } + ] + }, + { + "name": "oracleQueueVrfConfig", + "accounts": [ + { + "name": "queue", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OracleQueueVrfConfigParams" + } + } + ] + }, + { + "name": "oracleWithdraw", + "accounts": [ + { + "name": "oracle", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "tokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "withdrawAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "permission", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OracleWithdrawParams" + } + } + ] + }, + { + "name": "permissionInit", + "accounts": [ + { + "name": "permission", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "granter", + "isMut": false, + "isSigner": false + }, + { + "name": "grantee", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PermissionInitParams" + } + } + ] + }, + { + "name": "permissionSet", + "accounts": [ + { + "name": "permission", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PermissionSetParams" + } + } + ] + }, + { + "name": "programConfig", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ProgramConfigParams" + } + } + ] + }, + { + "name": "programInit", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenMint", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ProgramInitParams" + } + } + ] + }, + { + "name": "vaultTransfer", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "to", + "isMut": true, + "isSigner": false + }, + { + "name": "vault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "VaultTransferParams" + } + } + ] + }, + { + "name": "vrfInit", + "accounts": [ + { + "name": "vrf", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "oracleQueue", + "isMut": false, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "VrfInitParams" + } + } + ] + }, + { + "name": "vrfProve", + "accounts": [ + { + "name": "vrf", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "randomnessProducer", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "VrfProveParams" + } + } + ] + }, + { + "name": "vrfProveAndVerify", + "accounts": [ + { + "name": "vrf", + "isMut": true, + "isSigner": false + }, + { + "name": "callbackPid", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "oracleAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "oracleWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "instructionsSysvar", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "VrfProveAndVerifyParams" + } + } + ] + }, + { + "name": "vrfRequestRandomness", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "vrf", + "isMut": true, + "isSigner": false + }, + { + "name": "oracleQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "queueAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "dataBuffer", + "isMut": false, + "isSigner": false + }, + { + "name": "permission", + "isMut": true, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "payerWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "payerAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "recentBlockhashes", + "isMut": false, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "VrfRequestRandomnessParams" + } + } + ] + }, + { + "name": "vrfVerify", + "accounts": [ + { + "name": "vrf", + "isMut": true, + "isSigner": false + }, + { + "name": "callbackPid", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "programState", + "isMut": false, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "oracleAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "oracleWallet", + "isMut": true, + "isSigner": false + }, + { + "name": "instructionsSysvar", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "VrfVerifyParams" + } + } + ] + } + ], + "accounts": [ + { + "name": "SbState", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "tokenMint", + "type": "publicKey" + }, + { + "name": "tokenVault", + "type": "publicKey" + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 1024] + } + } + ] + } + }, + { + "name": "AggregatorAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "metadata", + "type": { + "array": ["u8", 128] + } + }, + { + "name": "authorWallet", + "type": "publicKey" + }, + { + "name": "queuePubkey", + "type": "publicKey" + }, + { + "name": "oracleRequestBatchSize", + "type": "u32" + }, + { + "name": "minOracleResults", + "type": "u32" + }, + { + "name": "minJobResults", + "type": "u32" + }, + { + "name": "minUpdateDelaySeconds", + "type": "u32" + }, + { + "name": "startAfter", + "type": "i64" + }, + { + "name": "varianceThreshold", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "forceReportPeriod", + "type": "i64" + }, + { + "name": "expiration", + "type": "i64" + }, + { + "name": "consecutiveFailureCount", + "type": "u64" + }, + { + "name": "nextAllowedUpdateTime", + "type": "i64" + }, + { + "name": "isLocked", + "type": "bool" + }, + { + "name": "crankPubkey", + "type": "publicKey" + }, + { + "name": "latestConfirmedRound", + "type": { + "defined": "AggregatorRound" + } + }, + { + "name": "currentRound", + "type": { + "defined": "AggregatorRound" + } + }, + { + "name": "jobPubkeysData", + "type": { + "array": ["publicKey", 16] + } + }, + { + "name": "jobHashes", + "type": { + "array": [ + { + "defined": "Hash" + }, + 16 + ] + } + }, + { + "name": "jobPubkeysSize", + "type": "u32" + }, + { + "name": "jobsChecksum", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "historyBuffer", + "type": "publicKey" + }, + { + "name": "previousConfirmedRoundResult", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "previousConfirmedRoundSlot", + "type": "u64" + }, + { + "name": "disableCrank", + "type": "bool" + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 163] + } + } + ] + } + }, + { + "name": "PermissionAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "permissions", + "type": "u32" + }, + { + "name": "granter", + "type": "publicKey" + }, + { + "name": "grantee", + "type": "publicKey" + }, + { + "name": "expiration", + "type": "i64" + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 256] + } + } + ] + } + }, + { + "name": "LeaseAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "escrow", + "type": "publicKey" + }, + { + "name": "queue", + "type": "publicKey" + }, + { + "name": "aggregator", + "type": "publicKey" + }, + { + "name": "tokenProgram", + "type": "publicKey" + }, + { + "name": "isActive", + "type": "bool" + }, + { + "name": "crankRowCount", + "type": "u32" + }, + { + "name": "createdAt", + "type": "i64" + }, + { + "name": "updateCount", + "type": "u128" + }, + { + "name": "withdrawAuthority", + "type": "publicKey" + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 256] + } + } + ] + } + }, + { + "name": "OracleQueueAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "metadata", + "type": { + "array": ["u8", 64] + } + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "oracleTimeout", + "type": "u32" + }, + { + "name": "reward", + "type": "u64" + }, + { + "name": "minStake", + "type": "u64" + }, + { + "name": "slashingEnabled", + "type": "bool" + }, + { + "name": "varianceToleranceMultiplier", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "feedProbationPeriod", + "type": "u32" + }, + { + "name": "currIdx", + "type": "u32" + }, + { + "name": "size", + "type": "u32" + }, + { + "name": "gcIdx", + "type": "u32" + }, + { + "name": "consecutiveFeedFailureLimit", + "type": "u64" + }, + { + "name": "consecutiveOracleFailureLimit", + "type": "u64" + }, + { + "name": "unpermissionedFeedsEnabled", + "type": "bool" + }, + { + "name": "unpermissionedVrfEnabled", + "type": "bool" + }, + { + "name": "curatorRewardCut", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "lockLeaseFunding", + "type": "bool" + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 1001] + } + }, + { + "name": "maxSize", + "type": "u32" + }, + { + "name": "dataBuffer", + "type": "publicKey" + } + ] + } + }, + { + "name": "CrankAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "metadata", + "type": { + "array": ["u8", 64] + } + }, + { + "name": "queuePubkey", + "type": "publicKey" + }, + { + "name": "pqSize", + "type": "u32" + }, + { + "name": "maxRows", + "type": "u32" + }, + { + "name": "jitterModifier", + "type": "u8" + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 255] + } + }, + { + "name": "dataBuffer", + "type": "publicKey" + } + ] + } + }, + { + "name": "OracleAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "metadata", + "type": { + "array": ["u8", 128] + } + }, + { + "name": "oracleAuthority", + "type": "publicKey" + }, + { + "name": "lastHeartbeat", + "type": "i64" + }, + { + "name": "numInUse", + "type": "u32" + }, + { + "name": "tokenAccount", + "type": "publicKey" + }, + { + "name": "queuePubkey", + "type": "publicKey" + }, + { + "name": "metrics", + "type": { + "defined": "OracleMetrics" + } + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 256] + } + } + ] + } + }, + { + "name": "JobAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "metadata", + "type": { + "array": ["u8", 64] + } + }, + { + "name": "authorWallet", + "type": "publicKey" + }, + { + "name": "expiration", + "type": "i64" + }, + { + "name": "hash", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "data", + "type": "bytes" + }, + { + "name": "referenceCount", + "type": "u32" + }, + { + "name": "totalSpent", + "type": "u128" + } + ] + } + }, + { + "name": "VrfAccountData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "status", + "type": { + "defined": "VrfStatus" + } + }, + { + "name": "counter", + "type": "u128" + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "oracleQueue", + "type": "publicKey" + }, + { + "name": "escrow", + "type": "publicKey" + }, + { + "name": "callback", + "type": { + "defined": "CallbackZC" + } + }, + { + "name": "batchSize", + "type": "u32" + }, + { + "name": "builders", + "type": { + "array": [ + { + "defined": "VrfBuilder" + }, + 8 + ] + } + }, + { + "name": "buildersLen", + "type": "u32" + }, + { + "name": "testMode", + "type": "bool" + }, + { + "name": "currentRound", + "type": { + "defined": "VrfRound" + } + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 1024] + } + } + ] + } + } + ], + "types": [ + { + "name": "AggregatorAddJobParams", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "AggregatorInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "metadata", + "type": { + "array": ["u8", 128] + } + }, + { + "name": "batchSize", + "type": "u32" + }, + { + "name": "minOracleResults", + "type": "u32" + }, + { + "name": "minJobResults", + "type": "u32" + }, + { + "name": "minUpdateDelaySeconds", + "type": "u32" + }, + { + "name": "startAfter", + "type": "i64" + }, + { + "name": "varianceThreshold", + "type": { + "defined": "BorshDecimal" + } + }, + { + "name": "forceReportPeriod", + "type": "i64" + }, + { + "name": "expiration", + "type": "i64" + }, + { + "name": "stateBump", + "type": "u8" + } + ] + } + }, + { + "name": "AggregatorLockParams", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "AggregatorOpenRoundParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "leaseBump", + "type": "u8" + }, + { + "name": "permissionBump", + "type": "u8" + }, + { + "name": "jitter", + "type": "u8" + } + ] + } + }, + { + "name": "AggregatorRemoveJobParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "jobIdx", + "type": "u32" + } + ] + } + }, + { + "name": "AggregatorSaveResultParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oracleIdx", + "type": "u32" + }, + { + "name": "error", + "type": "bool" + }, + { + "name": "value", + "type": { + "defined": "BorshDecimal" + } + }, + { + "name": "jobsChecksum", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "minResponse", + "type": { + "defined": "BorshDecimal" + } + }, + { + "name": "maxResponse", + "type": { + "defined": "BorshDecimal" + } + }, + { + "name": "feedPermissionBump", + "type": "u8" + }, + { + "name": "oraclePermissionBump", + "type": "u8" + }, + { + "name": "leaseBump", + "type": "u8" + }, + { + "name": "stateBump", + "type": "u8" + } + ] + } + }, + { + "name": "AggregatorSetAuthorityParams", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "AggregatorSetBatchSizeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "batchSize", + "type": "u32" + } + ] + } + }, + { + "name": "AggregatorSetHistoryBufferParams", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "AggregatorSetMinJobsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "minJobResults", + "type": "u32" + } + ] + } + }, + { + "name": "AggregatorSetMinOraclesParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "minOracleResults", + "type": "u32" + } + ] + } + }, + { + "name": "AggregatorSetQueueParams", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "AggregatorSetUpdateIntervalParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "newInterval", + "type": "u32" + } + ] + } + }, + { + "name": "AggregatorSetVarianceThresholdParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "varianceThreshold", + "type": { + "defined": "BorshDecimal" + } + } + ] + } + }, + { + "name": "CrankInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": "bytes" + }, + { + "name": "metadata", + "type": "bytes" + }, + { + "name": "crankSize", + "type": "u32" + } + ] + } + }, + { + "name": "CrankPopParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "leaseBumps", + "type": "bytes" + }, + { + "name": "permissionBumps", + "type": "bytes" + }, + { + "name": "nonce", + "type": { + "option": "u32" + } + }, + { + "name": "failOpenOnAccountMismatch", + "type": { + "option": "bool" + } + } + ] + } + }, + { + "name": "CrankPushParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "permissionBump", + "type": "u8" + } + ] + } + }, + { + "name": "JobInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "expiration", + "type": "i64" + }, + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "data", + "type": "bytes" + } + ] + } + }, + { + "name": "LeaseExtendParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "loadAmount", + "type": "u64" + }, + { + "name": "leaseBump", + "type": "u8" + }, + { + "name": "stateBump", + "type": "u8" + } + ] + } + }, + { + "name": "LeaseInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "loadAmount", + "type": "u64" + }, + { + "name": "withdrawAuthority", + "type": "publicKey" + }, + { + "name": "leaseBump", + "type": "u8" + }, + { + "name": "stateBump", + "type": "u8" + } + ] + } + }, + { + "name": "LeaseSetAuthorityParams", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "LeaseWithdrawParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "leaseBump", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "OracleHeartbeatParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "permissionBump", + "type": "u8" + } + ] + } + }, + { + "name": "OracleInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": "bytes" + }, + { + "name": "metadata", + "type": "bytes" + }, + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "oracleBump", + "type": "u8" + } + ] + } + }, + { + "name": "OracleQueueInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "metadata", + "type": { + "array": ["u8", 64] + } + }, + { + "name": "reward", + "type": "u64" + }, + { + "name": "minStake", + "type": "u64" + }, + { + "name": "feedProbationPeriod", + "type": "u32" + }, + { + "name": "oracleTimeout", + "type": "u32" + }, + { + "name": "slashingEnabled", + "type": "bool" + }, + { + "name": "varianceToleranceMultiplier", + "type": { + "defined": "BorshDecimal" + } + }, + { + "name": "consecutiveFeedFailureLimit", + "type": "u64" + }, + { + "name": "consecutiveOracleFailureLimit", + "type": "u64" + }, + { + "name": "queueSize", + "type": "u32" + }, + { + "name": "unpermissionedFeeds", + "type": "bool" + }, + { + "name": "unpermissionedVrf", + "type": "bool" + } + ] + } + }, + { + "name": "OracleQueueSetRewardsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "rewards", + "type": "u64" + } + ] + } + }, + { + "name": "OracleQueueVrfConfigParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "unpermissionedVrfEnabled", + "type": "bool" + } + ] + } + }, + { + "name": "OracleWithdrawParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "permissionBump", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "PermissionInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "permissionBump", + "type": "u8" + } + ] + } + }, + { + "name": "PermissionSetParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "permission", + "type": { + "defined": "SwitchboardPermission" + } + }, + { + "name": "enable", + "type": "bool" + } + ] + } + }, + { + "name": "ProgramConfigParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "token", + "type": "publicKey" + }, + { + "name": "bump", + "type": "u8" + } + ] + } + }, + { + "name": "ProgramInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "stateBump", + "type": "u8" + } + ] + } + }, + { + "name": "VaultTransferParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "VrfInitParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "callback", + "type": { + "defined": "Callback" + } + }, + { + "name": "stateBump", + "type": "u8" + } + ] + } + }, + { + "name": "VrfProveParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "proof", + "type": "bytes" + }, + { + "name": "idx", + "type": "u32" + } + ] + } + }, + { + "name": "VrfProveAndVerifyParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nonce", + "type": { + "option": "u32" + } + }, + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "idx", + "type": "u32" + }, + { + "name": "proof", + "type": "bytes" + } + ] + } + }, + { + "name": "VrfRequestRandomnessParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "permissionBump", + "type": "u8" + }, + { + "name": "stateBump", + "type": "u8" + } + ] + } + }, + { + "name": "VrfVerifyParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nonce", + "type": { + "option": "u32" + } + }, + { + "name": "stateBump", + "type": "u8" + }, + { + "name": "idx", + "type": "u32" + } + ] + } + }, + { + "name": "Hash", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": { + "array": ["u8", 32] + } + } + ] + } + }, + { + "name": "AggregatorRound", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numSuccess", + "type": "u32" + }, + { + "name": "numError", + "type": "u32" + }, + { + "name": "isClosed", + "type": "bool" + }, + { + "name": "roundOpenSlot", + "type": "u64" + }, + { + "name": "roundOpenTimestamp", + "type": "i64" + }, + { + "name": "result", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "stdDeviation", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "minResponse", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "maxResponse", + "type": { + "defined": "SwitchboardDecimal" + } + }, + { + "name": "oraclePubkeysData", + "type": { + "array": ["publicKey", 16] + } + }, + { + "name": "mediansData", + "type": { + "array": [ + { + "defined": "SwitchboardDecimal" + }, + 16 + ] + } + }, + { + "name": "currentPayout", + "type": { + "array": ["i64", 16] + } + }, + { + "name": "mediansFulfilled", + "type": { + "array": ["bool", 16] + } + }, + { + "name": "errorsFulfilled", + "type": { + "array": ["bool", 16] + } + } + ] + } + }, + { + "name": "AggregatorHistoryRow", + "type": { + "kind": "struct", + "fields": [ + { + "name": "timestamp", + "type": "i64" + }, + { + "name": "value", + "type": { + "defined": "SwitchboardDecimal" + } + } + ] + } + }, + { + "name": "SwitchboardDecimal", + "type": { + "kind": "struct", + "fields": [ + { + "name": "mantissa", + "type": "i128" + }, + { + "name": "scale", + "type": "u32" + } + ] + } + }, + { + "name": "CrankRow", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "nextTimestamp", + "type": "i64" + } + ] + } + }, + { + "name": "OracleMetrics", + "type": { + "kind": "struct", + "fields": [ + { + "name": "consecutiveSuccess", + "type": "u64" + }, + { + "name": "consecutiveError", + "type": "u64" + }, + { + "name": "consecutiveDisagreement", + "type": "u64" + }, + { + "name": "consecutiveLateResponse", + "type": "u64" + }, + { + "name": "consecutiveFailure", + "type": "u64" + }, + { + "name": "totalSuccess", + "type": "u128" + }, + { + "name": "totalError", + "type": "u128" + }, + { + "name": "totalDisagreement", + "type": "u128" + }, + { + "name": "totalLateResponse", + "type": "u128" + } + ] + } + }, + { + "name": "BorshDecimal", + "type": { + "kind": "struct", + "fields": [ + { + "name": "mantissa", + "type": "i128" + }, + { + "name": "scale", + "type": "u32" + } + ] + } + }, + { + "name": "EcvrfProofZC", + "type": { + "kind": "struct", + "fields": [ + { + "name": "gamma", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "c", + "type": { + "defined": "Scalar" + } + }, + { + "name": "s", + "type": { + "defined": "Scalar" + } + } + ] + } + }, + { + "name": "Scalar", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bytes", + "type": { + "array": ["u8", 32] + } + } + ] + } + }, + { + "name": "FieldElementZC", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bytes", + "type": { + "array": ["u64", 5] + } + } + ] + } + }, + { + "name": "CompletedPointZC", + "type": { + "kind": "struct", + "fields": [ + { + "name": "x", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "y", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "z", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "t", + "type": { + "defined": "FieldElementZC" + } + } + ] + } + }, + { + "name": "EdwardsPointZC", + "type": { + "kind": "struct", + "fields": [ + { + "name": "x", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "y", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "z", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "t", + "type": { + "defined": "FieldElementZC" + } + } + ] + } + }, + { + "name": "ProjectivePointZC", + "type": { + "kind": "struct", + "fields": [ + { + "name": "x", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "y", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "z", + "type": { + "defined": "FieldElementZC" + } + } + ] + } + }, + { + "name": "EcvrfIntermediate", + "type": { + "kind": "struct", + "fields": [ + { + "name": "r", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "nS", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "d", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "t13", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "t15", + "type": { + "defined": "FieldElementZC" + } + } + ] + } + }, + { + "name": "VrfBuilder", + "type": { + "kind": "struct", + "fields": [ + { + "name": "producer", + "type": "publicKey" + }, + { + "name": "status", + "type": { + "defined": "VrfStatus" + } + }, + { + "name": "reprProof", + "type": { + "array": ["u8", 80] + } + }, + { + "name": "proof", + "type": { + "defined": "EcvrfProofZC" + } + }, + { + "name": "yPoint", + "type": "publicKey" + }, + { + "name": "stage", + "type": "u32" + }, + { + "name": "stage1Out", + "type": { + "defined": "EcvrfIntermediate" + } + }, + { + "name": "r1", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "r2", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "stage3Out", + "type": { + "defined": "EcvrfIntermediate" + } + }, + { + "name": "hPoint", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "sReduced", + "type": { + "defined": "Scalar" + } + }, + { + "name": "yPointBuilder", + "type": { + "array": [ + { + "defined": "FieldElementZC" + }, + 3 + ] + } + }, + { + "name": "yRistrettoPoint", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "mulRound", + "type": "u8" + }, + { + "name": "hashPointsRound", + "type": "u8" + }, + { + "name": "mulTmp1", + "type": { + "defined": "CompletedPointZC" + } + }, + { + "name": "uPoint1", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "uPoint2", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "vPoint1", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "vPoint2", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "uPoint", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "vPoint", + "type": { + "defined": "EdwardsPointZC" + } + }, + { + "name": "u1", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "u2", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "invertee", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "y", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "z", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "p1Bytes", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "p2Bytes", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "p3Bytes", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "p4Bytes", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "cPrimeHashbuf", + "type": { + "array": ["u8", 16] + } + }, + { + "name": "m1", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "m2", + "type": { + "defined": "FieldElementZC" + } + }, + { + "name": "txRemaining", + "type": "u32" + }, + { + "name": "verified", + "type": "bool" + }, + { + "name": "result", + "type": { + "array": ["u8", 32] + } + } + ] + } + }, + { + "name": "AccountMetaZC", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "isSigner", + "type": "bool" + }, + { + "name": "isWritable", + "type": "bool" + } + ] + } + }, + { + "name": "AccountMetaBorsh", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "isSigner", + "type": "bool" + }, + { + "name": "isWritable", + "type": "bool" + } + ] + } + }, + { + "name": "CallbackZC", + "type": { + "kind": "struct", + "fields": [ + { + "name": "programId", + "type": "publicKey" + }, + { + "name": "accounts", + "type": { + "array": [ + { + "defined": "AccountMetaZC" + }, + 32 + ] + } + }, + { + "name": "accountsLen", + "type": "u32" + }, + { + "name": "ixData", + "type": { + "array": ["u8", 1024] + } + }, + { + "name": "ixDataLen", + "type": "u32" + } + ] + } + }, + { + "name": "Callback", + "type": { + "kind": "struct", + "fields": [ + { + "name": "programId", + "type": "publicKey" + }, + { + "name": "accounts", + "type": { + "vec": { + "defined": "AccountMetaBorsh" + } + } + }, + { + "name": "ixData", + "type": "bytes" + } + ] + } + }, + { + "name": "VrfRound", + "type": { + "kind": "struct", + "fields": [ + { + "name": "alpha", + "type": { + "array": ["u8", 256] + } + }, + { + "name": "alphaLen", + "type": "u32" + }, + { + "name": "requestSlot", + "type": "u64" + }, + { + "name": "requestTimestamp", + "type": "i64" + }, + { + "name": "result", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "numVerified", + "type": "u32" + }, + { + "name": "ebuf", + "type": { + "array": ["u8", 256] + } + } + ] + } + }, + { + "name": "Lanes", + "type": { + "kind": "enum", + "variants": [ + { + "name": "C" + }, + { + "name": "D" + }, + { + "name": "AB" + }, + { + "name": "AC" + }, + { + "name": "CD" + }, + { + "name": "AD" + }, + { + "name": "BC" + }, + { + "name": "ABCD" + } + ] + } + }, + { + "name": "Shuffle", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AAAA" + }, + { + "name": "BBBB" + }, + { + "name": "CACA" + }, + { + "name": "DBBD" + }, + { + "name": "ADDA" + }, + { + "name": "CBCB" + }, + { + "name": "ABAB" + }, + { + "name": "BADC" + }, + { + "name": "BACD" + }, + { + "name": "ABDC" + } + ] + } + }, + { + "name": "Shuffle", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AAAA" + }, + { + "name": "BBBB" + }, + { + "name": "BADC" + }, + { + "name": "BACD" + }, + { + "name": "ADDA" + }, + { + "name": "CBCB" + }, + { + "name": "ABDC" + }, + { + "name": "ABAB" + }, + { + "name": "DBBD" + }, + { + "name": "CACA" + } + ] + } + }, + { + "name": "Lanes", + "type": { + "kind": "enum", + "variants": [ + { + "name": "D" + }, + { + "name": "C" + }, + { + "name": "AB" + }, + { + "name": "AC" + }, + { + "name": "AD" + }, + { + "name": "BCD" + } + ] + } + }, + { + "name": "SwitchboardPermission", + "type": { + "kind": "enum", + "variants": [ + { + "name": "PermitOracleHeartbeat" + }, + { + "name": "PermitOracleQueueUsage" + }, + { + "name": "PermitVrfRequests" + } + ] + } + }, + { + "name": "OracleResponseType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "TypeSuccess" + }, + { + "name": "TypeError" + }, + { + "name": "TypeDisagreement" + }, + { + "name": "TypeNoResponse" + } + ] + } + }, + { + "name": "VrfStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "StatusNone" + }, + { + "name": "StatusRequesting" + }, + { + "name": "StatusVerifying" + }, + { + "name": "StatusVerified" + }, + { + "name": "StatusCallbackSuccess" + }, + { + "name": "StatusVerifyFailure" + } + ] + } + } + ], + "events": [ + { + "name": "AggregatorInitEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "VrfRequestRandomnessEvent", + "fields": [ + { + "name": "vrfPubkey", + "type": "publicKey", + "index": true + }, + { + "name": "oraclePubkeys", + "type": { + "vec": "publicKey" + }, + "index": false + }, + { + "name": "loadAmount", + "type": "u64", + "index": false + }, + { + "name": "existingAmount", + "type": "u64", + "index": false + } + ] + }, + { + "name": "VrfRequestEvent", + "fields": [ + { + "name": "vrfPubkey", + "type": "publicKey", + "index": true + }, + { + "name": "oraclePubkeys", + "type": { + "vec": "publicKey" + }, + "index": false + } + ] + }, + { + "name": "VrfProveEvent", + "fields": [ + { + "name": "vrfPubkey", + "type": "publicKey", + "index": true + }, + { + "name": "oraclePubkey", + "type": "publicKey", + "index": true + }, + { + "name": "authorityPubkey", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "VrfVerifyEvent", + "fields": [ + { + "name": "vrfPubkey", + "type": "publicKey", + "index": true + }, + { + "name": "oraclePubkey", + "type": "publicKey", + "index": true + }, + { + "name": "authorityPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + } + ] + }, + { + "name": "VrfCallbackPerformedEvent", + "fields": [ + { + "name": "vrfPubkey", + "type": "publicKey", + "index": true + }, + { + "name": "oraclePubkey", + "type": "publicKey", + "index": true + }, + { + "name": "amount", + "type": "u64", + "index": false + } + ] + }, + { + "name": "AggregatorOpenRoundEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "oraclePubkeys", + "type": { + "vec": "publicKey" + }, + "index": false + }, + { + "name": "jobPubkeys", + "type": { + "vec": "publicKey" + }, + "index": false + }, + { + "name": "remainingFunds", + "type": "u64", + "index": false + }, + { + "name": "queueAuthority", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "AggregatorValueUpdateEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "value", + "type": { + "defined": "BorshDecimal" + }, + "index": false + }, + { + "name": "slot", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + }, + { + "name": "oraclePubkeys", + "type": { + "vec": "publicKey" + }, + "index": false + }, + { + "name": "oracleValues", + "type": { + "vec": { + "defined": "BorshDecimal" + } + }, + "index": false + } + ] + }, + { + "name": "OracleRewardEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "leasePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "oraclePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "walletPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "roundSlot", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "OracleWithdrawEvent", + "fields": [ + { + "name": "oraclePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "walletPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "destinationWallet", + "type": "publicKey", + "index": false + }, + { + "name": "previousAmount", + "type": "u64", + "index": false + }, + { + "name": "newAmount", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "LeaseWithdrawEvent", + "fields": [ + { + "name": "leasePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "walletPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "previousAmount", + "type": "u64", + "index": false + }, + { + "name": "newAmount", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "OracleSlashEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "leasePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "oraclePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "walletPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "roundSlot", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "LeaseFundEvent", + "fields": [ + { + "name": "leasePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "funder", + "type": "publicKey", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "ProbationBrokenEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "queuePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "FeedPermissionRevokedEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + }, + { + "name": "GarbageCollectFailureEvent", + "fields": [ + { + "name": "queuePubkey", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "OracleBootedEvent", + "fields": [ + { + "name": "queuePubkey", + "type": "publicKey", + "index": false + }, + { + "name": "oraclePubkey", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "CrankLeaseInsufficientFundsEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "leasePubkey", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "CrankPopExpectedFailureEvent", + "fields": [ + { + "name": "feedPubkey", + "type": "publicKey", + "index": false + }, + { + "name": "leasePubkey", + "type": "publicKey", + "index": false + } + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "ArrayOperationError", + "msg": "Illegal operation on a Switchboard array." + }, + { + "code": 6001, + "name": "QueueOperationError", + "msg": "Illegal operation on a Switchboard queue." + }, + { + "code": 6002, + "name": "IncorrectProgramOwnerError", + "msg": "An account required to be owned by the program has a different owner." + }, + { + "code": 6003, + "name": "InvalidAggregatorRound", + "msg": "Aggregator is not currently populated with a valid round." + }, + { + "code": 6004, + "name": "TooManyAggregatorJobs", + "msg": "Aggregator cannot fit any more jobs." + }, + { + "code": 6005, + "name": "AggregatorCurrentRoundClosed", + "msg": "Aggregator's current round is closed. No results are being accepted." + }, + { + "code": 6006, + "name": "AggregatorInvalidSaveResult", + "msg": "Aggregator received an invalid save result instruction." + }, + { + "code": 6007, + "name": "InvalidStrDecimalConversion", + "msg": "Failed to convert string to decimal format." + }, + { + "code": 6008, + "name": "AccountLoaderMissingSignature", + "msg": "AccountLoader account is missing a required signature." + }, + { + "code": 6009, + "name": "MissingRequiredSignature", + "msg": "Account is missing a required signature." + }, + { + "code": 6010, + "name": "ArrayOverflowError", + "msg": "The attempted action will overflow a zero-copy account array." + }, + { + "code": 6011, + "name": "ArrayUnderflowError", + "msg": "The attempted action will underflow a zero-copy account array." + }, + { + "code": 6012, + "name": "PubkeyNotFoundError", + "msg": "The queried public key was not found." + }, + { + "code": 6013, + "name": "AggregatorIllegalRoundOpenCall", + "msg": "Aggregator round open called too early." + }, + { + "code": 6014, + "name": "AggregatorIllegalRoundCloseCall", + "msg": "Aggregator round close called too early." + }, + { + "code": 6015, + "name": "AggregatorClosedError", + "msg": "Aggregator is closed. Illegal action." + }, + { + "code": 6016, + "name": "IllegalOracleIdxError", + "msg": "Illegal oracle index." + }, + { + "code": 6017, + "name": "OracleAlreadyRespondedError", + "msg": "The provided oracle has already responded this round." + }, + { + "code": 6018, + "name": "ProtoDeserializeError", + "msg": "Failed to deserialize protocol buffer." + }, + { + "code": 6019, + "name": "UnauthorizedStateUpdateError", + "msg": "Unauthorized program state modification attempted." + }, + { + "code": 6020, + "name": "MissingOracleAccountsError", + "msg": "Not enough oracle accounts provided to closeRounds." + }, + { + "code": 6021, + "name": "OracleMismatchError", + "msg": "An unexpected oracle account was provided for the transaction." + }, + { + "code": 6022, + "name": "CrankMaxCapacityError", + "msg": "Attempted to push to a Crank that's at capacity" + }, + { + "code": 6023, + "name": "AggregatorLeaseInsufficientFunds", + "msg": "Aggregator update call attempted but attached lease has insufficient funds." + }, + { + "code": 6024, + "name": "IncorrectTokenAccountMint", + "msg": "The provided token account does not point to the Switchboard token mint." + }, + { + "code": 6025, + "name": "InvalidEscrowAccount", + "msg": "An invalid escrow account was provided." + }, + { + "code": 6026, + "name": "CrankEmptyError", + "msg": "Crank empty. Pop failed." + }, + { + "code": 6027, + "name": "PdaDeriveError", + "msg": "Failed to derive a PDA from the provided seed." + }, + { + "code": 6028, + "name": "AggregatorAccountNotFound", + "msg": "Aggregator account missing from provided account list." + }, + { + "code": 6029, + "name": "PermissionAccountNotFound", + "msg": "Permission account missing from provided account list." + }, + { + "code": 6030, + "name": "LeaseAccountDeriveFailure", + "msg": "Failed to derive a lease account." + }, + { + "code": 6031, + "name": "PermissionAccountDeriveFailure", + "msg": "Failed to derive a permission account." + }, + { + "code": 6032, + "name": "EscrowAccountNotFound", + "msg": "Escrow account missing from provided account list." + }, + { + "code": 6033, + "name": "LeaseAccountNotFound", + "msg": "Lease account missing from provided account list." + }, + { + "code": 6034, + "name": "DecimalConversionError", + "msg": "Decimal conversion method failed." + }, + { + "code": 6035, + "name": "PermissionDenied", + "msg": "Permission account is missing required flags for the given action." + }, + { + "code": 6036, + "name": "QueueAtCapacity", + "msg": "Oracle queue is at lease capacity." + }, + { + "code": 6037, + "name": "ExcessiveCrankRowsError", + "msg": "Data feed is already pushed on a crank." + }, + { + "code": 6038, + "name": "AggregatorLockedError", + "msg": "Aggregator is locked, no setting modifications or job additions allowed." + }, + { + "code": 6039, + "name": "AggregatorInvalidBatchSizeError", + "msg": "Aggregator invalid batch size." + }, + { + "code": 6040, + "name": "AggregatorJobChecksumMismatch", + "msg": "Oracle provided an incorrect aggregator job checksum." + }, + { + "code": 6041, + "name": "IntegerOverflowError", + "msg": "An integer overflow occurred." + }, + { + "code": 6042, + "name": "InvalidUpdatePeriodError", + "msg": "Minimum update period is 5 seconds." + }, + { + "code": 6043, + "name": "NoResultsError", + "msg": "Aggregator round evaluation attempted with no results." + }, + { + "code": 6044, + "name": "InvalidExpirationError", + "msg": "An expiration constraint was broken." + }, + { + "code": 6045, + "name": "InsufficientStakeError", + "msg": "An account provided insufficient stake for action." + }, + { + "code": 6046, + "name": "LeaseInactiveError", + "msg": "The provided lease account is not active." + }, + { + "code": 6047, + "name": "NoAggregatorJobsFound", + "msg": "No jobs are currently included in the aggregator." + }, + { + "code": 6048, + "name": "IntegerUnderflowError", + "msg": "An integer underflow occurred." + }, + { + "code": 6049, + "name": "OracleQueueMismatch", + "msg": "An invalid oracle queue account was provided." + }, + { + "code": 6050, + "name": "OracleWalletMismatchError", + "msg": "An unexpected oracle wallet account was provided for the transaction." + }, + { + "code": 6051, + "name": "InvalidBufferAccountError", + "msg": "An invalid buffer account was provided." + }, + { + "code": 6052, + "name": "InsufficientOracleQueueError", + "msg": "Insufficient oracle queue size." + }, + { + "code": 6053, + "name": "InvalidAuthorityError", + "msg": "Invalid authority account provided." + }, + { + "code": 6054, + "name": "InvalidTokenAccountMintError", + "msg": "A provided token wallet is associated with an incorrect mint." + }, + { + "code": 6055, + "name": "ExcessiveLeaseWithdrawlError", + "msg": "You must leave enough funds to perform at least 1 update in the lease." + }, + { + "code": 6056, + "name": "InvalideHistoryAccountError", + "msg": "Invalid history account provided." + }, + { + "code": 6057, + "name": "InvalidLeaseAccountEscrowError", + "msg": "Invalid lease account escrow." + }, + { + "code": 6058, + "name": "InvalidCrankAccountError", + "msg": "Invalid crank provided." + }, + { + "code": 6059, + "name": "CrankNoElementsReadyError", + "msg": "No elements ready to be popped." + }, + { + "code": 6060, + "name": "IndexOutOfBoundsError", + "msg": "Index out of bounds" + }, + { + "code": 6061, + "name": "VrfInvalidRequestError", + "msg": "Invalid vrf request params" + }, + { + "code": 6062, + "name": "VrfInvalidProofSubmissionError", + "msg": "Vrf proof failed to verify" + }, + { + "code": 6063, + "name": "VrfVerifyError", + "msg": "Error in verifying vrf proof." + }, + { + "code": 6064, + "name": "VrfCallbackError", + "msg": "Vrf callback function failed." + }, + { + "code": 6065, + "name": "VrfCallbackParamsError", + "msg": "Invalid vrf callback params provided." + }, + { + "code": 6066, + "name": "VrfCallbackAlreadyCalledError", + "msg": "Vrf callback has already been triggered." + }, + { + "code": 6067, + "name": "VrfInvalidPubkeyError", + "msg": "The provided pubkey is invalid to use in ecvrf proofs" + }, + { + "code": 6068, + "name": "VrfTooManyVerifyCallsError", + "msg": "Number of required verify calls exceeded" + }, + { + "code": 6069, + "name": "VrfRequestAlreadyLaunchedError", + "msg": "Vrf request is already pending" + }, + { + "code": 6070, + "name": "VrfInsufficientVerificationError", + "msg": "Insufficient amount of proofs collected for VRF callback" + }, + { + "code": 6071, + "name": "InvalidVrfProducerError", + "msg": "An incorrect oracle attempted to submit a proof" + }, + { + "code": 6072, + "name": "NoopError", + "msg": "Noop error" + } + ] +} diff --git a/basics/anchorpy-main/tests/idls/sysvars.json b/basics/anchorpy-main/tests/idls/sysvars.json new file mode 100644 index 0000000..11d7c4b --- /dev/null +++ b/basics/anchorpy-main/tests/idls/sysvars.json @@ -0,0 +1,27 @@ +{ + "version": "0.0.0", + "name": "sysvars", + "instructions": [ + { + "name": "sysvars", + "accounts": [ + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "stakeHistory", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/idls/tictactoe.json b/basics/anchorpy-main/tests/idls/tictactoe.json new file mode 100644 index 0000000..507f863 --- /dev/null +++ b/basics/anchorpy-main/tests/idls/tictactoe.json @@ -0,0 +1,179 @@ +{ + "version": "0.1.0", + "name": "tic_tac_toe", + "instructions": [ + { + "name": "setupGame", + "accounts": [ + { + "name": "game", + "isMut": true, + "isSigner": true + }, + { + "name": "playerOne", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "playerTwo", + "type": "publicKey" + } + ] + }, + { + "name": "play", + "accounts": [ + { + "name": "game", + "isMut": true, + "isSigner": false + }, + { + "name": "player", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "tile", + "type": { + "defined": "Tile" + } + } + ] + } + ], + "accounts": [ + { + "name": "Game", + "type": { + "kind": "struct", + "fields": [ + { + "name": "players", + "type": { + "array": ["publicKey", 2] + } + }, + { + "name": "turn", + "type": "u8" + }, + { + "name": "board", + "type": { + "array": [ + { + "array": [ + { + "option": { + "defined": "Sign" + } + }, + 3 + ] + }, + 3 + ] + } + }, + { + "name": "state", + "type": { + "defined": "GameState" + } + } + ] + } + } + ], + "types": [ + { + "name": "Tile", + "type": { + "kind": "struct", + "fields": [ + { + "name": "row", + "type": "u8" + }, + { + "name": "column", + "type": "u8" + } + ] + } + }, + { + "name": "GameState", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Active" + }, + { + "name": "Tie" + }, + { + "name": "Won", + "fields": [ + { + "name": "winner", + "type": "publicKey" + } + ] + } + ] + } + }, + { + "name": "Sign", + "type": { + "kind": "enum", + "variants": [ + { + "name": "X" + }, + { + "name": "O" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "TileOutOfBounds" + }, + { + "code": 6001, + "name": "TileAlreadySet" + }, + { + "code": 6002, + "name": "GameAlreadyOver" + }, + { + "code": 6003, + "name": "NotPlayersTurn" + }, + { + "code": 6004, + "name": "GameAlreadyStarted" + } + ], + "metadata": { + "address": "4V6T2muqU1mHSg5XfK3SMgxZWQRSEUh72LzwGTLHGzsY" + } +} diff --git a/basics/anchorpy-main/tests/idls/typescript.json b/basics/anchorpy-main/tests/idls/typescript.json new file mode 100644 index 0000000..6aa06ab --- /dev/null +++ b/basics/anchorpy-main/tests/idls/typescript.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.0", + "name": "typescript", + "instructions": [ + { + "name": "initialize", + "accounts": [], + "args": [] + } + ] +} \ No newline at end of file diff --git a/basics/anchorpy-main/tests/test_basic_0.py b/basics/anchorpy-main/tests/test_basic_0.py new file mode 100644 index 0000000..6d176ad --- /dev/null +++ b/basics/anchorpy-main/tests/test_basic_0.py @@ -0,0 +1,22 @@ +"""Mimics anchor/examples/tutorial/basic-0/tests/basic-0.js.""" +from pathlib import Path + +from anchorpy import create_workspace +from anchorpy.pytest_plugin import localnet_fixture +from pytest import mark + +PATH = Path("anchor/examples/tutorial/basic-0") + +# We use localnet_fixture here to make sure it works, but use +# workspace_fixture elsewhere. +localnet = localnet_fixture(PATH) + + +@mark.asyncio +async def test_init(localnet) -> None: + """Test that the initialize function is invoked successfully.""" + workspace = create_workspace(PATH) + program = workspace["basic_0"] + res = await program.rpc["initialize"]() + assert res + await program.close() diff --git a/basics/anchorpy-main/tests/test_basic_1.py b/basics/anchorpy-main/tests/test_basic_1.py new file mode 100644 index 0000000..43be062 --- /dev/null +++ b/basics/anchorpy-main/tests/test_basic_1.py @@ -0,0 +1,61 @@ +"""Mimics anchor/examples/tutorial/basic-1.""" + +from anchorpy import Context, Program +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark +from pytest_asyncio import fixture as async_fixture +from solders.keypair import Keypair +from solders.system_program import ID as SYS_PROGRAM_ID + +workspace = workspace_fixture( + "anchor/examples/tutorial/basic-1", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + """Create a Program instance.""" + return workspace["basic_1"] + + +@async_fixture(scope="module") +async def initialized_account(program: Program) -> Keypair: + """Generate a keypair and initialize it.""" + my_account = Keypair() + await program.rpc["initialize"]( + 1234, + ctx=Context( + accounts={ + "my_account": my_account.pubkey(), + "user": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[my_account], + ), + ) + return my_account + + +@mark.asyncio +async def test_create_and_initialize_account( + program: Program, + initialized_account: Keypair, +) -> None: + """Test creating and initializing account in single tx.""" + account = await program.account["MyAccount"].fetch(initialized_account.pubkey()) + assert account.data == 1234 + + +@mark.asyncio +async def test_update_previously_created_account( + initialized_account: Keypair, + program: Program, +) -> None: + """Test updating a previously created account.""" + await program.rpc["update"]( + 4321, + ctx=Context(accounts={"my_account": initialized_account.pubkey()}), + ) + account = await program.account["MyAccount"].fetch(initialized_account.pubkey()) + assert account.data == 4321 diff --git a/basics/anchorpy-main/tests/test_basic_2.py b/basics/anchorpy-main/tests/test_basic_2.py new file mode 100644 index 0000000..0524633 --- /dev/null +++ b/basics/anchorpy-main/tests/test_basic_2.py @@ -0,0 +1,73 @@ +"""Mimics anchor/examples/tutorial/basic-2/tests/basic-2.js.""" + +from anchorpy import Context, Program, Provider +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark +from pytest_asyncio import fixture as async_fixture +from solders.keypair import Keypair +from solders.system_program import ID as SYS_PROGRAM_ID + +workspace = workspace_fixture("anchor/examples/tutorial/basic-2") + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + """Create a Program instance.""" + return workspace["basic_2"] + + +@fixture(scope="module") +def provider(program: Program) -> Provider: + """Get a Provider instance.""" + return program.provider + + +@async_fixture(scope="module") +async def created_counter(program: Program, provider: Provider) -> Keypair: + """Create the counter.""" + counter = Keypair() + await program.rpc["create"]( + provider.wallet.public_key, + ctx=Context( + accounts={ + "counter": counter.pubkey(), + "user": provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[counter], + ), + ) + return counter + + +@mark.asyncio +async def test_create_counter( + created_counter: Keypair, + program: Program, + provider: Provider, +) -> None: + """Test creating a counter.""" + counter_account = await program.account["Counter"].fetch(created_counter.pubkey()) + assert counter_account.authority == provider.wallet.public_key + assert counter_account.count == 0 + + +@mark.asyncio +async def test_update_counter( + created_counter: Keypair, + program: Program, + provider: Provider, +) -> None: + """Test updating the counter.""" + await program.rpc["increment"]( + ctx=Context( + accounts={ + "counter": created_counter.pubkey(), + "authority": provider.wallet.public_key, + }, + ), + ) + counter_account = await program.account["Counter"].fetch(created_counter.pubkey()) + assert counter_account.authority == provider.wallet.public_key + assert counter_account.count == 1 diff --git a/basics/anchorpy-main/tests/test_basic_3.py b/basics/anchorpy-main/tests/test_basic_3.py new file mode 100644 index 0000000..b87b089 --- /dev/null +++ b/basics/anchorpy-main/tests/test_basic_3.py @@ -0,0 +1,49 @@ +"""Mimics anchor/examples/tutorial/basic-3/tests/basic-3.js.""" +from typing import AsyncGenerator + +from anchorpy import Context, Provider +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import mark +from pytest_asyncio import fixture as async_fixture +from solders.keypair import Keypair +from solders.system_program import ID as SYS_PROGRAM_ID + +workspace = workspace_fixture("anchor/examples/tutorial/basic-3") + + +@async_fixture(scope="module") +async def provider() -> AsyncGenerator[Provider, None]: + """Create a Provider instance.""" + prov = Provider.local() + yield prov + await prov.close() + + +@mark.asyncio +async def test_cpi(workspace: WorkspaceType, provider: Provider) -> None: + """Test CPI from puppet master to puppet.""" + puppet_master = workspace["puppet_master"] + puppet = workspace["puppet"] + new_puppet_account = Keypair() + await puppet.rpc["initialize"]( + ctx=Context( + accounts={ + "puppet": new_puppet_account.pubkey(), + "user": provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[new_puppet_account], + ), + ) + await puppet_master.rpc["pull_strings"]( + 111, + ctx=Context( + accounts={ + "puppet": new_puppet_account.pubkey(), + "puppet_program": puppet.program_id, + }, + ), + ) + puppet_account = await puppet.account["Data"].fetch(new_puppet_account.pubkey()) + assert puppet_account.data == 111 diff --git a/basics/anchorpy-main/tests/test_basic_3_bankrun.py b/basics/anchorpy-main/tests/test_basic_3_bankrun.py new file mode 100644 index 0000000..2ba38a1 --- /dev/null +++ b/basics/anchorpy-main/tests/test_basic_3_bankrun.py @@ -0,0 +1,63 @@ +"""Mimics anchor/examples/tutorial/basic-3/tests/basic-3.js.""" +from pathlib import Path +from typing import AsyncGenerator + +from anchorpy import Context +from anchorpy.pytest_plugin import bankrun_fixture +from anchorpy.workspace import WorkspaceType, close_workspace, create_workspace +from pytest import mark +from pytest_asyncio import fixture as async_fixture +from solders.bankrun import ProgramTestContext +from solders.keypair import Keypair +from solders.system_program import ID as SYS_PROGRAM_ID + +PATH = Path("anchor/examples/tutorial/basic-3") + +bankrun = bankrun_fixture(PATH) + + +@async_fixture(scope="module") +async def workspace(bankrun: ProgramTestContext) -> AsyncGenerator[WorkspaceType, None]: + ws = create_workspace(PATH) + yield ws + await close_workspace(ws) + + +@mark.asyncio +async def test_cpi(workspace: WorkspaceType, bankrun: ProgramTestContext) -> None: + """Test CPI from puppet master to puppet.""" + puppet_master = workspace["puppet_master"] + puppet = workspace["puppet"] + new_puppet_account = Keypair() + payer = bankrun.payer + blockhash = bankrun.last_blockhash + client = bankrun.banks_client + tx0 = puppet.transaction["initialize"]( + payer=payer, + blockhash=blockhash, + ctx=Context( + accounts={ + "puppet": new_puppet_account.pubkey(), + "user": payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + signers=[new_puppet_account], + ), + ) + await client.process_transaction(tx0) + tx1 = puppet_master.transaction["pull_strings"]( + 111, + payer=payer, + blockhash=blockhash, + ctx=Context( + accounts={ + "puppet": new_puppet_account.pubkey(), + "puppet_program": puppet.program_id, + }, + ), + ) + await client.process_transaction(tx1) + puppet_account_raw = await client.get_account(new_puppet_account.pubkey()) + assert puppet_account_raw is not None + decoded = puppet.account["Data"].coder.accounts.decode(puppet_account_raw.data) + assert decoded.data == 111 diff --git a/basics/anchorpy-main/tests/test_chat.py b/basics/anchorpy-main/tests/test_chat.py new file mode 100644 index 0000000..8af7c17 --- /dev/null +++ b/basics/anchorpy-main/tests/test_chat.py @@ -0,0 +1,130 @@ +import random +import string + +from anchorpy import Context, Program, Provider +from anchorpy.pytest_plugin import workspace_fixture +from pytest import fixture, mark +from pytest_asyncio import fixture as async_fixture +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.sysvar import RENT + +workspace = workspace_fixture( + "anchor/tests/chat/", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace) -> Program: + """Create a Program instance.""" + return workspace["chat"] + + +@fixture(scope="module") +async def provider(program: Program) -> Provider: + """Get a Provider instance.""" + return program.provider + + +@async_fixture(scope="module") +async def created_chatroom(program: Program) -> Keypair: + chatroom = Keypair() + await program.rpc["create_chat_room"]( + "Test Chat", + ctx=Context( + accounts={ + "chat_room": chatroom.pubkey(), + "rent": RENT, + }, + pre_instructions=[ + await program.account["ChatRoom"].create_instruction(chatroom), + ], + signers=[chatroom], + ), + ) + return chatroom + + +@async_fixture(scope="module") +async def created_user( + created_chatroom: Keypair, program: Program +) -> tuple[Pubkey, Pubkey]: + authority = program.provider.wallet.public_key + user, bump = Pubkey.find_program_address([bytes(authority)], program.program_id) + await program.rpc["create_user"]( + "My User", + ctx=Context( + accounts={ + "user": user, + "authority": authority, + "system_program": SYS_PROGRAM_ID, + } + ), + ) + return user, authority + + +@async_fixture(scope="module") +async def sent_messages( + created_user: tuple[Pubkey, Pubkey], + created_chatroom: Keypair, + program: Program, +) -> list[str]: + user, authority = created_user + num_messages = 10 + to_choose = string.ascii_uppercase + string.digits + messages = ["".join(random.choices(to_choose, k=13)) for _ in range(num_messages)] + for i, msg in enumerate(messages): + print(f"sending message {i}") + await program.rpc["send_message"]( + msg, + ctx=Context( + accounts={ + "user": user, + "authority": authority, + "chat_room": created_chatroom.pubkey(), + }, + ), + ) + return messages + + +@mark.asyncio +async def test_created_chatroom(created_chatroom: Keypair, program: Program) -> None: + chat = await program.account["ChatRoom"].fetch(created_chatroom.pubkey()) + name = bytes(chat.name).rstrip(b"\x00").decode("utf-8") + assert name == "Test Chat" + assert len(chat.messages) == 33607 + assert chat.head == 0 + assert chat.tail == 0 + + +@mark.asyncio +async def test_created_user( + created_user: tuple[Pubkey, Pubkey], + program: Program, +) -> None: + user, authority = created_user + account = await program.account["User"].fetch(user) + assert account.name == "My User" + assert account.authority == authority + + +@mark.asyncio +async def test_sent_messages( + program: Program, + created_chatroom: Keypair, + sent_messages: list[str], + created_user: tuple[Pubkey, Pubkey], +) -> None: + user, _ = created_user + chat = await program.account["ChatRoom"].fetch(created_chatroom.pubkey()) + for i, msg in enumerate(chat.messages): + if i < len(sent_messages): + data = bytes(msg.data).rstrip(b"\x00").decode("utf-8") + print(f"Message {data}") + assert msg.from_ == user + assert data == sent_messages[i] + else: + assert msg.data == [0] * 280 diff --git a/basics/anchorpy-main/tests/test_cli.py b/basics/anchorpy-main/tests/test_cli.py new file mode 100644 index 0000000..7e964de --- /dev/null +++ b/basics/anchorpy-main/tests/test_cli.py @@ -0,0 +1,29 @@ +"""Test that the CLI commands work.""" + +from pathlib import Path + +from anchorpy import localnet_fixture +from anchorpy.cli import app +from solana.rpc.api import Client +from solana.rpc.commitment import Processed +from solders.signature import Signature +from typer.testing import CliRunner + +PATH = Path("anchor/examples/tutorial/basic-0") + +localnet = localnet_fixture(PATH) + +runner = CliRunner() + + +def test_shell(localnet, monkeypatch) -> None: + monkeypatch.chdir("anchor/examples/tutorial/basic-0") + cli_input = "await workspace['basic_0'].rpc['initialize']()\nexit()" + result = runner.invoke(app, ["shell"], input=cli_input) + assert result.exit_code == 0 + assert "Hint: type `workspace`" in result.stdout + tx_sig = Signature.from_string( + result.stdout.split("Out[1]: \n")[1].split("\n ")[1].split(",")[0] + ) + client = Client() + client.confirm_transaction(tx_sig, commitment=Processed) diff --git a/basics/anchorpy-main/tests/test_cli_init.py b/basics/anchorpy-main/tests/test_cli_init.py new file mode 100644 index 0000000..84aed56 --- /dev/null +++ b/basics/anchorpy-main/tests/test_cli_init.py @@ -0,0 +1,25 @@ +import subprocess +from pathlib import Path + +from pytest import fixture + +PATH = Path("anchor/examples/tutorial/basic-0") +PROJECT_NAME = "foo" + + +@fixture(scope="session") +def project_parent_dir(tmpdir_factory) -> Path: + return Path(tmpdir_factory.mktemp("temp")) + + +@fixture(scope="session") +def project_dir(project_parent_dir: Path) -> Path: + subprocess.run(["anchor", "init", PROJECT_NAME], cwd=project_parent_dir, check=True) + proj_dir = project_parent_dir / PROJECT_NAME + subprocess.run(["anchor", "build"], cwd=proj_dir, check=True) + subprocess.run(["anchorpy", "init", PROJECT_NAME], cwd=proj_dir, check=True) + return proj_dir + + +def test_init(project_dir: Path): + subprocess.run("pytest", cwd=project_dir, check=True) diff --git a/basics/anchorpy-main/tests/test_composite.py b/basics/anchorpy-main/tests/test_composite.py new file mode 100644 index 0000000..a1e70ce --- /dev/null +++ b/basics/anchorpy-main/tests/test_composite.py @@ -0,0 +1,70 @@ +"""Mimics anchor/tests/composite/tests/composite.js.""" +from anchorpy import Context, Program +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark +from pytest_asyncio import fixture as async_fixture +from solders.keypair import Keypair +from solders.sysvar import RENT + +workspace = workspace_fixture( + "anchor/tests/composite/", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + """Create a Program instance.""" + return workspace["composite"] + + +@async_fixture(scope="module") +async def initialized_accounts(program: Program) -> tuple[Keypair, Keypair]: + """Generate keypairs and use them when callling the initialize function.""" + dummy_a = Keypair() + dummy_b = Keypair() + await program.rpc["initialize"]( + ctx=Context( + accounts={ + "dummy_a": dummy_a.pubkey(), + "dummy_b": dummy_b.pubkey(), + "rent": RENT, + }, + signers=[dummy_a, dummy_b], + pre_instructions=[ + await program.account["DummyA"].create_instruction(dummy_a), + await program.account["DummyB"].create_instruction(dummy_b), + ], + ), + ) + return dummy_a, dummy_b + + +@async_fixture(scope="module") +async def composite_updated_accounts( + program: Program, + initialized_accounts: tuple[Keypair, Keypair], +) -> tuple[Keypair, Keypair]: + """Run composite_update and return the keypairs used.""" + dummy_a, dummy_b = initialized_accounts + ctx = Context( + accounts={ + "foo": {"dummy_a": dummy_a.pubkey()}, + "bar": {"dummy_b": dummy_b.pubkey()}, + }, + ) + await program.rpc["composite_update"](1234, 4321, ctx=ctx) + return initialized_accounts + + +@mark.asyncio +async def test_composite_update( + program: Program, + composite_updated_accounts: tuple[Keypair, Keypair], +) -> None: + """Test that the call to composite_update worked.""" + dummy_a, dummy_b = composite_updated_accounts + dummy_a_account = await program.account["DummyA"].fetch(dummy_a.pubkey()) + dummy_b_account = await program.account["DummyB"].fetch(dummy_b.pubkey()) + assert dummy_a_account.data == 1234 + assert dummy_b_account.data == 4321 diff --git a/basics/anchorpy-main/tests/test_errors.py b/basics/anchorpy-main/tests/test_errors.py new file mode 100644 index 0000000..5ab5721 --- /dev/null +++ b/basics/anchorpy-main/tests/test_errors.py @@ -0,0 +1,139 @@ +"""Mimics anchor/tests/errors/tests/errors.js.""" +from anchorpy import Context, Program +from anchorpy.error import ProgramError +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark, raises +from solana.rpc.core import RPCNoResultException +from solana.transaction import Transaction +from solders.instruction import AccountMeta, Instruction +from solders.keypair import Keypair +from solders.sysvar import RENT + +workspace = workspace_fixture( + "anchor/tests/errors/", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + return workspace["errors"] + + +@mark.asyncio +async def test_hello_err(program: Program) -> None: + """Test error from hello func.""" + with raises(ProgramError) as excinfo: + await program.rpc["hello"]() + assert excinfo.value.code == 6000 + expected_msg = "This is an error message clients will automatically display" + assert excinfo.value.msg == expected_msg + assert expected_msg in str(excinfo) + assert excinfo.value.logs + + +@mark.asyncio +async def test_hello_no_msg_err(program: Program) -> None: + """Test error from helloNoMsg func.""" + with raises(ProgramError) as excinfo: + await program.rpc["hello_no_msg"]() + assert excinfo.value.msg == "HelloNoMsg" + assert excinfo.value.code == 6000 + 123 + assert excinfo.value.logs + + +@mark.asyncio +async def test_hello_next_err(program: Program) -> None: + """Test error from helloNext func.""" + with raises(ProgramError) as excinfo: + await program.rpc["hello_next"]() + assert excinfo.value.msg == "HelloNext" + assert excinfo.value.code == 6000 + 124 + assert excinfo.value.logs + + +@mark.asyncio +async def test_mut_err(program: Program) -> None: + """Test mmut error.""" + with raises(ProgramError) as excinfo: + await program.rpc["mut_error"](ctx=Context(accounts={"my_account": RENT})) + assert excinfo.value.msg == "A mut constraint was violated" + assert excinfo.value.code == 2000 + assert excinfo.value.logs + + +@mark.asyncio +async def test_has_one_err(program: Program) -> None: + """Test hasOneError.""" + account = Keypair() + with raises(ProgramError) as excinfo: + await program.rpc["has_one_error"]( + ctx=Context( + accounts={ + "my_account": account.pubkey(), + "owner": RENT, + "rent": RENT, + }, + pre_instructions=[ + await program.account["HasOneAccount"].create_instruction(account) + ], + signers=[account], + ) + ) + assert excinfo.value.msg == "A has_one constraint was violated" + assert excinfo.value.code == 2001 + assert excinfo.value.logs + + +@mark.asyncio +async def test_signer_err(program: Program) -> None: + """Test signer error.""" + tx = Transaction() + tx.add( + Instruction( + accounts=[ + AccountMeta( + pubkey=RENT, + is_writable=False, + is_signer=False, + ), + ], + program_id=program.program_id, + data=program.coder.instruction.encode("signer_error", {}), + ), + ) + with raises(RPCNoResultException): + await program.provider.send(tx) + + +@mark.asyncio +async def test_raw_custom_err(program: Program) -> None: + with raises(ProgramError) as excinfo: + await program.rpc["raw_custom_error"]( + ctx=Context( + accounts={ + "my_account": RENT, + }, + ) + ) + assert excinfo.value.msg == "HelloCustom" + assert excinfo.value.code == 6000 + 125 + assert excinfo.value.logs + + +@mark.asyncio +async def test_account_not_initialised_err(program: Program) -> None: + with raises(ProgramError) as excinfo: + await program.rpc["account_not_initialized_error"]( + ctx=Context( + accounts={ + "not_initialized_account": Keypair().pubkey(), + }, + ) + ) + assert ( + excinfo.value.msg + == "The program expected this account to be already initialized" + ) + assert excinfo.value.code == 3012 + assert excinfo.value.logs diff --git a/basics/anchorpy-main/tests/test_events.py b/basics/anchorpy-main/tests/test_events.py new file mode 100644 index 0000000..3cf25dd --- /dev/null +++ b/basics/anchorpy-main/tests/test_events.py @@ -0,0 +1,43 @@ +"""Mimics anchor/tests/errors/tests/events.js. + +Note: this is unfinished. +""" +from typing import cast + +from anchorpy import ( + EventParser, + Program, +) +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark +from solana.rpc.websocket_api import SolanaWsClientProtocol, connect +from solders.rpc.config import RpcTransactionLogsFilter +from solders.rpc.responses import LogsNotification + +workspace = workspace_fixture( + "anchor/tests/events/", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + return workspace["events"] + + +@mark.asyncio +async def test_initialize(program: Program) -> None: + async with cast(SolanaWsClientProtocol, connect()) as websocket: # type: ignore + await websocket.logs_subscribe(RpcTransactionLogsFilter.All) + await websocket.recv() + await program.rpc["initialize"]() + received = await websocket.recv() + first = received[0] + assert isinstance(first, LogsNotification) + logs = first.result.value.logs + parser = EventParser(program.program_id, program.coder) + parsed = [] + parser.parse_logs(logs, lambda evt: parsed.append(evt)) + event = parsed[0] + assert event.data.data == 5 + assert event.data.label == "hello" diff --git a/basics/anchorpy-main/tests/test_misc.py b/basics/anchorpy-main/tests/test_misc.py new file mode 100644 index 0000000..56a5458 --- /dev/null +++ b/basics/anchorpy-main/tests/test_misc.py @@ -0,0 +1,234 @@ +"""Mimics anchor/tests/misc/tests/misc.js.""" +import asyncio +import subprocess +from pathlib import Path + +from anchorpy import Context, Program +from anchorpy.error import ProgramError +from anchorpy.provider import Provider, Wallet +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.utils.rpc import invoke +from anchorpy.workspace import WorkspaceType +from anchorpy_core.idl import IdlConst, IdlTypeSimple +from pytest import fixture, mark, raises +from pytest_asyncio import fixture as async_fixture +from solana.rpc.core import RPCNoResultException +from solana.rpc.types import MemcmpOpts +from solders.keypair import Keypair +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.sysvar import RENT + +PATH = Path("anchor/tests/misc/") +# bankrun = bankrun_fixture(PATH, build_cmd="anchor build --skip-lint") +workspace = workspace_fixture(PATH, build_cmd="anchor build --skip-lint") + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + return workspace["misc"] + + +def test_idl_constants(program: Program) -> None: + idl_constants = program.idl.constants + assert idl_constants == [ + IdlConst(name="BASE", ty=IdlTypeSimple.U128, value="1_000_000"), + IdlConst(name="DECIMALS", ty=IdlTypeSimple.U8, value="6"), + ] + + +def test_methods(program: Program, initialized_keypair: Keypair) -> None: + ix_from_methods = ( + program.methods["test_close"] + .accounts( + { + "data": initialized_keypair.pubkey(), + "sol_dest": initialized_keypair.pubkey(), + } + ) + .instruction() + ) + ix_legacy = program.instruction["test_close"]( + ctx=Context( + accounts={ + "data": initialized_keypair.pubkey(), + "sol_dest": initialized_keypair.pubkey(), + }, + ) + ) + assert ix_from_methods == ix_legacy + + +@mark.asyncio +async def test_at_constructor(program: Program) -> None: + """Test that the Program.at classmethod works.""" + idl_path = "target/idl/misc.json" + subprocess.run( + ["anchor", "idl", "init", "-f", idl_path, str(program.program_id)], + cwd=PATH, + ) + fetched = await program.at(program.program_id, program.provider) + await fetched.close() + assert fetched.idl.name == "misc" + + +@async_fixture(scope="module") +async def initialized_keypair(program: Program) -> Keypair: + data = Keypair() + await program.rpc["initialize"]( + 1234, + 22, + ctx=Context( + accounts={"data": data.pubkey(), "rent": RENT}, + signers=[data], + pre_instructions=[await program.account["Data"].create_instruction(data)], + ), + ) + return data + + +@mark.asyncio +async def test_readonly_provider( + program: Program, initialized_keypair: Keypair +) -> None: + async with Provider.readonly() as provider: + readonly_program = Program(program.idl, program.program_id, provider=provider) + data_account = await readonly_program.account["Data"].fetch( + initialized_keypair.pubkey() + ) + assert data_account.udata == 1234 + assert data_account.idata == 22 + + +@mark.asyncio +async def test_fetch_multiple(program: Program, initialized_keypair: Keypair) -> None: + batch_size = 2 + n_accounts = batch_size * 100 + 1 + data_account = await program.account["Data"].fetch(initialized_keypair.pubkey()) + pubkeys = [initialized_keypair.pubkey()] * n_accounts + data_accounts = await program.account["Data"].fetch_multiple( + pubkeys, batch_size=batch_size + ) + assert len(data_accounts) == n_accounts + assert all(acc == data_account for acc in data_accounts) + + +@mark.asyncio +async def test_can_use_executable_attribute(program: Program) -> None: + await program.rpc["test_executable"]( + ctx=Context(accounts={"program": program.program_id}), + ) + # sleep so we don't get AlreadyProcessed error + await asyncio.sleep(10) + with raises(ProgramError): + await program.rpc["test_executable"]( + ctx=Context(accounts={"program": program.provider.wallet.public_key}), + ) + + +@mark.asyncio +async def test_can_execute_fallback_function(program: Program) -> None: + with raises(RPCNoResultException) as excinfo: + await invoke(program.program_id, program.provider) + assert ( + "Transaction failed to sanitize accounts offsets correctly" + in excinfo.value.args[0] + ) + + +@mark.asyncio +async def test_can_fetch_all_accounts_of_a_given_type( + program: Program, event_loop +) -> None: + # Initialize the accounts. + data1 = Keypair() + data2 = Keypair() + data3 = Keypair() + data4 = Keypair() + # Initialize filterable data. + filterable1 = Keypair().pubkey() + filterable2 = Keypair().pubkey() + provider = Provider( + program.provider.connection, + Wallet(Keypair()), + program.provider.opts, + ) + another_program = Program(program.idl, program.program_id, provider) + lamports_per_sol = 1000000000 + tx_res = await program.provider.connection.request_airdrop( + another_program.provider.wallet.public_key, + lamports_per_sol, + ) + signature = tx_res.value + await program.provider.connection.confirm_transaction(signature) + # Create all the accounts. + tasks = [ + program.rpc["test_fetch_all"]( + filterable1, + ctx=Context( + accounts={ + "data": data1.pubkey(), + "authority": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[data1], + ), + ), + program.rpc["test_fetch_all"]( + filterable1, + ctx=Context( + accounts={ + "data": data2.pubkey(), + "authority": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[data2], + ), + ), + program.rpc["test_fetch_all"]( + filterable2, + ctx=Context( + accounts={ + "data": data3.pubkey(), + "authority": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[data3], + ), + ), + another_program.rpc["test_fetch_all"]( + filterable1, + ctx=Context( + accounts={ + "data": data4.pubkey(), + "authority": another_program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[data4], + ), + ), + ] + await asyncio.wait([event_loop.create_task(t) for t in tasks]) + all_accounts = await program.account["DataWithFilter"].all() + all_accounts_filtered_by_bytes = await program.account["DataWithFilter"].all( + bytes(program.provider.wallet.public_key), + ) + all_accounts_filtered_by_program_filters1 = await program.account[ + "DataWithFilter" + ].all( + filters=[ + MemcmpOpts(offset=8, bytes=str(program.provider.wallet.public_key)), + MemcmpOpts(offset=40, bytes=str(filterable1)), + ], + ) + all_accounts_filtered_by_program_filters2 = await program.account[ + "DataWithFilter" + ].all( + filters=[ + MemcmpOpts(offset=8, bytes=str(program.provider.wallet.public_key)), + MemcmpOpts(offset=40, bytes=str(filterable2)), + ], + ) + assert len(all_accounts) == 4 + assert len(all_accounts_filtered_by_bytes) == 3 + assert len(all_accounts_filtered_by_program_filters1) == 2 + assert len(all_accounts_filtered_by_program_filters2) == 1 diff --git a/basics/anchorpy-main/tests/test_misc_core.py b/basics/anchorpy-main/tests/test_misc_core.py new file mode 100644 index 0000000..cb09d1e --- /dev/null +++ b/basics/anchorpy-main/tests/test_misc_core.py @@ -0,0 +1,686 @@ +"""Mimics anchor/tests/misc/tests/misc.js.""" +from pathlib import Path + +from anchorpy import Context, Program +from anchorpy.error import ProgramError +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark, raises +from pytest_asyncio import fixture as async_fixture +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.system_program import TransferParams, transfer +from solders.sysvar import RENT +from spl.token.async_client import AsyncToken +from spl.token.constants import TOKEN_PROGRAM_ID + +PATH = Path("anchor/tests/misc/") +workspace = workspace_fixture(PATH, build_cmd="anchor build --skip-lint") + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + return workspace["misc"] + + +@fixture(scope="module") +def misc2program(workspace: WorkspaceType) -> Program: + return workspace["misc2"] + + +@async_fixture(scope="module") +async def initialized_keypair(program: Program) -> Keypair: + data = Keypair() + await program.rpc["initialize"]( + 1234, + 22, + ctx=Context( + accounts={"data": data.pubkey(), "rent": RENT}, + signers=[data], + pre_instructions=[await program.account["Data"].create_instruction(data)], + ), + ) + return data + + +@mark.asyncio +async def test_can_use_u128_and_i128( + program: Program, initialized_keypair: Keypair +) -> None: + data_account = await program.account["Data"].fetch(initialized_keypair.pubkey()) + assert data_account.udata == 1234 + assert data_account.idata == 22 + + +@async_fixture(scope="module") +async def keypair_after_test_u16(program: Program) -> Keypair: + data = Keypair() + await program.rpc["test_u16"]( + 99, + ctx=Context( + accounts={"my_account": data.pubkey(), "rent": RENT}, + signers=[data], + pre_instructions=[ + await program.account["DataU16"].create_instruction(data) + ], + ), + ) + return data + + +@mark.asyncio +async def test_can_use_u16( + program: Program, + keypair_after_test_u16: Keypair, +) -> None: + data_account = await program.account["DataU16"].fetch( + keypair_after_test_u16.pubkey(), + ) + assert data_account.data == 99 + + +@mark.asyncio +async def test_can_use_owner_constraint( + program: Program, initialized_keypair: Keypair +) -> None: + await program.rpc["test_owner"]( + ctx=Context( + accounts={ + "data": initialized_keypair.pubkey(), + "misc": program.program_id, + }, + ), + ) + with raises(ProgramError): + await program.rpc["test_owner"]( + ctx=Context( + accounts={ + "data": program.provider.wallet.public_key, + "misc": program.program_id, + }, + ), + ) + + +@mark.asyncio +async def test_can_retrieve_events_when_simulating_transaction( + program: Program, +) -> None: + resp = await program.simulate["test_simulate"](44) + expected_raw_first_entry = ( + "Program 3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh invoke [1]" + ) + events = resp.events + assert resp.raw[0] == expected_raw_first_entry + assert events[0].name == "E1" + assert events[0].data.data == 44 + assert events[1].name == "E2" + assert events[1].data.data == 1234 + assert events[2].name == "E3" + assert events[2].data.data == 9 + + +@mark.asyncio +async def test_can_use_i8_in_idl(program: Program) -> None: + data = Keypair() + await program.rpc["test_i8"]( + -3, + ctx=Context( + accounts={"data": data.pubkey(), "rent": RENT}, + pre_instructions=[await program.account["DataI8"].create_instruction(data)], + signers=[data], + ), + ) + data_account = await program.account["DataI8"].fetch(data.pubkey()) + assert data_account.data == -3 + + +@async_fixture(scope="module") +async def data_i16_keypair(program: Program) -> Keypair: + data = Keypair() + await program.rpc["test_i16"]( + -2048, + ctx=Context( + accounts={"data": data.pubkey(), "rent": RENT}, + pre_instructions=[ + await program.account["DataI16"].create_instruction(data) + ], + signers=[data], + ), + ) + return data + + +@mark.asyncio +async def test_can_use_i16_in_idl(program: Program, data_i16_keypair: Keypair) -> None: + data_account = await program.account["DataI16"].fetch(data_i16_keypair.pubkey()) + assert data_account.data == -2048 + + +@mark.asyncio +async def test_fail_to_close_account_when_sending_lamports_to_itself( + program: Program, + initialized_keypair: Keypair, +) -> None: + with raises(ProgramError) as excinfo: + await program.rpc["test_close"]( + ctx=Context( + accounts={ + "data": initialized_keypair.pubkey(), + "sol_dest": initialized_keypair.pubkey(), + }, + ), + ) + assert excinfo.value.code == 2011 + assert excinfo.value.msg == "A close constraint was violated" + + +@mark.asyncio +async def test_can_close_account( + program: Program, + initialized_keypair: Keypair, +) -> None: + open_account = await program.provider.connection.get_account_info( + initialized_keypair.pubkey(), + ) + assert open_account.value is not None + before_balance_raw = await program.provider.connection.get_account_info( + program.provider.wallet.public_key, + ) + before_balance_res = before_balance_raw.value + assert before_balance_res is not None + before_balance = before_balance_res.lamports + await program.rpc["test_close"]( + ctx=Context( + accounts={ + "data": initialized_keypair.pubkey(), + "sol_dest": program.provider.wallet.public_key, + }, + ), + ) + after_balance_raw = await program.provider.connection.get_account_info( + program.provider.wallet.public_key, + ) + after_balance_res = after_balance_raw.value + assert after_balance_res is not None + after_balance = after_balance_res.lamports + assert after_balance > before_balance + closed_account = await program.provider.connection.get_account_info( + initialized_keypair.pubkey(), + ) + assert closed_account.value is None + + +@mark.asyncio +async def test_can_use_instruction_data_in_accounts_constraints( + program: Program, +) -> None: + seed = b"my-seed" + my_pda, nonce = Pubkey.find_program_address([seed, bytes(RENT)], program.program_id) + await program.rpc["test_instruction_constraint"]( + nonce, + ctx=Context(accounts={"my_pda": my_pda, "my_account": RENT}), + ) + + +@mark.asyncio +async def test_can_create_a_pda_with_instruction_data( + program: Program, +) -> None: + seed = bytes([1, 2, 3, 4]) + domain = "my-domain" + foo = RENT + my_pda, nonce = Pubkey.find_program_address( + [b"my-seed", domain.encode(), bytes(foo), seed], program.program_id + ) + await program.rpc["test_pda_init"]( + domain, + seed, + nonce, + ctx=Context( + accounts={ + "my_pda": my_pda, + "my_payer": program.provider.wallet.public_key, + "foo": foo, + "rent": RENT, + "system_program": SYS_PROGRAM_ID, + } + ), + ) + my_pda_account = await program.account["DataU16"].fetch(my_pda) + assert my_pda_account.data == 6 + + +@mark.asyncio +async def test_can_create_a_zero_copy_pda(program: Program) -> None: + my_pda, nonce = Pubkey.find_program_address([b"my-seed"], program.program_id) + await program.rpc["test_pda_init_zero_copy"]( + ctx=Context( + accounts={ + "my_pda": my_pda, + "my_payer": program.provider.wallet.public_key, + "rent": RENT, + "system_program": SYS_PROGRAM_ID, + }, + ), + ) + my_pda_account = await program.account["DataZeroCopy"].fetch(my_pda) + assert my_pda_account.data == 9 + assert my_pda_account.bump == nonce + + +@mark.asyncio +async def test_can_write_to_a_zero_copy_pda(program: Program) -> None: + my_pda, bump = Pubkey.find_program_address([b"my-seed"], program.program_id) + await program.rpc["test_pda_mut_zero_copy"]( + ctx=Context( + accounts={ + "my_pda": my_pda, + "my_payer": program.provider.wallet.public_key, + }, + ) + ) + my_pda_account = await program.account["DataZeroCopy"].fetch(my_pda) + assert my_pda_account.data == 1234 + assert my_pda_account.bump == bump + + +@mark.asyncio +async def test_can_create_a_token_account_from_seeds_pda(program: Program) -> None: + mint, mint_bump = Pubkey.find_program_address([b"my-mint-seed"], program.program_id) + my_pda, token_bump = Pubkey.find_program_address( + [b"my-token-seed"], program.program_id + ) + await program.rpc["test_token_seeds_init"]( + ctx=Context( + accounts={ + "my_pda": my_pda, + "mint": mint, + "authority": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + "rent": RENT, + "token_program": TOKEN_PROGRAM_ID, + }, + ), + ) + mint_account = AsyncToken( + program.provider.connection, + mint, + TOKEN_PROGRAM_ID, + program.provider.wallet.payer, + ) + account = await mint_account.get_account_info(my_pda) + assert account.is_frozen is False + assert account.is_initialized is True + assert account.amount == 0 + assert account.owner == program.provider.wallet.public_key + assert account.mint == mint + + +@mark.asyncio +async def test_can_init_random_account(program: Program) -> None: + data = Keypair() + await program.rpc["test_init"]( + ctx=Context( + accounts={ + "data": data.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[data], + ), + ) + account = await program.account["DataI8"].fetch(data.pubkey()) + assert account.data == 3 + + +@mark.asyncio +async def test_can_init_random_account_prefunded(program: Program) -> None: + data = Keypair() + await program.rpc["test_init"]( + ctx=Context( + accounts={ + "data": data.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[data], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=program.provider.wallet.public_key, + to_pubkey=data.pubkey(), + lamports=4039280, + ), + ), + ], + ), + ) + account = await program.account["DataI8"].fetch(data.pubkey()) + assert account.data == 3 + + +@mark.asyncio +async def test_can_init_random_zero_copy_account(program: Program) -> None: + data = Keypair() + await program.rpc["test_init_zero_copy"]( + ctx=Context( + accounts={ + "data": data.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + signers=[data], + ), + ) + account = await program.account["DataZeroCopy"].fetch(data.pubkey()) + assert account.data == 10 + assert account.bump == 2 + + +@mark.asyncio +async def test_can_create_random_mint_account( + program: Program, +) -> None: + mint = Keypair() + await program.rpc["test_init_mint"]( + ctx=Context( + accounts={ + "mint": mint.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[mint], + ), + ) + client = AsyncToken( + program.provider.connection, + mint.pubkey(), + TOKEN_PROGRAM_ID, + program.provider.wallet.payer, + ) + mint_account = await client.get_mint_info() + assert mint_account.decimals == 6 + assert mint_account.mint_authority == program.provider.wallet.public_key + assert mint_account.freeze_authority == program.provider.wallet.public_key + + +@async_fixture(scope="module") +async def prefunded_mint(program: Program) -> Keypair: + mint = Keypair() + await program.rpc["test_init_mint"]( + ctx=Context( + accounts={ + "mint": mint.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[mint], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=program.provider.wallet.public_key, + to_pubkey=mint.pubkey(), + lamports=4039280, + ), + ), + ], + ), + ) + return mint + + +@mark.asyncio +async def test_can_create_random_mint_account_prefunded( + program: Program, + prefunded_mint: Keypair, +) -> None: + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + program.provider.wallet.payer, + ) + mint_account = await client.get_mint_info() + assert mint_account.decimals == 6 + assert mint_account.mint_authority == program.provider.wallet.public_key + + +@mark.asyncio +async def test_can_create_random_token_account( + program: Program, + prefunded_mint: Keypair, +) -> None: + token = Keypair() + await program.rpc["test_init_token"]( + ctx=Context( + accounts={ + "token": token.pubkey(), + "mint": prefunded_mint.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[token], + ), + ) + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + program.provider.wallet.payer, + ) + account = await client.get_account_info(token.pubkey()) + assert not account.is_frozen + assert account.amount == 0 + assert account.is_initialized + assert account.owner == program.provider.wallet.public_key + assert account.mint == prefunded_mint.pubkey() + + +@mark.asyncio +async def test_can_create_random_token_account_with_prefunding( + program: Program, + prefunded_mint: Keypair, +) -> None: + token = Keypair() + await program.rpc["test_init_token"]( + ctx=Context( + accounts={ + "token": token.pubkey(), + "mint": prefunded_mint.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[token], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=program.provider.wallet.public_key, + to_pubkey=token.pubkey(), + lamports=4039280, + ), + ) + ], + ), + ) + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + program.provider.wallet.payer, + ) + account = await client.get_account_info(token.pubkey()) + assert not account.is_frozen + assert account.amount == 0 + assert account.is_initialized + assert account.owner == program.provider.wallet.public_key + assert account.mint == prefunded_mint.pubkey() + + +@mark.asyncio +async def test_can_create_random_token_account_with_prefunding_under_rent_exemption( + program: Program, + prefunded_mint: Keypair, +) -> None: + token = Keypair() + await program.rpc["test_init_token"]( + ctx=Context( + accounts={ + "token": token.pubkey(), + "mint": prefunded_mint.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[token], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=program.provider.wallet.public_key, + to_pubkey=token.pubkey(), + lamports=1, + ), + ) + ], + ), + ) + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + program.provider.wallet.payer, + ) + account = await client.get_account_info(token.pubkey()) + assert not account.is_frozen + assert account.amount == 0 + assert account.is_initialized + assert account.owner == program.provider.wallet.public_key + assert account.mint == prefunded_mint.pubkey() + + +@mark.asyncio +async def test_init_multiple_accounts_via_composite_payer(program: Program) -> None: + data1 = Keypair() + data2 = Keypair() + await program.rpc["test_composite_payer"]( + ctx=Context( + accounts={ + "composite": { + "data": data1.pubkey(), + "payer": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + "data": data2.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + signers=[data1, data2], + ) + ) + account1 = await program.account["DataI8"].fetch(data1.pubkey()) + assert account1.data == 1 + + account2 = await program.account["Data"].fetch(data2.pubkey()) + assert account2.udata == 2 + assert account2.idata == 3 + + +@mark.asyncio +async def test_can_create_associated_token_account(program: Program) -> None: + # TODO + pass + + +@mark.asyncio +async def test_can_validate_associated_token_constraints(program: Program) -> None: + # TODO + pass + + +@mark.asyncio +async def test_can_use_pdas_with_empty_seeds(program: Program) -> None: + pda, bump = Pubkey.find_program_address([], program.program_id) + await program.rpc["test_init_with_empty_seeds"]( + ctx=Context( + accounts={ + "pda": pda, + "authority": program.provider.wallet.public_key, + "system_program": SYS_PROGRAM_ID, + }, + ), + ) + await program.rpc["test_empty_seeds_constraint"]( + ctx=Context( + accounts={ + "pda": pda, + }, + ), + ) + pda2, _ = Pubkey.find_program_address( + [b"non-empty"], + program.program_id, + ) + with raises(ProgramError) as excinfo: + await program.rpc["test_empty_seeds_constraint"]( + ctx=Context( + accounts={ + "pda": pda2, + }, + ), + ) + assert excinfo.value.code == 2006 + + +@async_fixture(scope="module") +async def if_needed_acc(program: Program) -> Keypair: + keypair = Keypair() + await program.rpc["test_init_if_needed"]( + 1, + ctx=Context( + accounts={ + "data": keypair.pubkey(), + "system_program": SYS_PROGRAM_ID, + "payer": program.provider.wallet.public_key, + }, + signers=[keypair], + ), + ) + return keypair + + +@mark.asyncio +async def test_can_init_if_needed_a_new_account( + program: Program, + if_needed_acc: Keypair, +) -> None: + account = await program.account["DataU16"].fetch(if_needed_acc.pubkey()) + assert account.data == 1 + + +@mark.asyncio +async def test_can_init_if_needed_a_previously_created_account( + program: Program, + if_needed_acc: Keypair, +) -> None: + await program.rpc["test_init_if_needed"]( + 3, + ctx=Context( + accounts={ + "data": if_needed_acc.pubkey(), + "system_program": SYS_PROGRAM_ID, + "payer": program.provider.wallet.public_key, + }, + signers=[if_needed_acc], + ), + ) + account = await program.account["DataU16"].fetch(if_needed_acc.pubkey()) + assert account.data == 3 diff --git a/basics/anchorpy-main/tests/test_misc_core_bankrun.py b/basics/anchorpy-main/tests/test_misc_core_bankrun.py new file mode 100644 index 0000000..b86d927 --- /dev/null +++ b/basics/anchorpy-main/tests/test_misc_core_bankrun.py @@ -0,0 +1,938 @@ +"""Mimics anchor/tests/misc/tests/misc.js.""" +from pathlib import Path +from typing import Any, AsyncGenerator, Optional + +from anchorpy import Context, Program +from anchorpy.error import ProgramError +from anchorpy.program.context import EMPTY_CONTEXT +from anchorpy.program.core import _parse_idl_errors +from anchorpy.program.event import EventParser +from anchorpy.program.namespace.account import AccountClient +from anchorpy.program.namespace.simulate import SimulateResponse +from anchorpy.pytest_plugin import bankrun_fixture +from anchorpy.workspace import WorkspaceType, close_workspace, create_workspace +from pytest import fixture, mark, raises +from pytest_asyncio import fixture as async_fixture +from solana.rpc.core import RPCException +from solders.account import Account +from solders.bankrun import BanksClientError, ProgramTestContext +from solders.instruction import Instruction +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.rpc.responses import GetAccountInfoResp, RpcResponseContext +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.system_program import ( + CreateAccountParams, + TransferParams, + create_account, + transfer, +) +from solders.sysvar import RENT +from spl.token.async_client import AsyncToken +from spl.token.constants import TOKEN_PROGRAM_ID + +PATH = Path("anchor/tests/misc/") +bankrun = bankrun_fixture(PATH, build_cmd="anchor build --skip-lint") + + +@async_fixture(scope="module") +async def workspace(bankrun: ProgramTestContext) -> AsyncGenerator[WorkspaceType, None]: + ws = create_workspace(PATH) + yield ws + await close_workspace(ws) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + return workspace["misc"] + + +@fixture(scope="module") +def misc2program(workspace: WorkspaceType) -> Program: + return workspace["misc2"] + + +async def bankrun_rpc( + prog: Program, name: str, args: list, ctx: Context, bankrun: ProgramTestContext +) -> None: + recent_blockhash = (await bankrun.banks_client.get_latest_blockhash())[0] + tx = prog.transaction[name]( + *args, payer=bankrun.payer, blockhash=recent_blockhash, ctx=ctx + ) + await bankrun.banks_client.process_transaction(tx) + + +def as_account_info_resp(acc: Optional[Account]) -> GetAccountInfoResp: + return GetAccountInfoResp(acc, RpcResponseContext(0)) + + +async def bankrun_create_instruction( + acc: AccountClient, signer: Keypair, program_id: Pubkey, bankrun: ProgramTestContext +) -> Instruction: + rent = await bankrun.banks_client.get_rent() + space = acc._size + mbre = rent.minimum_balance(space) + return create_account( + CreateAccountParams( + from_pubkey=bankrun.payer.pubkey(), + to_pubkey=signer.pubkey(), + space=space, + lamports=mbre, + owner=program_id, + ) + ) + + +async def bankrun_fetch( + acc: AccountClient, address: Pubkey, bankrun: ProgramTestContext +) -> Any: + raw = await bankrun.banks_client.get_account(address) + assert raw is not None + return acc.coder.accounts.decode(raw.data) + + +async def bankrun_simulate( + prog: Program, name: str, args: list, ctx: Context, bankrun: ProgramTestContext +) -> SimulateResponse: + blockhash = (await bankrun.banks_client.get_latest_blockhash())[0] + tx = prog.transaction[name]( + *args, payer=bankrun.payer, blockhash=blockhash, ctx=ctx + ) + resp = await bankrun.banks_client.simulate_transaction(tx) + resp_err = resp.result + meta = resp.meta + logs = [] if meta is None else meta.log_messages + idl_errors = _parse_idl_errors(prog.idl) + if resp_err is None: + events = [] + if prog.idl.events is not None: + parser = EventParser(prog.program_id, prog.coder) + parser.parse_logs(logs, lambda evt: events.append(evt)) + return SimulateResponse(events, logs) + else: + translated_err = ProgramError.parse_tx_error( + resp_err, idl_errors, prog.program_id, logs + ) + if translated_err is not None: + raise translated_err + raise RPCException(resp_err) + + +@async_fixture(scope="module") +async def initialized_keypair(program: Program, bankrun: ProgramTestContext) -> Keypair: + data = Keypair() + await bankrun_rpc( + program, + "initialize", + [ + 1234, + 22, + ], + ctx=Context( + accounts={"data": data.pubkey(), "rent": RENT}, + signers=[data], + pre_instructions=[ + await bankrun_create_instruction( + program.account["Data"], data, program.program_id, bankrun + ) + ], + ), + bankrun=bankrun, + ) + return data + + +@mark.asyncio +async def test_can_use_u128_and_i128( + program: Program, initialized_keypair: Keypair, bankrun: ProgramTestContext +) -> None: + data_account = await bankrun_fetch( + program.account["Data"], initialized_keypair.pubkey(), bankrun + ) + assert data_account.udata == 1234 + assert data_account.idata == 22 + + +@async_fixture(scope="module") +async def keypair_after_test_u16( + program: Program, bankrun: ProgramTestContext +) -> Keypair: + data = Keypair() + await bankrun_rpc( + program, + "test_u16", + [99], + ctx=Context( + accounts={"my_account": data.pubkey(), "rent": RENT}, + signers=[data], + pre_instructions=[ + await bankrun_create_instruction( + program.account["DataU16"], data, program.program_id, bankrun + ) + ], + ), + bankrun=bankrun, + ) + return data + + +@mark.asyncio +async def test_can_use_u16( + program: Program, + keypair_after_test_u16: Keypair, + bankrun: ProgramTestContext, +) -> None: + data_account = await bankrun_fetch( + program.account["DataU16"], keypair_after_test_u16.pubkey(), bankrun + ) + assert data_account.data == 99 + + +@mark.asyncio +async def test_can_use_owner_constraint( + program: Program, initialized_keypair: Keypair, bankrun: ProgramTestContext +) -> None: + await bankrun_rpc( + program, + "test_owner", + [], + ctx=Context( + accounts={ + "data": initialized_keypair.pubkey(), + "misc": program.program_id, + }, + ), + bankrun=bankrun, + ) + with raises(BanksClientError): + await bankrun_rpc( + program, + "test_owner", + [], + ctx=Context( + accounts={ + "data": bankrun.payer.pubkey(), + "misc": program.program_id, + }, + ), + bankrun=bankrun, + ) + + +@mark.asyncio +async def test_can_retrieve_events_when_simulating_transaction( + program: Program, bankrun: ProgramTestContext +) -> None: + resp = await bankrun_simulate( + program, "test_simulate", [44], ctx=EMPTY_CONTEXT, bankrun=bankrun + ) + expected_raw_first_entry = ( + "Program 3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh invoke [1]" + ) + events = resp.events + assert resp.raw[0] == expected_raw_first_entry + assert events[0].name == "E1" + assert events[0].data.data == 44 + assert events[1].name == "E2" + assert events[1].data.data == 1234 + assert events[2].name == "E3" + assert events[2].data.data == 9 + + +@mark.asyncio +async def test_can_use_i8_in_idl(program: Program, bankrun: ProgramTestContext) -> None: + data = Keypair() + await bankrun_rpc( + program, + "test_i8", + [-3], + ctx=Context( + accounts={"data": data.pubkey(), "rent": RENT}, + pre_instructions=[ + await bankrun_create_instruction( + program.account["DataI8"], data, program.program_id, bankrun + ) + ], + signers=[data], + ), + bankrun=bankrun, + ) + data_account = await bankrun_fetch( + program.account["DataI8"], data.pubkey(), bankrun + ) + assert data_account.data == -3 + + +@async_fixture(scope="module") +async def data_i16_keypair(program: Program, bankrun: ProgramTestContext) -> Keypair: + data = Keypair() + await bankrun_rpc( + program, + "test_i16", + [-2048], + ctx=Context( + accounts={"data": data.pubkey(), "rent": RENT}, + pre_instructions=[ + await bankrun_create_instruction( + program.account["DataI16"], data, program.program_id, bankrun + ) + ], + signers=[data], + ), + bankrun=bankrun, + ) + return data + + +@mark.asyncio +async def test_can_use_i16_in_idl( + program: Program, data_i16_keypair: Keypair, bankrun: ProgramTestContext +) -> None: + data_account = await bankrun_fetch( + program.account["DataI16"], data_i16_keypair.pubkey(), bankrun + ) + assert data_account.data == -2048 + + +@mark.asyncio +async def test_fail_to_close_account_when_sending_lamports_to_itself( + program: Program, + initialized_keypair: Keypair, + bankrun: ProgramTestContext, +) -> None: + with raises(BanksClientError) as excinfo: + await bankrun_rpc( + program, + "test_close", + [], + ctx=Context( + accounts={ + "data": initialized_keypair.pubkey(), + "sol_dest": initialized_keypair.pubkey(), + }, + ), + bankrun=bankrun, + ) + assert "0x7db" in excinfo.value.args[0] + + +@mark.asyncio +async def test_can_close_account( + program: Program, + initialized_keypair: Keypair, + bankrun: ProgramTestContext, +) -> None: + client = bankrun.banks_client + open_account = await client.get_account(initialized_keypair.pubkey()) + assert open_account is not None + before_balance_res = await client.get_account( + bankrun.payer.pubkey(), + ) + assert before_balance_res is not None + before_balance = before_balance_res.lamports + await bankrun_rpc( + program, + "test_close", + [], + ctx=Context( + accounts={ + "data": initialized_keypair.pubkey(), + "sol_dest": bankrun.payer.pubkey(), + }, + ), + bankrun=bankrun, + ) + after_balance_res = await client.get_account( + bankrun.payer.pubkey(), + ) + assert after_balance_res is not None + after_balance = after_balance_res.lamports + assert after_balance > before_balance + closed_account = await client.get_account( + initialized_keypair.pubkey(), + ) + assert closed_account is None + + +@mark.asyncio +async def test_can_use_instruction_data_in_accounts_constraints( + program: Program, bankrun: ProgramTestContext +) -> None: + seed = b"my-seed" + my_pda, nonce = Pubkey.find_program_address([seed, bytes(RENT)], program.program_id) + await bankrun_rpc( + program, + "test_instruction_constraint", + [nonce], + ctx=Context(accounts={"my_pda": my_pda, "my_account": RENT}), + bankrun=bankrun, + ) + + +@mark.asyncio +async def test_can_create_a_pda_with_instruction_data( + program: Program, bankrun: ProgramTestContext +) -> None: + seed = bytes([1, 2, 3, 4]) + domain = "my-domain" + foo = RENT + my_pda, nonce = Pubkey.find_program_address( + [b"my-seed", domain.encode(), bytes(foo), seed], program.program_id + ) + await bankrun_rpc( + program, + "test_pda_init", + [domain, seed, nonce], + ctx=Context( + accounts={ + "my_pda": my_pda, + "my_payer": bankrun.payer.pubkey(), + "foo": foo, + "rent": RENT, + "system_program": SYS_PROGRAM_ID, + } + ), + bankrun=bankrun, + ) + my_pda_account = await bankrun_fetch(program.account["DataU16"], my_pda, bankrun) + assert my_pda_account.data == 6 + + +@mark.asyncio +async def test_can_create_a_zero_copy_pda( + program: Program, bankrun: ProgramTestContext +) -> None: + my_pda, nonce = Pubkey.find_program_address([b"my-seed"], program.program_id) + await bankrun_rpc( + program, + "test_pda_init_zero_copy", + [], + ctx=Context( + accounts={ + "my_pda": my_pda, + "my_payer": bankrun.payer.pubkey(), + "rent": RENT, + "system_program": SYS_PROGRAM_ID, + }, + ), + bankrun=bankrun, + ) + my_pda_account = await bankrun_fetch( + program.account["DataZeroCopy"], my_pda, bankrun + ) + assert my_pda_account.data == 9 + assert my_pda_account.bump == nonce + + +@mark.asyncio +async def test_can_write_to_a_zero_copy_pda( + program: Program, bankrun: ProgramTestContext +) -> None: + my_pda, bump = Pubkey.find_program_address([b"my-seed"], program.program_id) + await bankrun_rpc( + program, + "test_pda_mut_zero_copy", + [], + ctx=Context( + accounts={ + "my_pda": my_pda, + "my_payer": bankrun.payer.pubkey(), + }, + ), + bankrun=bankrun, + ) + my_pda_account = await bankrun_fetch( + program.account["DataZeroCopy"], my_pda, bankrun + ) + assert my_pda_account.data == 1234 + assert my_pda_account.bump == bump + + +@mark.asyncio +async def test_can_create_a_token_account_from_seeds_pda( + program: Program, bankrun: ProgramTestContext +) -> None: + mint, mint_bump = Pubkey.find_program_address([b"my-mint-seed"], program.program_id) + my_pda, token_bump = Pubkey.find_program_address( + [b"my-token-seed"], program.program_id + ) + await bankrun_rpc( + program, + "test_token_seeds_init", + [], + ctx=Context( + accounts={ + "my_pda": my_pda, + "mint": mint, + "authority": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + "rent": RENT, + "token_program": TOKEN_PROGRAM_ID, + }, + ), + bankrun=bankrun, + ) + mint_account = AsyncToken( + program.provider.connection, mint, TOKEN_PROGRAM_ID, bankrun.payer + ) + account_raw = await bankrun.banks_client.get_account(my_pda) + as_acc_info = as_account_info_resp(account_raw) + account = mint_account._create_account_info(as_acc_info) + assert account.is_frozen is False + assert account.is_initialized is True + assert account.amount == 0 + assert account.owner == bankrun.payer.pubkey() + assert account.mint == mint + + +@mark.asyncio +async def test_can_init_random_account( + program: Program, bankrun: ProgramTestContext +) -> None: + data = Keypair() + await bankrun_rpc( + program, + "test_init", + [], + ctx=Context( + accounts={ + "data": data.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + signers=[data], + ), + bankrun=bankrun, + ) + account = await bankrun_fetch(program.account["DataI8"], data.pubkey(), bankrun) + assert account.data == 3 + + +@mark.asyncio +async def test_can_init_random_account_prefunded( + program: Program, bankrun: ProgramTestContext +) -> None: + data = Keypair() + await bankrun_rpc( + program, + "test_init", + [], + ctx=Context( + accounts={ + "data": data.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + signers=[data], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=bankrun.payer.pubkey(), + to_pubkey=data.pubkey(), + lamports=4039280, + ), + ), + ], + ), + bankrun=bankrun, + ) + account = await bankrun_fetch(program.account["DataI8"], data.pubkey(), bankrun) + assert account.data == 3 + + +@mark.asyncio +async def test_can_init_random_zero_copy_account( + program: Program, bankrun: ProgramTestContext +) -> None: + data = Keypair() + await bankrun_rpc( + program, + "test_init_zero_copy", + [], + ctx=Context( + accounts={ + "data": data.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + signers=[data], + ), + bankrun=bankrun, + ) + account = await bankrun_fetch( + program.account["DataZeroCopy"], data.pubkey(), bankrun + ) + assert account.data == 10 + assert account.bump == 2 + + +@mark.asyncio +async def test_can_create_random_mint_account( + program: Program, bankrun: ProgramTestContext +) -> None: + mint = Keypair() + await bankrun_rpc( + program, + "test_init_mint", + [], + ctx=Context( + accounts={ + "mint": mint.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[mint], + ), + bankrun=bankrun, + ) + client = AsyncToken( + program.provider.connection, + mint.pubkey(), + TOKEN_PROGRAM_ID, + bankrun.payer, + ) + mint_acc_raw = await bankrun.banks_client.get_account(client.pubkey) + mint_account = client._create_mint_info(as_account_info_resp(mint_acc_raw)) + assert mint_account.decimals == 6 + assert mint_account.mint_authority == bankrun.payer.pubkey() + assert mint_account.freeze_authority == bankrun.payer.pubkey() + + +@async_fixture(scope="module") +async def prefunded_mint(program: Program, bankrun: ProgramTestContext) -> Keypair: + mint = Keypair() + await bankrun_rpc( + program, + "test_init_mint", + [], + ctx=Context( + accounts={ + "mint": mint.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[mint], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=bankrun.payer.pubkey(), + to_pubkey=mint.pubkey(), + lamports=4039280, + ), + ), + ], + ), + bankrun=bankrun, + ) + return mint + + +@mark.asyncio +async def test_can_create_random_mint_account_prefunded( + program: Program, + prefunded_mint: Keypair, + bankrun: ProgramTestContext, +) -> None: + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + bankrun.payer, + ) + mint_acc_raw = await bankrun.banks_client.get_account(client.pubkey) + mint_account = client._create_mint_info(as_account_info_resp(mint_acc_raw)) + assert mint_account.decimals == 6 + assert mint_account.mint_authority == bankrun.payer.pubkey() + + +@mark.asyncio +async def test_can_create_random_token_account( + program: Program, + prefunded_mint: Keypair, + bankrun: ProgramTestContext, +) -> None: + token = Keypair() + await bankrun_rpc( + program, + "test_init_token", + [], + ctx=Context( + accounts={ + "token": token.pubkey(), + "mint": prefunded_mint.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[token], + ), + bankrun=bankrun, + ) + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + bankrun.payer, + ) + account_raw = await bankrun.banks_client.get_account(token.pubkey()) + account = client._create_account_info(as_account_info_resp(account_raw)) + assert not account.is_frozen + assert account.amount == 0 + assert account.is_initialized + assert account.owner == bankrun.payer.pubkey() + assert account.mint == prefunded_mint.pubkey() + + +@mark.asyncio +async def test_can_create_random_token_account_with_prefunding( + program: Program, + prefunded_mint: Keypair, + bankrun: ProgramTestContext, +) -> None: + token = Keypair() + await bankrun_rpc( + program, + "test_init_token", + [], + ctx=Context( + accounts={ + "token": token.pubkey(), + "mint": prefunded_mint.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[token], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=bankrun.payer.pubkey(), + to_pubkey=token.pubkey(), + lamports=4039280, + ), + ) + ], + ), + bankrun=bankrun, + ) + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + bankrun.payer, + ) + account_raw = await bankrun.banks_client.get_account(token.pubkey()) + account = client._create_account_info(as_account_info_resp(account_raw)) + assert not account.is_frozen + assert account.amount == 0 + assert account.is_initialized + assert account.owner == bankrun.payer.pubkey() + assert account.mint == prefunded_mint.pubkey() + + +@mark.asyncio +async def test_can_create_random_token_account_with_prefunding_under_rent_exemption( + program: Program, + prefunded_mint: Keypair, + bankrun: ProgramTestContext, +) -> None: + token = Keypair() + await bankrun_rpc( + program, + "test_init_token", + [], + ctx=Context( + accounts={ + "token": token.pubkey(), + "mint": prefunded_mint.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + "token_program": TOKEN_PROGRAM_ID, + "rent": RENT, + }, + signers=[token], + pre_instructions=[ + transfer( + TransferParams( + from_pubkey=bankrun.payer.pubkey(), + to_pubkey=token.pubkey(), + lamports=1, + ), + ) + ], + ), + bankrun=bankrun, + ) + client = AsyncToken( + program.provider.connection, + prefunded_mint.pubkey(), + TOKEN_PROGRAM_ID, + bankrun.payer, + ) + account_raw = await bankrun.banks_client.get_account(token.pubkey()) + account = client._create_account_info(as_account_info_resp(account_raw)) + assert not account.is_frozen + assert account.amount == 0 + assert account.is_initialized + assert account.owner == bankrun.payer.pubkey() + assert account.mint == prefunded_mint.pubkey() + + +@mark.asyncio +async def test_init_multiple_accounts_via_composite_payer( + program: Program, bankrun: ProgramTestContext +) -> None: + data1 = Keypair() + data2 = Keypair() + await bankrun_rpc( + program, + "test_composite_payer", + [], + ctx=Context( + accounts={ + "composite": { + "data": data1.pubkey(), + "payer": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + "data": data2.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + signers=[data1, data2], + ), + bankrun=bankrun, + ) + account1 = await bankrun_fetch(program.account["DataI8"], data1.pubkey(), bankrun) + assert account1.data == 1 + + account2 = await bankrun_fetch(program.account["Data"], data2.pubkey(), bankrun) + assert account2.udata == 2 + assert account2.idata == 3 + + +@mark.asyncio +async def test_can_create_associated_token_account( + program: Program, bankrun: ProgramTestContext +) -> None: + # TODO + pass + + +@mark.asyncio +async def test_can_validate_associated_token_constraints( + program: Program, bankrun: ProgramTestContext +) -> None: + # TODO + pass + + +@mark.asyncio +async def test_can_use_pdas_with_empty_seeds( + program: Program, bankrun: ProgramTestContext +) -> None: + pda, bump = Pubkey.find_program_address([], program.program_id) + await bankrun_rpc( + program, + "test_init_with_empty_seeds", + [], + ctx=Context( + accounts={ + "pda": pda, + "authority": bankrun.payer.pubkey(), + "system_program": SYS_PROGRAM_ID, + }, + ), + bankrun=bankrun, + ) + await bankrun_rpc( + program, + "test_empty_seeds_constraint", + [], + ctx=Context( + accounts={ + "pda": pda, + }, + ), + bankrun=bankrun, + ) + pda2, _ = Pubkey.find_program_address( + [b"non-empty"], + program.program_id, + ) + with raises(BanksClientError) as excinfo: + await bankrun_rpc( + program, + "test_empty_seeds_constraint", + [], + ctx=Context( + accounts={ + "pda": pda2, + }, + ), + bankrun=bankrun, + ) + assert "0x7d6" in excinfo.value.args[0] + + +@async_fixture(scope="module") +async def if_needed_acc(program: Program, bankrun: ProgramTestContext) -> Keypair: + keypair = Keypair() + await bankrun_rpc( + program, + "test_init_if_needed", + [1], + ctx=Context( + accounts={ + "data": keypair.pubkey(), + "system_program": SYS_PROGRAM_ID, + "payer": bankrun.payer.pubkey(), + }, + signers=[keypair], + ), + bankrun=bankrun, + ) + return keypair + + +@mark.asyncio +async def test_can_init_if_needed_a_new_account( + program: Program, + if_needed_acc: Keypair, + bankrun: ProgramTestContext, +) -> None: + account = await bankrun_fetch( + program.account["DataU16"], if_needed_acc.pubkey(), bankrun + ) + assert account.data == 1 + + +@mark.asyncio +async def test_can_init_if_needed_a_previously_created_account( + program: Program, + if_needed_acc: Keypair, + bankrun: ProgramTestContext, +) -> None: + await bankrun_rpc( + program, + "test_init_if_needed", + [3], + ctx=Context( + accounts={ + "data": if_needed_acc.pubkey(), + "system_program": SYS_PROGRAM_ID, + "payer": bankrun.payer.pubkey(), + }, + signers=[if_needed_acc], + ), + bankrun=bankrun, + ) + account = await bankrun_fetch( + program.account["DataU16"], if_needed_acc.pubkey(), bankrun + ) + assert account.data == 3 diff --git a/basics/anchorpy-main/tests/test_multisig.py b/basics/anchorpy-main/tests/test_multisig.py new file mode 100644 index 0000000..696c417 --- /dev/null +++ b/basics/anchorpy-main/tests/test_multisig.py @@ -0,0 +1,192 @@ +"""Mimics anchor/tests/multisig.""" +from anchorpy import Context, Program, Provider +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark +from pytest_asyncio import fixture as async_fixture +from solders.instruction import AccountMeta +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.sysvar import RENT + +CreatedMultisig = tuple[Keypair, int, list[Pubkey], int, Pubkey, Keypair, Keypair] +CreatedTransaction = tuple[Keypair, list[dict], bytes, Keypair, Pubkey, list[Pubkey]] + +workspace = workspace_fixture( + "anchor/tests/multisig/", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + """Create a Program instance.""" + return workspace["multisig"] + + +@fixture(scope="module") +def provider(program: Program) -> Provider: + """Get a Provider instance.""" + return program.provider + + +@async_fixture(scope="module") +async def created_multisig(program: Program) -> CreatedMultisig: + """Run the create_multisig RPC function.""" + multisig = Keypair() + multisig_signer, nonce = Pubkey.find_program_address( + [bytes(multisig.pubkey())], program.program_id + ) + multisig_size = 200 + owner_a, owner_b, owner_c = Keypair(), Keypair(), Keypair() + owners = [owner_a.pubkey(), owner_b.pubkey(), owner_c.pubkey()] + threshold = 2 + await program.rpc["create_multisig"]( + owners, + threshold, + nonce, + ctx=Context( + accounts={ + "multisig": multisig.pubkey(), + "rent": RENT, + }, + pre_instructions=[ + await program.account["Multisig"].create_instruction( + multisig, multisig_size + ), + ], + signers=[multisig], + ), + ) + return multisig, nonce, owners, threshold, multisig_signer, owner_a, owner_b + + +@mark.asyncio +async def test_created_multisig( + created_multisig: CreatedMultisig, + program: Program, +) -> None: + multisig, nonce, owners, threshold = created_multisig[:4] + multisig_account = await program.account["Multisig"].fetch(multisig.pubkey()) + assert multisig_account.nonce == nonce + assert multisig_account.threshold == threshold + assert multisig_account.owners == owners + + +@async_fixture(scope="module") +async def created_transaction( + program: Program, + created_multisig: CreatedMultisig, +) -> CreatedTransaction: + owner_d = Keypair() + multisig, _, owners, _, multisig_signer, owner_a, _ = created_multisig + accounts = [ + program.type["TransactionAccount"]( + pubkey=multisig.pubkey(), + is_writable=True, + is_signer=False, + ), + program.type["TransactionAccount"]( + pubkey=multisig_signer, + is_writable=False, + is_signer=True, + ), + ] + new_owners = [*owners[:2], owner_d.pubkey()] + data = program.coder.instruction.encode("set_owners", {"owners": new_owners}) + transaction = Keypair() + tx_size = 1000 + await program.rpc["create_transaction"]( + program.program_id, + accounts, + data, + ctx=Context( + accounts={ + "multisig": multisig.pubkey(), + "transaction": transaction.pubkey(), + "proposer": owner_a.pubkey(), + "rent": RENT, + }, + pre_instructions=[ + await program.account["Transaction"].create_instruction( + transaction, + tx_size, + ), + ], + signers=[transaction, owner_a], + ), + ) + return transaction, accounts, data, multisig, multisig_signer, new_owners + + +@mark.asyncio +async def test_created_transaction( + created_transaction: CreatedTransaction, + program: Program, +) -> None: + transaction, accounts, data, multisig, _, _ = created_transaction + tx_account = await program.account["Transaction"].fetch(transaction.pubkey()) + assert tx_account.program_id == program.program_id + assert tx_account.accounts == accounts + assert tx_account.data == data + assert tx_account.multisig == multisig.pubkey() + assert tx_account.did_execute is False + + +@async_fixture(scope="module") +async def executed_transaction( + program: Program, + created_transaction: CreatedTransaction, + created_multisig: CreatedMultisig, +) -> None: + transaction, _, _, multisig, multisig_signer, _ = created_transaction + owner_b = created_multisig[6] + await program.rpc["approve"]( + ctx=Context( + accounts={ + "multisig": multisig.pubkey(), + "transaction": transaction.pubkey(), + "owner": owner_b.pubkey(), + }, + signers=[owner_b], + ), + ) + remaining_accounts_raw = program.instruction["set_owners"].accounts( + {"multisig": multisig.pubkey(), "multisig_signer": multisig_signer} + ) + with_corrected_signer = [] + for meta in remaining_accounts_raw: + to_append = ( + AccountMeta( + pubkey=meta.pubkey, is_signer=False, is_writable=meta.is_writable + ) + if meta.pubkey == multisig_signer + else meta + ) + with_corrected_signer.append(to_append) + remaining_accounts = with_corrected_signer + [ + AccountMeta(pubkey=program.program_id, is_signer=False, is_writable=False) + ] + ctx = Context( + accounts={ + "multisig": multisig.pubkey(), + "multisig_signer": multisig_signer, + "transaction": transaction.pubkey(), + }, + remaining_accounts=remaining_accounts, + ) + await program.rpc["execute_transaction"](ctx=ctx) + + +@mark.asyncio +async def test_executed_transaction( + created_multisig: CreatedMultisig, + created_transaction: CreatedTransaction, + executed_transaction: None, + program: Program, +) -> None: + multisig, nonce, _, threshold = created_multisig[:4] + new_owners = created_transaction[5] + multisig_account = await program.account["Multisig"].fetch(multisig.pubkey()) + assert multisig_account.nonce == nonce + assert multisig_account.threshold == threshold + assert multisig_account.owners == new_owners diff --git a/basics/anchorpy-main/tests/test_pyth.py b/basics/anchorpy-main/tests/test_pyth.py new file mode 100644 index 0000000..ad5ef28 --- /dev/null +++ b/basics/anchorpy-main/tests/test_pyth.py @@ -0,0 +1,135 @@ +"""Mimics anchor/tests/misc/tests/misc.js.""" +from dataclasses import dataclass + +from anchorpy import Context, Program +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from construct import Int32sl, Int64ul +from pytest import fixture, mark +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.system_program import ( + CreateAccountParams, + create_account, +) + +workspace = workspace_fixture( + "anchor/tests/pyth/", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + return workspace["pyth"] + + +async def create_price_feed( + oracle_program: Program, + init_price: int, + expo: int, +) -> Pubkey: + conf = int((init_price / 10) * 10**-expo) + space = 3312 + mbre_resp = ( + await oracle_program.provider.connection.get_minimum_balance_for_rent_exemption( + space, + ) + ) + collateral_token_feed = Keypair() + await oracle_program.rpc["initialize"]( + int(init_price * 10**-expo), + expo, + conf, + ctx=Context( + accounts={"price": collateral_token_feed.pubkey()}, + signers=[collateral_token_feed], + pre_instructions=[ + create_account( + CreateAccountParams( + from_pubkey=oracle_program.provider.wallet.public_key, + to_pubkey=collateral_token_feed.pubkey(), + space=3312, + lamports=mbre_resp.value, + owner=oracle_program.program_id, + ), + ), + ], + ), + ) + return collateral_token_feed.pubkey() + + +async def set_feed_price( + oracle_program: Program, + new_price: int, + price_feed: Pubkey, +) -> None: + data = await get_feed_data(oracle_program, price_feed) + await oracle_program.rpc["set_price"]( + int(new_price * 10**-data.exponent), + ctx=Context(accounts={"price": price_feed}), + ) + + +@dataclass +class PriceData: + exponent: int + price: int + + +def parse_price_data(data: bytes) -> PriceData: + exponent = Int32sl.parse(data[20:24]) + raw_price = Int64ul.parse(data[208:216]) + price = raw_price * 10**exponent + return PriceData(exponent, price) + + +async def get_feed_data( + oracle_program: Program, + price_feed: Pubkey, +) -> PriceData: + info = await oracle_program.provider.connection.get_account_info( + price_feed, + encoding="base64", + ) + val = info.value + if val is None: + raise ValueError("Account does not exist.") + return parse_price_data(val.data) + + +@mark.asyncio +async def test_initialize(program: Program) -> None: + price = 50000 + price_feed_address = await create_price_feed( + oracle_program=program, + init_price=price, + expo=-6, + ) + feed_data = await get_feed_data(program, price_feed_address) + assert feed_data.price == price + + +@mark.asyncio +async def test_change_feed_price(program: Program) -> None: + price = 50000 + expo = -7 + price_feed_address = await create_price_feed( + oracle_program=program, + init_price=price, + expo=expo, + ) + feed_data_before = await get_feed_data(program, price_feed_address) + assert feed_data_before.price == price + assert feed_data_before.exponent == expo + new_price = 55000 + await set_feed_price(program, new_price, price_feed_address) + feed_data_after = await get_feed_data(program, price_feed_address) + assert feed_data_after.price == new_price + assert feed_data_after.exponent == expo + + +@mark.asyncio +async def test_enum(program: Program) -> None: + corp_act = program.type["CorpAction"] + assert corp_act.NoCorpAct().index == 0 diff --git a/basics/anchorpy-main/tests/test_zero_copy.py b/basics/anchorpy-main/tests/test_zero_copy.py new file mode 100644 index 0000000..4ef96ee --- /dev/null +++ b/basics/anchorpy-main/tests/test_zero_copy.py @@ -0,0 +1,334 @@ +"""Mimics anchor/tests/zero-copy.""" +from pathlib import Path + +from anchorpy import ( + Context, + Program, + Provider, +) +from anchorpy.pytest_plugin import workspace_fixture +from anchorpy.workspace import WorkspaceType +from pytest import fixture, mark, raises +from pytest_asyncio import fixture as async_fixture +from solana.rpc.core import RPCException +from solders.keypair import Keypair +from solders.pubkey import Pubkey +from solders.system_program import ID as SYS_PROGRAM_ID +from solders.sysvar import RENT + +PATH = Path("anchor/tests/zero-copy") +DEFAULT_PUBKEY = Pubkey.from_string("11111111111111111111111111111111") + +workspace = workspace_fixture( + "anchor/tests/zero-copy", build_cmd="anchor build --skip-lint" +) + + +@fixture(scope="module") +def program(workspace: WorkspaceType) -> Program: + return workspace["zero_copy"] + + +@fixture(scope="module") +def program_cpi(workspace: dict[str, Program]) -> Program: + return workspace["zero_cpi"] + + +@async_fixture(scope="module") +async def provider(program: Program) -> Provider: + """Get a Provider instance.""" + print(program.idl) + return program.provider + + +@async_fixture(scope="module") +async def foo(program: Program) -> Keypair: + foo_keypair = Keypair() + await program.rpc["create_foo"]( + ctx=Context( + accounts={ + "foo": foo_keypair.pubkey(), + "authority": program.provider.wallet.public_key, + "rent": RENT, + }, + pre_instructions=[ + await program.account["Foo"].create_instruction(foo_keypair) + ], + signers=[foo_keypair], + ) + ) + return foo_keypair + + +@mark.asyncio +async def test_create_foo(foo: Keypair, provider: Provider, program: Program) -> None: + account = await program.account["Foo"].fetch(foo.pubkey()) + assert account.authority == provider.wallet.public_key + assert account.data == 0 + assert account.second_data == 0 + assert account.second_authority == list(bytes(provider.wallet.public_key)) + + +@async_fixture(scope="module") +async def update_foo(program: Program, foo: Keypair) -> None: + await program.rpc["update_foo"]( + 1234, + ctx=Context( + accounts={ + "foo": foo.pubkey(), + "authority": program.provider.wallet.public_key, + }, + ), + ) + + +@mark.asyncio +async def test_update_foo( + foo: Keypair, provider: Provider, program: Program, update_foo: None +) -> None: + account = await program.account["Foo"].fetch(foo.pubkey()) + assert account.authority == provider.wallet.public_key + assert account.data == 1234 + assert account.second_data == 0 + assert account.second_authority == list(bytes(program.provider.wallet.public_key)) + + +@async_fixture(scope="module") +async def update_foo_second(program: Program, foo: Keypair, update_foo: None) -> None: + await program.rpc["update_foo_second"]( + 55, + ctx=Context( + accounts={ + "foo": foo.pubkey(), + "second_authority": program.provider.wallet.public_key, + }, + ), + ) + + +@mark.asyncio +async def test_update_foo_second( + foo: Keypair, provider: Provider, program: Program, update_foo_second: None +) -> None: + account = await program.account["Foo"].fetch(foo.pubkey()) + assert account.authority == provider.wallet.public_key + assert account.data == 1234 + assert account.second_data == 55 + assert account.second_authority == list(bytes(program.provider.wallet.public_key)) + + +@async_fixture(scope="module") +async def bar( + program: Program, provider: Provider, foo: Keypair, update_foo_second: None +) -> Pubkey: + bar_pubkey = Pubkey.find_program_address( + [bytes(provider.wallet.public_key), bytes(foo.pubkey())], program.program_id + )[0] + await program.rpc["create_bar"]( + ctx=Context( + accounts={ + "bar": bar_pubkey, + "authority": provider.wallet.public_key, + "foo": foo.pubkey(), + "system_program": SYS_PROGRAM_ID, + } + ) + ) + return bar_pubkey + + +@mark.asyncio +async def test_create_bar(provider: Provider, program: Program, bar: Pubkey) -> None: + account = await program.account["Bar"].fetch(bar) + assert account.authority == provider.wallet.public_key + assert account.data == 0 + + +@async_fixture(scope="module") +async def update_associated_zero_copy_account( + program: Program, + provider: Provider, + foo: Keypair, + bar: Pubkey, +) -> None: + await program.rpc["update_bar"]( + 99, + ctx=Context( + accounts={ + "bar": bar, + "authority": program.provider.wallet.public_key, + "foo": foo.pubkey(), + }, + ), + ) + + +@mark.asyncio +async def test_update_associated_zero_copy_account( + provider: Provider, + program: Program, + bar: Pubkey, + update_associated_zero_copy_account: None, +) -> None: + account = await program.account["Bar"].fetch(bar) + assert account.authority == provider.wallet.public_key + assert account.data == 99 + + +@async_fixture(scope="module") +async def check_cpi( + program_cpi: Program, + program: Program, + provider: Provider, + foo: Keypair, + bar: Pubkey, + update_associated_zero_copy_account: None, +) -> None: + await program_cpi.rpc["check_cpi"]( + 1337, + ctx=Context( + accounts={ + "bar": bar, + "authority": provider.wallet.public_key, + "foo": foo.pubkey(), + "zero_copy_program": program.program_id, + }, + ), + ) + + +@mark.asyncio +async def test_check_cpi( + provider: Provider, + program: Program, + bar: Pubkey, + check_cpi: None, +) -> None: + account = await program.account["Bar"].fetch(bar) + assert account.authority == provider.wallet.public_key + assert account.data == 1337 + + +@async_fixture(scope="module") +async def event_q( + program: Program, + check_cpi: None, +) -> Keypair: + event_q_keypair = Keypair() + size = 1000000 + 8 + await program.rpc["create_large_account"]( + ctx=Context( + accounts={ + "event_q": event_q_keypair.pubkey(), + "rent": RENT, + }, + pre_instructions=[ + await program.account["EventQ"].create_instruction( + event_q_keypair, size + ) + ], + signers=[event_q_keypair], + ), + ) + return event_q_keypair + + +@mark.asyncio +async def test_event_q( + program: Program, + event_q: Keypair, +) -> None: + account = await program.account["EventQ"].fetch(event_q.pubkey()) + events = account.events + assert len(events) == 25000 + for event in events: + assert event.from_ == DEFAULT_PUBKEY + assert event.data == 0 + + +@mark.asyncio +async def test_update_event_q( + program: Program, + provider: Provider, + event_q: Keypair, +) -> None: + await program.rpc["update_large_account"]( + 0, + 48, + ctx=Context( + accounts={ + "event_q": event_q.pubkey(), + "from": provider.wallet.public_key, + }, + ), + ) + account = await program.account["EventQ"].fetch(event_q.pubkey()) + events = account.events + assert len(events) == 25000 + for idx, event in enumerate(events): + if idx == 0: + assert event.from_ == provider.wallet.public_key + assert event.data == 48 + else: + assert event.from_ == DEFAULT_PUBKEY + assert event.data == 0 + await program.rpc["update_large_account"]( + 11111, + 1234, + ctx=Context( + accounts={ + "event_q": event_q.pubkey(), + "from": provider.wallet.public_key, + }, + ), + ) + account = await program.account["EventQ"].fetch(event_q.pubkey()) + events = account.events + assert len(events) == 25000 + for idx, event in enumerate(events): + if idx == 0: + assert event.from_ == provider.wallet.public_key + assert event.data == 48 + elif idx == 11111: + assert event.from_ == provider.wallet.public_key + assert event.data == 1234 + else: + assert event.from_ == DEFAULT_PUBKEY + assert event.data == 0 + await program.rpc["update_large_account"]( + 24999, + 99, + ctx=Context( + accounts={ + "event_q": event_q.pubkey(), + "from": provider.wallet.public_key, + }, + ), + ) + account = await program.account["EventQ"].fetch(event_q.pubkey()) + events = account.events + assert len(events) == 25000 + for idx, event in enumerate(events): + if idx == 0: + assert event.from_ == provider.wallet.public_key + assert event.data == 48 + elif idx == 11111: + assert event.from_ == provider.wallet.public_key + assert event.data == 1234 + elif idx == 24999: + assert event.from_ == provider.wallet.public_key + assert event.data == 99 + else: + assert event.from_ == DEFAULT_PUBKEY + assert event.data == 0 + with raises(RPCException): + await program.rpc["update_large_account"]( + 25000, + 99, + ctx=Context( + accounts={ + "event_q": event_q.pubkey(), + "from": provider.wallet.public_key, + }, + ), + ) diff --git a/basics/anchorpy-main/tests/unit/test_accounts_array.py b/basics/anchorpy-main/tests/unit/test_accounts_array.py new file mode 100644 index 0000000..97bf3e0 --- /dev/null +++ b/basics/anchorpy-main/tests/unit/test_accounts_array.py @@ -0,0 +1,30 @@ +from pathlib import Path + +from anchorpy import Idl +from anchorpy.program.namespace.instruction import _accounts_array +from pytest import mark +from solana.transaction import AccountMeta +from solders.keypair import Keypair + + +@mark.unit +def test_accounts_array() -> None: + """Test accounts_array returns expected.""" + raw = Path("tests/idls/composite.json").read_text() + idl = Idl.from_json(raw) + dummy_a = Keypair() + dummy_b = Keypair() + comp_accounts = { + "foo": { + "dummy_a": dummy_a.pubkey(), + }, + "bar": { + "dummy_b": dummy_b.pubkey(), + }, + } + accounts_arg = idl.instructions[1].accounts + acc_arr = _accounts_array(comp_accounts, accounts_arg) + assert acc_arr == [ + AccountMeta(pubkey=dummy_a.pubkey(), is_signer=False, is_writable=True), + AccountMeta(pubkey=dummy_b.pubkey(), is_signer=False, is_writable=True), + ] diff --git a/basics/anchorpy-main/tests/unit/test_accounts_coder.py b/basics/anchorpy-main/tests/unit/test_accounts_coder.py new file mode 100644 index 0000000..906b4e8 --- /dev/null +++ b/basics/anchorpy-main/tests/unit/test_accounts_coder.py @@ -0,0 +1,16 @@ +from pathlib import Path + +from anchorpy import AccountsCoder, Idl +from pytest import mark + + +@mark.unit +def test_accounts_coder() -> None: + """Test accounts coder.""" + raw = Path("tests/idls/basic_1.json").read_text() + idl = Idl.from_json(raw) + raw_acc_data = b"\xf6\x1c\x06W\xfb-2*\xd2\x04\x00\x00\x00\x00\x00\x00" + acc_coder = AccountsCoder(idl) + decoded = acc_coder.parse(raw_acc_data) + encoded = acc_coder.build(decoded) + assert encoded == raw_acc_data diff --git a/basics/anchorpy-main/tests/unit/test_clientgen.py b/basics/anchorpy-main/tests/unit/test_clientgen.py new file mode 100644 index 0000000..7938049 --- /dev/null +++ b/basics/anchorpy-main/tests/unit/test_clientgen.py @@ -0,0 +1,57 @@ +from pathlib import Path + +from anchorpy import Idl +from anchorpy.clientgen.instructions import gen_accounts +from anchorpy.clientgen.types import gen_struct +from genpy import Suite + + +def test_gen_accounts() -> None: + path = Path("tests/idls/composite.json") + raw = path.read_text() + idl = Idl.from_json(raw) + accs = gen_accounts( + "CompositeUpdateAccounts", idl.instructions[1].accounts, gen_pdas=True + )[0] + suite = Suite(accs) + assert str(suite) == ( + " class CompositeUpdateAccounts(typing.TypedDict):" + "\n foo: FooNested" + "\n bar: BarNested" + "\n class FooNested(typing.TypedDict):" + "\n dummy_a: Pubkey" + "\n class BarNested(typing.TypedDict):" + "\n dummy_b: Pubkey" + "\n class FooNested(typing.TypedDict):" + "\n dummy_a: Pubkey" + ) + + +def test_empty_fields() -> None: + path = Path("tests/idls/switchboard_v2.mainnet.06022022.json") + raw = path.read_text() + idl = Idl.from_json(raw) + struct = gen_struct(idl, "AggregatorLockParams", []) + assert str(struct) == ( + "import typing" + "\nfrom dataclasses import dataclass" + "\nfrom construct import Container, Construct" + "\nfrom solders.pubkey import Pubkey" + "\nfrom anchorpy.borsh_extension import BorshPubkey" + "\nimport borsh_construct as borsh" + "\nclass AggregatorLockParamsJSON(typing.TypedDict):" + "\n pass" + "\n@dataclass" + "\nclass AggregatorLockParams():" + "\n layout: typing.ClassVar = borsh.CStruct()" + "\n @classmethod" + '\n def from_decoded(cls, obj: Container) -> "AggregatorLockParams":' + "\n return cls()" + "\n def to_encodable(self) -> dict[str, typing.Any]:" + "\n return {}" + "\n def to_json(self) -> AggregatorLockParamsJSON:" + "\n return {}" + "\n @classmethod" + '\n def from_json(cls, obj: AggregatorLockParamsJSON) -> "AggregatorLockParams":' + "\n return cls()" + ) diff --git a/basics/anchorpy-main/tests/unit/test_event_parser.py b/basics/anchorpy-main/tests/unit/test_event_parser.py new file mode 100644 index 0000000..54debcf --- /dev/null +++ b/basics/anchorpy-main/tests/unit/test_event_parser.py @@ -0,0 +1,32 @@ +from pathlib import Path + +from anchorpy import Event, EventParser, Idl, Program +from solders.pubkey import Pubkey + + +def test_event_parser() -> None: + path = Path("tests/idls/events.json") + raw = path.read_text() + idl = Idl.from_json(raw) + program = Program( + idl, Pubkey.from_string("2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy") + ) + logs = [ + "Program 2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy invoke [1]", + "Program log: Instruction: Initialize", + "Program data: YLjF84sCWpQFAAAAAAAAAAUAAABoZWxsbw==", + "Program 2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy consumed 1019 of 1400000 compute units", + "Program 2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy success", + ] + parser = EventParser(program.program_id, program.coder) + evts = [] + parser.parse_logs(logs, lambda evt: evts.append(evt)) + assert len(evts) == 1 + events_coder = program.coder.events + event_cls = events_coder.layouts["MyEvent"].datacls # type: ignore + expected_data = event_cls( + data=5, + label="hello", + ) + expected_event = Event(name="MyEvent", data=expected_data) + assert evts[0] == expected_event diff --git a/basics/anchorpy-main/tests/unit/test_idl.py b/basics/anchorpy-main/tests/unit/test_idl.py new file mode 100644 index 0000000..f8e08aa --- /dev/null +++ b/basics/anchorpy-main/tests/unit/test_idl.py @@ -0,0 +1,39 @@ +from pathlib import Path + +from anchorpy import Idl, Program +from solders.pubkey import Pubkey + + +def test_idls() -> None: + idls = [] + programs = [] + for path in Path("tests/idls/").iterdir(): + raw = path.read_text() + idl = Idl.from_json(raw) + idls.append(idl) + if "spl_token" not in str(path): + program = Program(idl, Pubkey.default()) + programs.append(program) + assert idls + + +def test_jet_enum() -> None: + path = Path("tests/idls/jet.json") + raw = path.read_text() + idl = Idl.from_json(raw) + program = Program(idl, Pubkey.default()) + expired_err = program.type["CacheInvalidError"].Expired + assert expired_err(msg="hi").msg == "hi" + + +def test_switchboard_tuple() -> None: + path = Path("tests/idls/switchboard.json") + raw = path.read_text() + idl = Idl.from_json(raw) + program = Program(idl, Pubkey.default()) # noqa: F841 + + +def test_clientgen_example() -> None: + path = Path("tests/idls/clientgen_example_program.json") + raw = path.read_text() + Idl.from_json(raw) diff --git a/basics/anchorpy-main/tests/unit/test_instruction_coder.py b/basics/anchorpy-main/tests/unit/test_instruction_coder.py new file mode 100644 index 0000000..a06e2d6 --- /dev/null +++ b/basics/anchorpy-main/tests/unit/test_instruction_coder.py @@ -0,0 +1,21 @@ +from pathlib import Path + +from anchorpy import Idl, InstructionCoder +from anchorpy.program.common import _to_instruction +from anchorpy.program.context import _check_args_length +from pytest import mark + + +@mark.unit +def test_instruction_coder() -> None: + """Test InstructionCoder behaves as expected.""" + raw = Path("tests/idls/basic_1.json").read_text() + idl = Idl.from_json(raw) + idl_ix = idl.instructions[0] + args = (1234,) + _check_args_length(idl_ix, args) + ix = _to_instruction(idl_ix, args) + coder = InstructionCoder(idl) + encoded = coder.build(ix) + assert encoded == b"\xaf\xafm\x1f\r\x98\x9b\xed\xd2\x04\x00\x00\x00\x00\x00\x00" + assert coder.parse(encoded) == ix diff --git a/basics/anchorpy-main/tests/unit/test_transaction.py b/basics/anchorpy-main/tests/unit/test_transaction.py new file mode 100644 index 0000000..136d732 --- /dev/null +++ b/basics/anchorpy-main/tests/unit/test_transaction.py @@ -0,0 +1,78 @@ +from anchorpy import Coder, Idl +from anchorpy.program.context import Context +from anchorpy.program.namespace.instruction import _InstructionFn +from anchorpy.program.namespace.transaction import _build_transaction_fn +from pytest import fixture +from solders.hash import Hash +from solders.instruction import Instruction +from solders.keypair import Keypair +from solders.pubkey import Pubkey + +DEFAULT_PUBKEY = Pubkey.default() + + +def _make_ix(data: bytes) -> Instruction: + return Instruction( + accounts=[], + program_id=DEFAULT_PUBKEY, + data=data, + ) + + +@fixture +def pre_ix() -> Instruction: + return _make_ix(b"pre") + + +@fixture +def post_ix() -> Instruction: + return _make_ix(b"post") + + +@fixture +def idl() -> Idl: + raw = """{ + "version": "0.0.0", + "name": "basic_0", + "instructions": [ + { + "name": "initialize", + "accounts": [], + "args": [] + } + ] + }""" + return Idl.from_json(raw) + + +@fixture +def coder(idl: Idl) -> Coder: + return Coder(idl) + + +def test_pre_instructions(coder: Coder, idl: Idl, pre_ix: Instruction) -> None: + coder.instruction.encode + ix_item = _InstructionFn( + idl.instructions[0], coder.instruction.build, DEFAULT_PUBKEY + ) + tx_item = _build_transaction_fn(idl.instructions[0], ix_item) + tx = tx_item( + ctx=Context(pre_instructions=[pre_ix]), + payer=Keypair(), + blockhash=Hash.default(), + ) + assert len(tx.message.instructions) == 2 + + +def test_post_instructions(coder: Coder, idl: Idl, post_ix: Instruction) -> None: + coder.instruction.encode + ix_item = _InstructionFn( + idl.instructions[0], coder.instruction.build, DEFAULT_PUBKEY + ) + tx_item = _build_transaction_fn(idl.instructions[0], ix_item) + tx = tx_item( + ctx=Context(post_instructions=[post_ix]), + payer=Keypair(), + blockhash=Hash.default(), + ) + assert len(tx.message.instructions) == 2 diff --git a/tokens/Acc-info-for-Solana-address/README.md b/tokens/Acc-info-for-Solana-address/README.md new file mode 100644 index 0000000..3326728 --- /dev/null +++ b/tokens/Acc-info-for-Solana-address/README.md @@ -0,0 +1,9 @@ +# Web3-Examples + +This script will query account information for a given Solana address + +Make sure you have the solanapy library installed. You can install it using pip: +pip install solanapy + + +Reference Implementation From https://github.com/solana-developers/web3-examples diff --git a/tokens/Acc-info-for-Solana-address/Solana.py b/tokens/Acc-info-for-Solana-address/Solana.py new file mode 100644 index 0000000..24605dd --- /dev/null +++ b/tokens/Acc-info-for-Solana-address/Solana.py @@ -0,0 +1,26 @@ +import solana +from solana.rpc.api import Client +from solana.account import Account + +# Initialize a Solana RPC client +rpc_url = "https://api.mainnet-beta.solana.com" # Use the desired Solana network +client = Client(rpc_url) + +# Define the Solana address you want to query +solana_address = "SOLANA_ADDRESS_GOES_HERE" + +# Convert the address to bytes +address_bytes = solana.decode(solana_address) + +# Query account information +response = client.get_account_info(address_bytes) + +if response: + account_data = response.get("result", {}) + balance = account_data.get("value", {}).get("lamports", 0) / 10**9 # Convert lamports to SOL + owner = account_data.get("value", {}).get("owner", "") + print(f"Solana Address: {solana_address}") + print(f"Balance: {balance} SOL") + print(f"Owner: {owner}") +else: + print(f"Failed to retrieve account information for {solana_address}")