Documentation and tutorials init
This commit is contained in:
parent
c2d2041759
commit
322c9bb548
|
@ -103,7 +103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "basic-program"
|
||||
name = "basic-program-0"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anchor",
|
||||
|
@ -260,6 +260,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constraints-program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anchor",
|
||||
"borsh",
|
||||
"solana-program",
|
||||
"solana-sdk",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.7.0"
|
||||
|
|
|
@ -25,4 +25,5 @@ members = [
|
|||
"attributes/*",
|
||||
"derive",
|
||||
"examples/basic",
|
||||
"examples/tutorial/basic-0/program",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
pids
|
||||
logs
|
||||
node_modules
|
||||
npm-debug.log
|
||||
coverage/
|
||||
run
|
||||
dist
|
||||
.DS_Store
|
||||
.nyc_output
|
||||
.basement
|
||||
config.local.js
|
||||
basement_dist
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "anchor",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"authors": {
|
||||
"name": "",
|
||||
"email": ""
|
||||
},
|
||||
"repository": "/anchor",
|
||||
"scripts": {
|
||||
"dev": "vuepress dev src",
|
||||
"build": "vuepress build src"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"vuepress": "^1.5.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<p class="demo">
|
||||
{{ msg }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Hello this is <Foo-Bar>'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<p class="demo">This is another component</p>
|
||||
</template>
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<p class="demo">
|
||||
{{ msg }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
msg: 'Hello this is <demo-component>'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,58 @@
|
|||
const { description } = require('../../package')
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Ref:https://v1.vuepress.vuejs.org/config/#title
|
||||
*/
|
||||
title: 'Anchor',
|
||||
/**
|
||||
* Ref:https://v1.vuepress.vuejs.org/config/#description
|
||||
*/
|
||||
description: description,
|
||||
|
||||
/**
|
||||
* Extra tags to be injected to the page HTML `<head>`
|
||||
*
|
||||
* ref:https://v1.vuepress.vuejs.org/config/#head
|
||||
*/
|
||||
head: [
|
||||
['meta', { name: 'theme-color', content: '#3eaf7c' }],
|
||||
['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
|
||||
['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }]
|
||||
],
|
||||
|
||||
/**
|
||||
* Theme configuration, here is the default theme configuration for VuePress.
|
||||
*
|
||||
* ref:https://v1.vuepress.vuejs.org/theme/default-theme-config.html
|
||||
*/
|
||||
themeConfig: {
|
||||
repo: '',
|
||||
editLinks: false,
|
||||
docsDir: '',
|
||||
editLinkText: '',
|
||||
lastUpdated: false,
|
||||
sidebar: {
|
||||
'/guide/': [
|
||||
{
|
||||
title: 'Getting Started',
|
||||
collapsable: false,
|
||||
children: [
|
||||
'',
|
||||
'prerequisites',
|
||||
'tutorial-0',
|
||||
'tutorial-1',
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply plugins,ref:https://v1.vuepress.vuejs.org/zh/plugin/
|
||||
*/
|
||||
plugins: [
|
||||
'@vuepress/plugin-back-to-top',
|
||||
'@vuepress/plugin-medium-zoom',
|
||||
]
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Client app enhancement file.
|
||||
*
|
||||
* https://v1.vuepress.vuejs.org/guide/basic-config.html#app-level-enhancements
|
||||
*/
|
||||
|
||||
export default ({
|
||||
Vue, // the version of Vue being used in the VuePress app
|
||||
options, // the options for the root Vue instance
|
||||
router, // the router instance for the app
|
||||
siteData // site metadata
|
||||
}) => {
|
||||
// ...apply enhancements for the site.
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* Custom Styles here.
|
||||
*
|
||||
* ref:https://v1.vuepress.vuejs.org/config/#index-styl
|
||||
*/
|
||||
|
||||
.home .hero img
|
||||
max-width 450px!important
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Custom palette here.
|
||||
*
|
||||
* ref:https://v1.vuepress.vuejs.org/zh/config/#palette-styl
|
||||
*/
|
||||
|
||||
$accentColor = #3eaf7c
|
||||
$textColor = #2c3e50
|
||||
$borderColor = #eaecef
|
||||
$codeBgColor = #282c34
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
sidebar: auto
|
||||
---
|
||||
|
||||
# Config
|
||||
|
||||
## foo
|
||||
|
||||
- Type: `string`
|
||||
- Default: `/`
|
||||
|
||||
## bar
|
||||
|
||||
- Type: `string`
|
||||
- Default: `/`
|
|
@ -0,0 +1,21 @@
|
|||
# Introduction
|
||||
|
||||
Anchor is a framework for Solana's [Sealevel](https://medium.com/solana-labs/sealevel-parallel-processing-thousands-of-smart-contracts-d814b378192) runtime, exposing a safer and more convenient programming model to the Solana developer by providing a
|
||||
|
||||
* Rust Crate for writing Solana programs
|
||||
* CLI for extracting an [IDL](https://en.wikipedia.org/wiki/Interface_description_language) from source
|
||||
* TypeScript package for generating clients from IDL
|
||||
|
||||
If you're familiar with developing in Ethereum's [Solidity](https://docs.soliditylang.org/en/v0.7.4/) and [web3.js](https://github.com/ethereum/web3.js) or Parity's [Ink!](https://github.com/paritytech/ink), then the experience will be familiar. Although the DSL syntax and semantics are targeted at Solana, the high level flow of writing RPC request handlers, emitting an IDL, and generating clients from IDL is the same.
|
||||
|
||||
Here, we'll walkthrough a tutorial demonstrating how to use Anchor. To skip the tutorial and jump straight to a full example, go [here](https://github.com/armaniferrante/anchor/tree/master/examples/basic).
|
||||
|
||||
## Contributing
|
||||
|
||||
It would be great to have clients generated for languages other than TypeScript. If you're
|
||||
interested in developing a client generator, feel free to reach out, or go ahead and just
|
||||
do it :P.
|
||||
|
||||
## Note
|
||||
|
||||
Anchor is in active development, so all APIs are subject to change. If you have feedback, please reach out by [filing an issue](https://github.com/armaniferrante/anchor/issues/new). This documentation is a work in progress and is expected to change dramatically as features continue to be built out. If you have any problems, consult the [source](https://github.com/armaniferrante/anchor) or feel free to ask questions on the [Serum Discord](https://discord.com/channels/739225212658122886/752530209848295555).
|
|
@ -0,0 +1,32 @@
|
|||
# Prerequisites
|
||||
|
||||
Before getting started, make sure to setup all the prerequisite tools on your local machine.
|
||||
|
||||
## Install Rust
|
||||
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
source $HOME/.cargo/env
|
||||
rustup component add rustfmt
|
||||
```
|
||||
|
||||
For an introduction to Rust, see the excellent Rust [book](https://doc.rust-lang.org/book/).
|
||||
|
||||
## Install Anchor
|
||||
|
||||
For now, we can use Cargo.
|
||||
|
||||
```bash
|
||||
cargo install --git https://github.com/project-serum/anchor anchor-cli
|
||||
```
|
||||
|
||||
## Install Solana
|
||||
|
||||
```bash
|
||||
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v1.4.14/install/solana-install-init.sh | sh -s - v1.4.14
|
||||
export PATH="/home/ubuntu/.local/share/solana/install/active_release/bin:$PATH"
|
||||
```
|
||||
|
||||
## Setup a Localnet
|
||||
|
||||
The easiest way to run a local cluster is to run the docker container provided by Solana. Instructions can be found [here](https://solana-labs.github.io/solana-web3.js/). (Note: `solana-test-validator` is the new, preferred way to run a local validator, though I haven't tested it yet).
|
|
@ -0,0 +1,108 @@
|
|||
# Tutorial 0: A Minimal Example
|
||||
|
||||
Here, we introduce a minimal example demonstrating the Anchor workflow and core syntax
|
||||
elements. This tutorial assumes all [prerequisites](./prerequisites.md) are installed and
|
||||
a local network is running.
|
||||
|
||||
## Clone the repo
|
||||
|
||||
To get started, clone the repo.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/armaniferrante/anchor
|
||||
```
|
||||
|
||||
And change directories to the [example](https://github.com/armaniferrante/anchor/tree/master/examples/basic-0).
|
||||
|
||||
```bash
|
||||
cd anchor/examples/tutorial/basic-0
|
||||
```
|
||||
|
||||
## Defining a program
|
||||
|
||||
We define the minimum viable program as follows.
|
||||
|
||||
<<< @/../examples/tutorial/basic-0/program/src/lib.rs
|
||||
|
||||
There are a couple of syntax elements to point out here.
|
||||
|
||||
### `#[program]`
|
||||
|
||||
First, notice that a program is defined with the `#[program]` attribute, where each
|
||||
inner method defines an RPC request handler, or, in Solana parlance, an "instruction"
|
||||
handler. These handlers are the entrypoints to your program that clients may invoke, as
|
||||
we will see soon.
|
||||
|
||||
### `Context<Initialize>`
|
||||
|
||||
The first parameter of *every* RPC handler is the `Context` struct, which is a simple
|
||||
container for the currently executing `program_id` generic over
|
||||
`Accounts`--here, the `Initialize` struct.
|
||||
|
||||
### `#[derive(Accounts)]`
|
||||
|
||||
The `Accounts` derive macro marks a struct containing all the accounts that must be
|
||||
specified for a given instruction. To understand Accounts on Solana, see the
|
||||
[docs](https://docs.solana.com/developing/programming-model/accounts).
|
||||
In subsequent tutorials, we'll demonstrate how an `Accounts` struct can be used to
|
||||
specify constraints on accounts given to your program. Since this example doesn't touch any
|
||||
accounts, we skip this (important) detail.
|
||||
|
||||
## Building a program
|
||||
|
||||
This program can be built in same way as any other Solana program.
|
||||
|
||||
```bash
|
||||
cargo build-bpf
|
||||
```
|
||||
|
||||
## Deploying a program
|
||||
|
||||
Similarly, we can deploy the program using the `solana deploy` command.
|
||||
|
||||
```bash
|
||||
solana deploy <path-to-your-repo>/anchor/target/deploy/basic_program_0.so
|
||||
```
|
||||
|
||||
Making sure to susbstitute paths to match your local filesystem. Now, save the address
|
||||
the program was deployed with. It will be useful later.
|
||||
|
||||
## Emmiting an IDL
|
||||
|
||||
After creating a program, one can use the Anchor CLI to emit an IDL, from which clients
|
||||
can be generated.
|
||||
|
||||
```bash
|
||||
anchor idl -f src/lib.rs -o idl.js
|
||||
```
|
||||
Inspecting the contents of `idl.js` one should see
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.0.0",
|
||||
"name": "basic",
|
||||
"instructions": [
|
||||
{
|
||||
"name": "initialize",
|
||||
"accounts": [],
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
For experienced Ethereum developers, this is analogous to an `abi.json` file.
|
||||
|
||||
## Generating a Client
|
||||
|
||||
Now that we have an IDL, we can use it to create a client.
|
||||
|
||||
<<< @/../examples/tutorial/basic-0/app/client.js#main
|
||||
|
||||
Notice how the program dynamically created the `initialize` method under
|
||||
the `rpc` namespace.
|
||||
|
||||
## Next Steps
|
||||
|
||||
So far we've seen the basics of how to create, deploy, and make RPCs to a program on Solana
|
||||
using Anchor. But a program isn't all that interesting without interacting with it's
|
||||
peristent state, which is what we'll cover next.
|
|
@ -0,0 +1,16 @@
|
|||
# Tutorial 1: Accounts, Arguments, and Types
|
||||
|
||||
It's recommended to read [Tutorial 0](./tutorial-0.md) first, as this tutorial will
|
||||
build on top of it. The full example can be found [here](https://github.com/armaniferrante/anchor/tree/master/examples/basic-1).
|
||||
|
||||
## Defining a program
|
||||
|
||||
We define our program as follows
|
||||
|
||||
<<< @/../examples/tutorial/basic-1/program/src/lib.rs#program
|
||||
|
||||
Some new syntax elements are introduced here.
|
||||
|
||||
First notice, the `data` argument passed into the program. This argument any other valid
|
||||
Rust types can be passed to the instruction to define inputs to the program. Additionally,
|
||||
notice how we take a `mutable` reference to `my_account` and assign to it.
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
home: true
|
||||
heroImage: https://v1.vuepress.vuejs.org/hero.png
|
||||
tagline:
|
||||
actionText: Quick Start →
|
||||
actionLink: /guide/
|
||||
features:
|
||||
- title: Feature 1 Title
|
||||
details: Feature 1 Description
|
||||
- title: Feature 2 Title
|
||||
details: Feature 2 Description
|
||||
- title: Feature 3 Title
|
||||
details: Feature 3 Description
|
||||
footer: Made by with ❤️
|
||||
---
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
.PHONY: examples
|
||||
|
||||
ANCHOR=$(PWD)/../target/debug/anchor
|
||||
|
||||
examples:
|
||||
cd tutorial/basic-0/program && cargo build-bpf && $(ANCHOR) idl -f src/lib.rs -o ../idl.json
|
||||
cd basic && cargo build-bpf && $(ANCHOR) idl -f src/lib.rs -o idl.json
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "basic-program"
|
||||
name = "constraints-program"
|
||||
version = "0.1.0"
|
||||
description = "Basic example"
|
||||
description = "An example illustrating anchor constraints"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
name = "basic_program"
|
||||
name = "cosntraints_program"
|
||||
|
||||
[dependencies]
|
||||
borsh = { git = "https://github.com/project-serum/borsh", branch = "serum", features = ["serum-program"] }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "example",
|
||||
"instructions": [
|
||||
{
|
||||
"name": "create_root",
|
||||
"name": "createRoot",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "root",
|
||||
|
@ -23,7 +23,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "update_root",
|
||||
"name": "updateRoot",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "authority",
|
||||
|
@ -44,7 +44,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "create_leaf",
|
||||
"name": "createLeaf",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "root",
|
||||
|
@ -71,7 +71,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "update_leaf",
|
||||
"name": "updateLeaf",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "authority",
|
||||
|
@ -160,7 +160,7 @@
|
|||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "my_data",
|
||||
"name": "myData",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ use anchor::prelude::*;
|
|||
|
||||
// Define the program's RPC handlers.
|
||||
|
||||
// #region program
|
||||
#[program]
|
||||
mod example {
|
||||
use super::*;
|
||||
|
@ -45,6 +46,7 @@ mod example {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
// #endregion program
|
||||
|
||||
// Define the validated accounts for each handler.
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
use solana_client_gen::solana_client_gen;
|
||||
|
||||
#[solana_client_gen]
|
||||
mod instruction {
|
||||
pub enum Example {
|
||||
CreateRoot,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
let (client, genesis) = serum_common_tests::genesis::<client::Client>();
|
||||
|
||||
let accs = vec![];
|
||||
client.initialize(&accs);
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,27 @@
|
|||
// TODO: replace path once the package is published.
|
||||
//
|
||||
// Before running this script, make sure to run `yarn && yarn build` inside
|
||||
// the `ts` directory.
|
||||
const anchor = require('../../../../ts');
|
||||
const fs = require('fs');
|
||||
|
||||
// Configure the local cluster.
|
||||
anchor.setProvider(anchor.Provider.local());
|
||||
|
||||
// #region main
|
||||
async function main() {
|
||||
// Read the generated IDL.
|
||||
const idl = JSON.parse(fs.readFileSync('../idl.json', 'utf8'));
|
||||
|
||||
// Address of the deployed program.
|
||||
const programId = new anchor.web3.PublicKey('<YOUR-PROGRAM-ID>');
|
||||
|
||||
// Generate the program client from IDL.
|
||||
const program = new anchor.Program(idl, programId);
|
||||
|
||||
// Execute the RPC.
|
||||
await program.rpc.initialize();
|
||||
}
|
||||
// #endregion main
|
||||
|
||||
main();
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": "0.0.0",
|
||||
"name": "basic",
|
||||
"instructions": [
|
||||
{
|
||||
"name": "initialize",
|
||||
"accounts": [],
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "basic-program-0"
|
||||
version = "0.1.0"
|
||||
description = "A minimal example of an anchor program"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
name = "basic_program_0"
|
||||
|
||||
[dependencies]
|
||||
borsh = { git = "https://github.com/project-serum/borsh", branch = "serum", features = ["serum-program"] }
|
||||
solana-program = "1.4.3"
|
||||
solana-sdk = { version = "1.3.14", default-features = false, features = ["program"] }
|
||||
anchor = { path = "../../../../", features = ["derive"] }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,14 @@
|
|||
#![feature(proc_macro_hygiene)]
|
||||
|
||||
use anchor::prelude::*;
|
||||
|
||||
#[program]
|
||||
mod basic {
|
||||
use super::*;
|
||||
pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize {}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"version": "0.0.0",
|
||||
"name": "basic_0",
|
||||
"instructions": [
|
||||
{
|
||||
"name": "initialize",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "myAccount",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "data",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "MyAccount",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "data",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "basic-program-0"
|
||||
version = "0.1.0"
|
||||
description = "A minimal example of an anchor program"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
name = "basic_program_0"
|
||||
|
||||
[dependencies]
|
||||
borsh = { git = "https://github.com/project-serum/borsh", branch = "serum", features = ["serum-program"] }
|
||||
solana-program = "1.4.3"
|
||||
solana-sdk = { version = "1.3.14", default-features = false, features = ["program"] }
|
||||
anchor = { path = "../../../", features = ["derive"] }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,25 @@
|
|||
#![feature(proc_macro_hygiene)]
|
||||
|
||||
use anchor::prelude::*;
|
||||
|
||||
#[program]
|
||||
mod basic {
|
||||
use super::*;
|
||||
|
||||
pub fn initialize(ctx: Context<Initialize>, data: u64) -> ProgramResult {
|
||||
let my_account = &mut ctx.accounts.my_account;
|
||||
my_account.data = data;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info> {
|
||||
#[account(mut)]
|
||||
pub my_account: ProgramAccount<'info, MyAccount>,
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize)]
|
||||
pub struct MyAccount {
|
||||
pub data: u64,
|
||||
}
|
|
@ -60,10 +60,20 @@ pub fn generate(accs: AccountsStruct) -> proc_macro2::TokenStream {
|
|||
.collect();
|
||||
|
||||
let name = &accs.ident;
|
||||
let generics = &accs.generics;
|
||||
let (combined_generics, trait_generics, strct_generics) = match accs.generics.lt_token {
|
||||
None => (
|
||||
quote!{<'info>},
|
||||
quote!{<'info>},
|
||||
quote!{},
|
||||
),
|
||||
Some(_) => {
|
||||
let g = &accs.generics;
|
||||
(quote!{#g}, quote!{#g}, quote!{#g})
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
impl#generics Accounts#generics for #name#generics {
|
||||
impl#combined_generics Accounts#trait_generics for #name#strct_generics {
|
||||
fn try_anchor(program_id: &Pubkey, accounts: &[AccountInfo<'info>]) -> Result<Self, ProgramError> {
|
||||
let acc_infos = &mut accounts.iter();
|
||||
|
||||
|
@ -77,7 +87,7 @@ pub fn generate(accs: AccountsStruct) -> proc_macro2::TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
impl#generics #name#generics {
|
||||
impl#strct_generics #name#strct_generics {
|
||||
pub fn exit(&self) -> ProgramResult {
|
||||
#(#on_save)*
|
||||
Ok(())
|
||||
|
|
|
@ -7,6 +7,8 @@ use quote::ToTokens;
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use heck::MixedCase;
|
||||
use heck::CamelCase;
|
||||
|
||||
static DERIVE_NAME: &'static str = "Accounts";
|
||||
|
||||
|
@ -47,7 +49,7 @@ pub fn parse(filename: &str) -> Result<Idl> {
|
|||
arg.raw_arg.ty.to_tokens(&mut tts);
|
||||
let ty = tts.to_string().parse().unwrap();
|
||||
IdlField {
|
||||
name: arg.name.to_string(),
|
||||
name: arg.name.to_string().to_mixed_case(),
|
||||
ty,
|
||||
}
|
||||
})
|
||||
|
@ -58,13 +60,13 @@ pub fn parse(filename: &str) -> Result<Idl> {
|
|||
.fields
|
||||
.iter()
|
||||
.map(|acc| IdlAccount {
|
||||
name: acc.ident.to_string(),
|
||||
name: acc.ident.to_string().to_mixed_case(),
|
||||
is_mut: acc.is_mut,
|
||||
is_signer: acc.is_signer,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
IdlInstruction {
|
||||
name: rpc.ident.to_string(),
|
||||
name: rpc.ident.to_string().to_mixed_case(),
|
||||
accounts,
|
||||
args,
|
||||
}
|
||||
|
@ -162,7 +164,12 @@ fn parse_ty_defs(f: &syn::File) -> Result<Vec<IdlTypeDef>> {
|
|||
let mut tts = proc_macro2::TokenStream::new();
|
||||
f.ty.to_tokens(&mut tts);
|
||||
Ok(IdlField {
|
||||
name: f.ident.as_ref().unwrap().to_string(),
|
||||
name: f
|
||||
.ident
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.to_mixed_case(),
|
||||
ty: tts.to_string().parse()?,
|
||||
})
|
||||
})
|
||||
|
|
|
@ -60,7 +60,7 @@ type RpcOptions = ConfirmOptions;
|
|||
*/
|
||||
type RpcContext = {
|
||||
// Accounts the instruction will use.
|
||||
accounts: RpcAccounts;
|
||||
accounts?: RpcAccounts;
|
||||
// Instructions to run *before* the specified rpc instruction.
|
||||
instructions?: TransactionInstruction[];
|
||||
// Accounts that must sign the transaction.
|
||||
|
@ -105,22 +105,24 @@ export class RpcFactory {
|
|||
ixFns[name] = ix;
|
||||
});
|
||||
|
||||
idl.accounts.forEach((idlAccount) => {
|
||||
// todo
|
||||
const accountFn = async (address: PublicKey): Promise<any> => {
|
||||
const provider = getProvider();
|
||||
if (provider === null) {
|
||||
throw new Error("Provider not set");
|
||||
}
|
||||
const accountInfo = await provider.connection.getAccountInfo(address);
|
||||
if (accountInfo === null) {
|
||||
throw new Error(`Entity does not exist ${address}`);
|
||||
}
|
||||
return coder.accounts.decode(idlAccount.name, accountInfo.data);
|
||||
};
|
||||
const name = camelCase(idlAccount.name);
|
||||
accountFns[name] = accountFn;
|
||||
});
|
||||
if (idl.accounts) {
|
||||
idl.accounts.forEach((idlAccount) => {
|
||||
// todo
|
||||
const accountFn = async (address: PublicKey): Promise<any> => {
|
||||
const provider = getProvider();
|
||||
if (provider === null) {
|
||||
throw new Error("Provider not set");
|
||||
}
|
||||
const accountInfo = await provider.connection.getAccountInfo(address);
|
||||
if (accountInfo === null) {
|
||||
throw new Error(`Entity does not exist ${address}`);
|
||||
}
|
||||
return coder.accounts.decode(idlAccount.name, accountInfo.data);
|
||||
};
|
||||
const name = camelCase(idlAccount.name);
|
||||
accountFns[name] = accountFn;
|
||||
});
|
||||
}
|
||||
|
||||
return [rpcs, ixFns, accountFns];
|
||||
}
|
||||
|
@ -181,7 +183,7 @@ function splitArgsAndCtx(
|
|||
idlIx: IdlInstruction,
|
||||
args: any[]
|
||||
): [any[], RpcContext] {
|
||||
let options = undefined;
|
||||
let options = {};
|
||||
|
||||
const inputLen = idlIx.args ? idlIx.args.length : 0;
|
||||
if (args.length > inputLen) {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
const assert = require('assert');
|
||||
const anchor = require('.');
|
||||
import * as assert from 'assert';
|
||||
import * as anchor from '../../';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
// Global workspace settings.
|
||||
const WORKSPACE = {
|
||||
idl: JSON.parse(require('fs').readFileSync('../examples/basic/idl.json', 'utf8')),
|
||||
idl: JSON.parse(readFileSync('../examples/basic/idl.json', 'utf8')),
|
||||
programId: new anchor.web3.PublicKey('CrQZpSbUnkXxwf1FnepmefoZ7VsbYE6HXmG1TjChH6y'),
|
||||
provider: anchor.Provider.local(),
|
||||
};
|
||||
|
||||
async function test() {
|
||||
console.log('Starting test.');
|
||||
|
||||
describe('Constraints program tests', () => {
|
||||
it('Runs against a localnetwork', async () => {
|
||||
// Configure the local cluster.
|
||||
anchor.setProvider(WORKSPACE.provider);
|
||||
|
||||
|
@ -31,19 +31,19 @@ async function test() {
|
|||
// 3) Accounts for the program's instruction. Ordering does *not* matter,
|
||||
// only that they names are as specified in the IDL.
|
||||
await program.rpc.createRoot(WORKSPACE.provider.wallet.publicKey, new anchor.BN(1234), {
|
||||
accounts: {
|
||||
root: root.publicKey,
|
||||
},
|
||||
signers: [root],
|
||||
instructions: [
|
||||
anchor.web3.SystemProgram.createAccount({
|
||||
fromPubkey: WORKSPACE.provider.wallet.publicKey,
|
||||
newAccountPubkey: root.publicKey,
|
||||
space: 41,
|
||||
lamports: await WORKSPACE.provider.connection.getMinimumBalanceForRentExemption(41),
|
||||
programId: WORKSPACE.programId,
|
||||
}),
|
||||
],
|
||||
accounts: {
|
||||
root: root.publicKey,
|
||||
},
|
||||
signers: [root],
|
||||
instructions: [
|
||||
anchor.web3.SystemProgram.createAccount({
|
||||
fromPubkey: WORKSPACE.provider.wallet.publicKey,
|
||||
newAccountPubkey: root.publicKey,
|
||||
space: 41,
|
||||
lamports: await WORKSPACE.provider.connection.getMinimumBalanceForRentExemption(41),
|
||||
programId: WORKSPACE.programId,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Read the newly created account data.
|
||||
|
@ -54,10 +54,10 @@ async function test() {
|
|||
|
||||
// Execute another RPC to update the data.
|
||||
await program.rpc.updateRoot(new anchor.BN(999), {
|
||||
accounts: {
|
||||
root: root.publicKey,
|
||||
authority: WORKSPACE.provider.wallet.publicKey,
|
||||
},
|
||||
accounts: {
|
||||
root: root.publicKey,
|
||||
authority: WORKSPACE.provider.wallet.publicKey,
|
||||
},
|
||||
});
|
||||
|
||||
// Check the update actually persisted.
|
||||
|
@ -68,20 +68,20 @@ async function test() {
|
|||
const leaf = new anchor.web3.Account();
|
||||
let customType = { myData: new anchor.BN(4), key: WORKSPACE.programId };
|
||||
await program.rpc.createLeaf(new anchor.BN(2), customType, {
|
||||
accounts: {
|
||||
root: root.publicKey,
|
||||
leaf: leaf.publicKey,
|
||||
},
|
||||
signers: [leaf],
|
||||
instructions: [
|
||||
anchor.web3.SystemProgram.createAccount({
|
||||
fromPubkey: WORKSPACE.provider.wallet.publicKey,
|
||||
newAccountPubkey: leaf.publicKey,
|
||||
space: 100,
|
||||
lamports: await WORKSPACE.provider.connection.getMinimumBalanceForRentExemption(100),
|
||||
programId: WORKSPACE.programId,
|
||||
}),
|
||||
],
|
||||
accounts: {
|
||||
root: root.publicKey,
|
||||
leaf: leaf.publicKey,
|
||||
},
|
||||
signers: [leaf],
|
||||
instructions: [
|
||||
anchor.web3.SystemProgram.createAccount({
|
||||
fromPubkey: WORKSPACE.provider.wallet.publicKey,
|
||||
newAccountPubkey: leaf.publicKey,
|
||||
space: 100,
|
||||
lamports: await WORKSPACE.provider.connection.getMinimumBalanceForRentExemption(100),
|
||||
programId: WORKSPACE.programId,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Check the account was initialized.
|
||||
|
@ -94,11 +94,11 @@ async function test() {
|
|||
|
||||
// Update the account.
|
||||
await program.rpc.updateLeaf(new anchor.BN(5), null, {
|
||||
accounts: {
|
||||
authority: WORKSPACE.provider.wallet.publicKey,
|
||||
root: root.publicKey,
|
||||
leaf: leaf.publicKey,
|
||||
},
|
||||
accounts: {
|
||||
authority: WORKSPACE.provider.wallet.publicKey,
|
||||
root: root.publicKey,
|
||||
leaf: leaf.publicKey,
|
||||
},
|
||||
});
|
||||
|
||||
// Check it was updated.
|
||||
|
@ -108,11 +108,11 @@ async function test() {
|
|||
// Now update with the option.
|
||||
customType = { myData: new anchor.BN(7), key: WORKSPACE.programId };
|
||||
await program.rpc.updateLeaf(new anchor.BN(6), customType, {
|
||||
accounts: {
|
||||
authority: WORKSPACE.provider.wallet.publicKey,
|
||||
root: root.publicKey,
|
||||
leaf: leaf.publicKey,
|
||||
},
|
||||
accounts: {
|
||||
authority: WORKSPACE.provider.wallet.publicKey,
|
||||
root: root.publicKey,
|
||||
leaf: leaf.publicKey,
|
||||
},
|
||||
});
|
||||
|
||||
// Check it was updated.
|
||||
|
@ -120,8 +120,5 @@ async function test() {
|
|||
assert.ok(account.data.eq(new anchor.BN(6)));
|
||||
assert.ok(account.custom.myData.eq(new anchor.BN(7)));
|
||||
assert.ok(account.custom.key.equals(WORKSPACE.programId));
|
||||
|
||||
console.log('Test complete.');
|
||||
}
|
||||
|
||||
test();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue