Compare commits

...

6 Commits

Author SHA1 Message Date
dfy313 9a918b5865
Merge d6715a8327 into 81c8c556e8 2024-04-25 13:06:05 -04:00
acheron 81c8c556e8
idl: Add accounts resolution for associated token accounts (#2927) 2024-04-24 18:02:20 +02:00
David Yu d6715a8327
Address PR Feedback
This commit renames the compatibility-testing package, test file, and test case to: solana-program-test-compatibility, compatibility-test.rs, and check_entrypoint. This commit also updates the compatibility test by passing None to the builtin_function argument, and letting cargo test-sbf load the programs. Finally, this commit updates the CI job in reusable-tests to take advantage of existing structure.
2024-03-19 11:16:20 -04:00
dfy313 4f8b32d9ad
Merge branch 'coral-xyz:master' into dfy313-anchor2738-solana-program-test-compatability 2024-03-19 10:44:04 -04:00
David Yu 6ac4d9e86d
Add test-anchor-compatibility job to CI
This CI job executes the newly added solana_program_test entrypoint_lifetime test. “continue-on-error: true” is included as the compatibility test is currently expected to fail
2024-03-14 12:28:59 -04:00
David Yu a2c404decd
Initial commit: add compatibility-testing package to tests directory
The compatibility-testing package contains a simple compatibility test defined in compatibility-testing/programs/compatibility-testing/tests/solana_program_test.rs that checks for entrypoint lifetime compatibility
2024-03-14 12:03:49 -04:00
17 changed files with 256 additions and 20 deletions

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -38,6 +38,7 @@
"spl/token-proxy",
"spl/token-wrapper",
"spl/transfer-hook",
"solana-program-test-compatibility",
"swap",
"system-accounts",
"sysvars",

View File

@ -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" }

View File

@ -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,

View File

@ -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();
});
});

View File

@ -0,0 +1,8 @@
.anchor
.DS_Store
target
node_modules
dist
build
test-ledger

View File

@ -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"

View File

@ -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

View File

@ -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.
};

View File

@ -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"
}
}

View File

@ -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"

View File

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

View File

@ -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 {}

View File

@ -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,
);
}

View File

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