Compare commits
6 Commits
c58cf69e9d
...
9a918b5865
Author | SHA1 | Date |
---|---|---|
dfy313 | 9a918b5865 | |
acheron | 81c8c556e8 | |
David Yu | d6715a8327 | |
dfy313 | 4f8b32d9ad | |
David Yu | 6ac4d9e86d | |
David Yu | a2c404decd |
|
@ -460,6 +460,8 @@ jobs:
|
|||
path: tests/bench
|
||||
- cmd: cd tests/idl && ./test.sh
|
||||
path: tests/idl
|
||||
- cmd: cd tests/solana-program-test-compatibility && cargo test-sbf --package solana-program-test-compatibility --test compatibility_test check_entrypoint
|
||||
path: tests/idl
|
||||
# TODO: Enable when `solang` becomes compatible with the new IDL spec
|
||||
# - cmd: cd tests/solang && anchor test
|
||||
# path: tests/solang
|
||||
|
|
|
@ -13,6 +13,7 @@ The minor version will be incremented upon a breaking change and the patch versi
|
|||
### Features
|
||||
|
||||
- avm: Support customizing the installation location using `AVM_HOME` environment variable ([#2917](https://github.com/coral-xyz/anchor/pull/2917))
|
||||
- idl, ts: Add accounts resolution for associated token accounts ([#2927](https://github.com/coral-xyz/anchor/pull/2927))
|
||||
|
||||
### Fixes
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use proc_macro2::TokenStream;
|
|||
use quote::{quote, ToTokens};
|
||||
|
||||
use super::common::{get_idl_module_path, get_no_docs};
|
||||
use crate::{AccountField, AccountsStruct, Field, Ty};
|
||||
use crate::{AccountField, AccountsStruct, Field, InitKind, Ty};
|
||||
|
||||
/// Generate the IDL build impl for the Accounts struct.
|
||||
pub fn gen_idl_build_impl_accounts_struct(accounts: &AccountsStruct) -> TokenStream {
|
||||
|
@ -168,26 +168,87 @@ fn get_address(acc: &Field) -> TokenStream {
|
|||
|
||||
fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream {
|
||||
let idl = get_idl_module_path();
|
||||
let parse_default = |expr: &syn::Expr| parse_seed(expr, accounts);
|
||||
|
||||
// Seeds
|
||||
let seed_constraints = acc.constraints.seeds.as_ref();
|
||||
let seeds = seed_constraints
|
||||
.map(|seed| seed.seeds.iter().map(|seed| parse_seed(seed, accounts)))
|
||||
.and_then(|seeds| seeds.collect::<Result<Vec<_>>>().ok());
|
||||
let program = seed_constraints
|
||||
.and_then(|seed| seed.program_seed.as_ref())
|
||||
.and_then(|program| parse_seed(program, accounts).ok())
|
||||
.map(|program| quote! { Some(#program) })
|
||||
.unwrap_or_else(|| quote! { None });
|
||||
match seeds {
|
||||
Some(seeds) => quote! {
|
||||
Some(
|
||||
#idl::IdlPda {
|
||||
seeds: vec![#(#seeds),*],
|
||||
program: #program,
|
||||
}
|
||||
)
|
||||
},
|
||||
_ => quote! { None },
|
||||
let pda = seed_constraints
|
||||
.map(|seed| seed.seeds.iter().map(parse_default))
|
||||
.and_then(|seeds| seeds.collect::<Result<Vec<_>>>().ok())
|
||||
.map(|seeds| {
|
||||
let program = seed_constraints
|
||||
.and_then(|seed| seed.program_seed.as_ref())
|
||||
.and_then(|program| parse_default(program).ok())
|
||||
.map(|program| quote! { Some(#program) })
|
||||
.unwrap_or_else(|| quote! { None });
|
||||
|
||||
quote! {
|
||||
Some(
|
||||
#idl::IdlPda {
|
||||
seeds: vec![#(#seeds),*],
|
||||
program: #program,
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
if let Some(pda) = pda {
|
||||
return pda;
|
||||
}
|
||||
|
||||
// Associated token
|
||||
let pda = acc
|
||||
.constraints
|
||||
.init
|
||||
.as_ref()
|
||||
.and_then(|init| match &init.kind {
|
||||
InitKind::AssociatedToken {
|
||||
owner,
|
||||
mint,
|
||||
token_program,
|
||||
} => Some((owner, mint, token_program)),
|
||||
_ => None,
|
||||
})
|
||||
.or_else(|| {
|
||||
acc.constraints
|
||||
.associated_token
|
||||
.as_ref()
|
||||
.map(|ata| (&ata.wallet, &ata.mint, &ata.token_program))
|
||||
})
|
||||
.and_then(|(wallet, mint, token_program)| {
|
||||
// ATA constraints have implicit `.key()` call
|
||||
let parse_expr = |ts| parse_default(&syn::parse2(ts).unwrap()).ok();
|
||||
let parse_ata = |expr| parse_expr(quote! { #expr.key().as_ref() });
|
||||
|
||||
let wallet = parse_ata(wallet);
|
||||
let mint = parse_ata(mint);
|
||||
let token_program = token_program
|
||||
.as_ref()
|
||||
.and_then(parse_ata)
|
||||
.or_else(|| parse_expr(quote!(anchor_spl::token::ID)));
|
||||
|
||||
let seeds = match (wallet, mint, token_program) {
|
||||
(Some(w), Some(m), Some(tp)) => quote! { vec![#w, #tp, #m] },
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let program = parse_expr(quote!(anchor_spl::associated_token::ID))
|
||||
.map(|program| quote! { Some(#program) })
|
||||
.unwrap();
|
||||
|
||||
Some(quote! {
|
||||
Some(
|
||||
#idl::IdlPda {
|
||||
seeds: #seeds,
|
||||
program: #program,
|
||||
}
|
||||
)
|
||||
})
|
||||
});
|
||||
if let Some(pda) = pda {
|
||||
return pda;
|
||||
}
|
||||
|
||||
quote! { None }
|
||||
}
|
||||
|
||||
/// Parse a seeds constraint, extracting the `IdlSeed` types.
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
"spl/token-proxy",
|
||||
"spl/token-wrapper",
|
||||
"spl/transfer-hook",
|
||||
"solana-program-test-compatibility",
|
||||
"swap",
|
||||
"system-accounts",
|
||||
"sysvars",
|
||||
|
|
|
@ -14,7 +14,8 @@ no-entrypoint = []
|
|||
no-idl = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
idl-build = ["anchor-lang/idl-build"]
|
||||
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
||||
anchor-spl = { path = "../../../../spl" }
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
mod other;
|
||||
|
||||
use anchor_lang::prelude::*;
|
||||
use anchor_spl::{
|
||||
associated_token::AssociatedToken,
|
||||
token::{Mint, Token, TokenAccount},
|
||||
};
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
|
@ -34,6 +38,10 @@ pub mod pda_derivation {
|
|||
ctx.accounts.account.data = 1337;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn associated_token_resolution(_ctx: Context<AssociatedTokenResolution>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -115,6 +123,29 @@ pub struct Nested<'info> {
|
|||
account_nested: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AssociatedTokenResolution<'info> {
|
||||
#[account(
|
||||
init,
|
||||
payer = payer,
|
||||
mint::authority = payer,
|
||||
mint::decimals = 9,
|
||||
)]
|
||||
pub mint: Account<'info, Mint>,
|
||||
#[account(
|
||||
init,
|
||||
payer = payer,
|
||||
associated_token::authority = payer,
|
||||
associated_token::mint = mint,
|
||||
)]
|
||||
pub ata: Account<'info, TokenAccount>,
|
||||
#[account(mut)]
|
||||
pub payer: Signer<'info>,
|
||||
pub system_program: Program<'info, System>,
|
||||
pub token_program: Program<'info, Token>,
|
||||
pub associated_token_program: Program<'info, AssociatedToken>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct MyAccount {
|
||||
data: u64,
|
||||
|
|
|
@ -103,4 +103,13 @@ describe("typescript", () => {
|
|||
|
||||
expect(called).is.true;
|
||||
});
|
||||
|
||||
it("Can resolve associated token accounts", async () => {
|
||||
const mintKp = anchor.web3.Keypair.generate();
|
||||
await program.methods
|
||||
.associatedTokenResolution()
|
||||
.accounts({ mint: mintKp.publicKey })
|
||||
.signers([mintKp])
|
||||
.rpc();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
.anchor
|
||||
.DS_Store
|
||||
target
|
||||
node_modules
|
||||
dist
|
||||
build
|
||||
test-ledger
|
|
@ -0,0 +1,18 @@
|
|||
[toolchain]
|
||||
|
||||
[features]
|
||||
seeds = false
|
||||
skip-lint = false
|
||||
|
||||
[programs.localnet]
|
||||
solana_program_test_compatibility = "3cgdzWdfZSy1GaV6Lg98iwLvTcL9W7AVD8BpxiZjCZ9z"
|
||||
|
||||
[registry]
|
||||
url = "https://api.apr.dev"
|
||||
|
||||
[provider]
|
||||
cluster = "Localnet"
|
||||
wallet = "/Users/david/.config/solana/id.json"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
|
|
@ -0,0 +1,13 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"programs/*"
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
overflow-checks = true
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
[profile.release.build-override]
|
||||
opt-level = 3
|
||||
incremental = false
|
||||
codegen-units = 1
|
|
@ -0,0 +1,12 @@
|
|||
// Migrations are an early feature. Currently, they're nothing more than this
|
||||
// single deploy script that's invoked from the CLI, injecting a provider
|
||||
// configured from the workspace's Anchor.toml.
|
||||
|
||||
const anchor = require("@coral-xyz/anchor");
|
||||
|
||||
module.exports = async function (provider) {
|
||||
// Configure client to use the provider.
|
||||
anchor.setProvider(provider);
|
||||
|
||||
// Add your deploy script here.
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"scripts": {
|
||||
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
|
||||
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coral-xyz/anchor": "^0.29.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.3.4",
|
||||
"mocha": "^9.0.3",
|
||||
"ts-mocha": "^10.0.0",
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/chai": "^4.3.0",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"typescript": "^4.3.5",
|
||||
"prettier": "^2.6.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "solana-program-test-compatibility"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "solana_program_test_compatibility"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
no-log-ix-name = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-program-test = ">=1.16, <1.18"
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,15 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("3cgdzWdfZSy1GaV6Lg98iwLvTcL9W7AVD8BpxiZjCZ9z");
|
||||
|
||||
#[program]
|
||||
pub mod solana_program_test_compatibility {
|
||||
use super::*;
|
||||
|
||||
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize {}
|
|
@ -0,0 +1,10 @@
|
|||
use solana_program_test::ProgramTest;
|
||||
|
||||
#[test]
|
||||
fn check_entrypoint() {
|
||||
let _pt = ProgramTest::new(
|
||||
"solana_program_test_compatibility",
|
||||
solana_program_test_compatibility::id(),
|
||||
None,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue