diff --git a/light-sdk-ts/src/idls/verifier_program.ts b/light-sdk-ts/src/idls/verifier_program.ts index 9196a1df15..0a2084a12d 100644 --- a/light-sdk-ts/src/idls/verifier_program.ts +++ b/light-sdk-ts/src/idls/verifier_program.ts @@ -50,6 +50,36 @@ export type VerifierProgram = { } ], "args": [] + }, + { + "name": "shieldedTransferSecond", + "docs": [ + "Stores the provided message in a compressed account, closes the", + "temporary PDA." + ], + "accounts": [ + { + "name": "signingAddress", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "verifierState", + "isMut": true, + "isSigner": false + }, + { + "name": "logWrapper", + "isMut": false, + "isSigner": false + } + ], + "args": [] } ], "accounts": [ @@ -65,6 +95,13 @@ export type VerifierProgram = { ] } } + ], + "errors": [ + { + "code": 6000, + "name": "NoopProgram", + "msg": "The provided program is not the noop program." + } ] }; @@ -120,6 +157,36 @@ export const IDL: VerifierProgram = { } ], "args": [] + }, + { + "name": "shieldedTransferSecond", + "docs": [ + "Stores the provided message in a compressed account, closes the", + "temporary PDA." + ], + "accounts": [ + { + "name": "signingAddress", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "verifierState", + "isMut": true, + "isSigner": false + }, + { + "name": "logWrapper", + "isMut": false, + "isSigner": false + } + ], + "args": [] } ], "accounts": [ @@ -135,5 +202,12 @@ export const IDL: VerifierProgram = { ] } } + ], + "errors": [ + { + "code": 6000, + "name": "NoopProgram", + "msg": "The provided program is not the noop program." + } ] }; diff --git a/light-system-programs/programs/verifier_program_storage/src/lib.rs b/light-system-programs/programs/verifier_program_storage/src/lib.rs index 0d93001b55..2b73ee7a51 100644 --- a/light-system-programs/programs/verifier_program_storage/src/lib.rs +++ b/light-system-programs/programs/verifier_program_storage/src/lib.rs @@ -1,8 +1,41 @@ -use anchor_lang::prelude::*; +use std::str::FromStr; + +use anchor_lang::{ + prelude::*, + solana_program::{instruction::Instruction, program::invoke}, +}; use light_verifier_sdk::light_transaction::VERIFIER_STATE_SEED; declare_id!("DJpbogMSrK94E1zvvJydtkqoE4sknuzmMRoutd6B7TKj"); +pub const NOOP_PROGRAM_ID: &str = "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV"; + +#[error_code] +pub enum VerifierError { + #[msg("The provided program is not the noop program.")] + NoopProgram, +} + +pub fn wrap_event<'info>( + msg: Vec, + noop_program: &AccountInfo<'info>, + signer: &AccountInfo<'info>, +) -> Result<()> { + if noop_program.key() != Pubkey::from_str(NOOP_PROGRAM_ID).unwrap() { + return Err(VerifierError::NoopProgram.into()); + } + let instruction = Instruction { + program_id: noop_program.key(), + accounts: vec![], + data: msg, + }; + invoke( + &instruction, + &[noop_program.to_account_info(), signer.to_account_info()], + )?; + Ok(()) +} + #[program] pub mod verifier_program { use super::*; @@ -25,6 +58,22 @@ pub mod verifier_program { ) -> Result<()> { Ok(()) } + + /// Stores the provided message in a compressed account, closes the + /// temporary PDA. + pub fn shielded_transfer_second<'info>( + ctx: Context>, + ) -> Result<()> { + let state = &mut ctx.accounts.verifier_state; + + wrap_event( + state.msg.clone(), + &ctx.accounts.log_wrapper, + &ctx.accounts.signing_address, + )?; + + Ok(()) + } } #[account] @@ -54,3 +103,19 @@ pub struct LightInstructionClose<'info> { #[account(mut, close=signing_address)] pub verifier_state: Account<'info, VerifierState>, } + +#[derive(Accounts)] +pub struct LightInstructionSecond<'info> { + #[account(mut)] + pub signing_address: Signer<'info>, + pub system_program: Program<'info, System>, + #[account( + mut, + seeds = [&signing_address.key().to_bytes(), VERIFIER_STATE_SEED], + bump, + close=signing_address + )] + pub verifier_state: Account<'info, VerifierState>, + /// CHECK: Checking manually in the `wrap_event` function. + pub log_wrapper: UncheckedAccount<'info>, +} diff --git a/light-system-programs/runTest.sh b/light-system-programs/runTest.sh index 5329ea6df8..6540e228ab 100644 --- a/light-system-programs/runTest.sh +++ b/light-system-programs/runTest.sh @@ -1,5 +1,5 @@ #!/bin/bash -e -../../solana/validator/solana-test-validator --reset --limit-ledger-size 500000000 --bpf-program J1RRetZ4ujphU75LP8RadjXMf3sA12yC2R44CF7PmU7i ./target/deploy/verifier_program_zero.so --bpf-program JA5cjkRJ1euVi9xLWsCJVzsRzEkT8vcC4rqw9sVAo5d6 ./target/deploy/merkle_tree_program.so --bpf-program 3KS2k14CmtnuVv2fvYcvdrNgC94Y11WETBpMUGgXyWZL ./target/deploy/verifier_program_one.so --bpf-program noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV ../../solana/web3.js/test/fixtures/noop-program/solana_sbf_rust_noop.so --bpf-program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS ./target/deploy/verifier_program.so --quiet & +../../solana/validator/solana-test-validator --reset --limit-ledger-size 500000000 --bpf-program J1RRetZ4ujphU75LP8RadjXMf3sA12yC2R44CF7PmU7i ./target/deploy/verifier_program_zero.so --bpf-program JA5cjkRJ1euVi9xLWsCJVzsRzEkT8vcC4rqw9sVAo5d6 ./target/deploy/merkle_tree_program.so --bpf-program 3KS2k14CmtnuVv2fvYcvdrNgC94Y11WETBpMUGgXyWZL ./target/deploy/verifier_program_one.so --bpf-program noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV ../../solana/web3.js/test/fixtures/noop-program/solana_sbf_rust_noop.so --bpf-program DJpbogMSrK94E1zvvJydtkqoE4sknuzmMRoutd6B7TKj ./target/deploy/verifier_program_storage.so --quiet & sleep 7 PID=$! $1; diff --git a/light-system-programs/tests/functional_tests.ts b/light-system-programs/tests/functional_tests.ts index 02347f8520..aafe48b005 100644 --- a/light-system-programs/tests/functional_tests.ts +++ b/light-system-programs/tests/functional_tests.ts @@ -77,6 +77,13 @@ describe("verifier_program", () => { IDL_VERIFIER_PROGRAM, verifierStorageProgramId, ); + const [verifierState] = anchor.web3.PublicKey.findProgramAddressSync( + [ + ADMIN_AUTH_KEYPAIR.publicKey.toBuffer(), + anchor.utils.bytes.utf8.encode("VERIFIER_STATE"), + ], + verifierProgram.programId, + ); const userKeypair = new SolanaKeypair(); @@ -106,14 +113,6 @@ describe("verifier_program", () => { // TODO(vadorovsky): We probably need some parts of that test to the SDK. it("shielded transfer 1 & close", async () => { - let [verifierState] = anchor.web3.PublicKey.findProgramAddressSync( - [ - ADMIN_AUTH_KEYPAIR.publicKey.toBuffer(), - anchor.utils.bytes.utf8.encode("VERIFIER_STATE"), - ], - verifierProgram.programId, - ); - let balance = await provider.connection.getBalance( verifierState, "confirmed", @@ -163,6 +162,39 @@ describe("verifier_program", () => { assert.equal(accountInfo, null); }); + it("shielded transfer 1 & 2", async () => { + let tx0 = await verifierProgram.methods + .shieldedTransferFirst(msg) + .accounts({ + signingAddress: ADMIN_AUTH_KEYPAIR.publicKey, + systemProgram: solana.SystemProgram.programId, + verifierState: verifierState, + }) + .signers([ADMIN_AUTH_KEYPAIR]) + .rpc(confirmConfig); + + console.log(tx0); + + let tx1 = await verifierProgram.methods + .shieldedTransferSecond() + .accounts({ + signingAddress: ADMIN_AUTH_KEYPAIR.publicKey, + verifierState: verifierState, + logWrapper: SPL_NOOP_ADDRESS, + }) + .signers([ADMIN_AUTH_KEYPAIR]) + .rpc(confirmConfig); + + console.log(tx1); + + let accountInfo = await provider.connection.getAccountInfo( + verifierState, + "confirmed", + ); + assert.equal(accountInfo, null); + }); + + it("Deposit 10 utxo", async () => { if (LOOK_UP_TABLE === undefined) { throw "undefined LOOK_UP_TABLE";