From c84fd4b738d5cb4c965e1fc93f836367c7547f2f Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Tue, 4 Feb 2025 13:07:43 +0100 Subject: [PATCH 1/6] Add relayer signer to ER swap --- Cargo.lock | 2 +- .../src/auction/service/auction_manager.rs | 2 +- .../src/auction/service/submit_quote.rs | 4 +- .../src/auction/service/verification.rs | 10 +- contracts/svm/Cargo.lock | 2 +- .../svm/programs/express_relay/Cargo.toml | 2 +- .../svm/programs/express_relay/src/lib.rs | 24 ++-- .../programs/express_relay/src/sdk/helpers.rs | 6 +- .../svm/testing/src/express_relay/swap.rs | 4 + contracts/svm/testing/tests/swap.rs | 122 +++++++++++++++--- sdk/rust/simple-searcher/src/lib.rs | 9 +- sdk/rust/src/lib.rs | 3 +- sdk/rust/src/svm.rs | 9 +- tilt-scripts/svm/test_swap.py | 4 +- 14 files changed, 147 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a431b6cf..4bd61430 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2652,7 +2652,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "express-relay" -version = "0.5.0" +version = "0.6.0" dependencies = [ "anchor-lang", "anchor-spl", diff --git a/auction-server/src/auction/service/auction_manager.rs b/auction-server/src/auction/service/auction_manager.rs index 4099494a..018a8f94 100644 --- a/auction-server/src/auction/service/auction_manager.rs +++ b/auction-server/src/auction/service/auction_manager.rs @@ -335,7 +335,7 @@ impl AuctionManager for Service { /// This is to make sure we are not missing any transaction. /// We run this once every minute (150 * 0.4). const CONCLUSION_TRIGGER_INTERVAL_SVM: u64 = 150; -const BID_MAXIMUM_LIFE_TIME_SVM: Duration = Duration::from_secs(10); +const BID_MAXIMUM_LIFE_TIME_SVM: Duration = Duration::from_secs(120); const TRIGGER_DURATION_SVM: Duration = Duration::from_millis(400); pub struct TriggerStreamSvm { diff --git a/auction-server/src/auction/service/submit_quote.rs b/auction-server/src/auction/service/submit_quote.rs index 14cef566..d9c11497 100644 --- a/auction-server/src/auction/service/submit_quote.rs +++ b/auction-server/src/auction/service/submit_quote.rs @@ -120,9 +120,7 @@ impl Service { .position(|p| p.eq(&user_wallet)) .expect("User wallet not found in transaction"); bid.chain_data.transaction.signatures[user_signature_pos] = input.user_signature; - - // TODO add relayer signature after program update - // self.add_relayer_signature(&mut bid); + self.add_relayer_signature(&mut bid); if bid.chain_data.bid_payment_instruction_type != entities::BidPaymentInstructionType::Swap { diff --git a/auction-server/src/auction/service/verification.rs b/auction-server/src/auction/service/verification.rs index 52c3609b..84d0393c 100644 --- a/auction-server/src/auction/service/verification.rs +++ b/auction-server/src/auction/service/verification.rs @@ -933,12 +933,10 @@ impl Service { opportunity.check_fee_payer(accounts).map_err(|e| { RestError::BadParameters(format!("Invalid first signer: {:?}", e)) })?; - self.all_signatures_exists( - &message_bytes, - accounts, - &signatures, - &opportunity.get_missing_signers(), - ) + let mut missing_signers = opportunity.get_missing_signers(); + missing_signers.push(self.config.chain_config.express_relay.relayer.pubkey()); + self.relayer_signer_exists(accounts, &signatures)?; + self.all_signatures_exists(&message_bytes, accounts, &signatures, &missing_signers) } SubmitType::ByServer => { self.relayer_signer_exists(accounts, &signatures)?; diff --git a/contracts/svm/Cargo.lock b/contracts/svm/Cargo.lock index 374c4ee4..ec85fdf1 100644 --- a/contracts/svm/Cargo.lock +++ b/contracts/svm/Cargo.lock @@ -1697,7 +1697,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "express-relay" -version = "0.5.0" +version = "0.6.0" dependencies = [ "anchor-lang", "anchor-spl", diff --git a/contracts/svm/programs/express_relay/Cargo.toml b/contracts/svm/programs/express_relay/Cargo.toml index b96fc68b..d4b5837d 100644 --- a/contracts/svm/programs/express_relay/Cargo.toml +++ b/contracts/svm/programs/express_relay/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "express-relay" -version = "0.5.0" +version = "0.6.0" description = "Pyth Express Relay program for handling permissioning and bid distribution" repository = "https://github.com/pyth-network/per" license = "Apache-2.0" diff --git a/contracts/svm/programs/express_relay/src/lib.rs b/contracts/svm/programs/express_relay/src/lib.rs index b24d4c5d..c4d86b1d 100644 --- a/contracts/svm/programs/express_relay/src/lib.rs +++ b/contracts/svm/programs/express_relay/src/lib.rs @@ -403,7 +403,7 @@ pub struct Swap<'info> { token::authority = searcher, token::token_program = token_program_searcher )] - pub searcher_ta_mint_searcher: InterfaceAccount<'info, TokenAccount>, + pub searcher_ta_mint_searcher: Box>, #[account( mut, @@ -411,7 +411,7 @@ pub struct Swap<'info> { token::authority = searcher, token::token_program = token_program_user )] - pub searcher_ta_mint_user: InterfaceAccount<'info, TokenAccount>, + pub searcher_ta_mint_user: Box>, // User accounts #[account( @@ -420,7 +420,7 @@ pub struct Swap<'info> { associated_token::authority = user, associated_token::token_program = token_program_searcher )] - pub user_ata_mint_searcher: InterfaceAccount<'info, TokenAccount>, + pub user_ata_mint_searcher: Box>, #[account( mut, @@ -428,7 +428,7 @@ pub struct Swap<'info> { associated_token::authority = user, associated_token::token_program = token_program_user )] - pub user_ata_mint_user: InterfaceAccount<'info, TokenAccount>, + pub user_ata_mint_user: Box>, // Fee receivers /// Router fee receiver token account: the referrer can provide an arbitrary receiver for the router fee @@ -437,7 +437,7 @@ pub struct Swap<'info> { token::mint = mint_fee, token::token_program = token_program_fee )] - pub router_fee_receiver_ta: InterfaceAccount<'info, TokenAccount>, + pub router_fee_receiver_ta: Box>, #[account( mut, @@ -445,7 +445,7 @@ pub struct Swap<'info> { associated_token::authority = express_relay_metadata.fee_receiver_relayer, associated_token::token_program = token_program_fee )] - pub relayer_fee_receiver_ata: InterfaceAccount<'info, TokenAccount>, + pub relayer_fee_receiver_ata: Box>, #[account( mut, @@ -453,20 +453,20 @@ pub struct Swap<'info> { associated_token::authority = express_relay_metadata.key(), associated_token::token_program = token_program_fee )] - pub express_relay_fee_receiver_ata: InterfaceAccount<'info, TokenAccount>, + pub express_relay_fee_receiver_ata: Box>, // Mints #[account(mint::token_program = token_program_searcher)] - pub mint_searcher: InterfaceAccount<'info, Mint>, + pub mint_searcher: Box>, #[account(mint::token_program = token_program_user)] - pub mint_user: InterfaceAccount<'info, Mint>, + pub mint_user: Box>, #[account( mint::token_program = token_program_fee, constraint = mint_fee.key() == if data.fee_token == FeeToken::Searcher { mint_searcher.key() } else { mint_user.key() } )] - pub mint_fee: InterfaceAccount<'info, Mint>, + pub mint_fee: Box>, // Token programs pub token_program_searcher: Interface<'info, TokenInterface>, @@ -478,6 +478,8 @@ pub struct Swap<'info> { pub token_program_fee: Interface<'info, TokenInterface>, /// Express relay configuration - #[account(seeds = [SEED_METADATA], bump)] + #[account(seeds = [SEED_METADATA], bump, has_one = relayer_signer)] pub express_relay_metadata: Box>, + + pub relayer_signer: Signer<'info>, } diff --git a/contracts/svm/programs/express_relay/src/sdk/helpers.rs b/contracts/svm/programs/express_relay/src/sdk/helpers.rs index d2b432bb..1f1ea676 100644 --- a/contracts/svm/programs/express_relay/src/sdk/helpers.rs +++ b/contracts/svm/programs/express_relay/src/sdk/helpers.rs @@ -110,6 +110,7 @@ pub fn create_swap_instruction( token_program_searcher: Pubkey, token_program_user: Pubkey, swap_args: SwapArgs, + relayer_signer: Pubkey, ) -> Instruction { let express_relay_metadata = Pubkey::find_program_address(&[SEED_METADATA], &express_relay_pid).0; @@ -119,7 +120,7 @@ pub fn create_swap_instruction( FeeToken::User => (mint_user, token_program_user), }; - let accounts_submit_bid = accounts::Swap { + let accounts_swap = accounts::Swap { searcher, user, searcher_ta_mint_searcher: searcher_ta_mint_searcher.unwrap_or( @@ -164,13 +165,14 @@ pub fn create_swap_instruction( token_program_user, token_program_fee, express_relay_metadata, + relayer_signer, } .to_account_metas(None); let data_submit_bid = instruction::Swap { data: swap_args }.data(); Instruction { program_id: express_relay_pid, - accounts: accounts_submit_bid, + accounts: accounts_swap, data: data_submit_bid, } } diff --git a/contracts/svm/testing/src/express_relay/swap.rs b/contracts/svm/testing/src/express_relay/swap.rs index 06fadbd7..6f323417 100644 --- a/contracts/svm/testing/src/express_relay/swap.rs +++ b/contracts/svm/testing/src/express_relay/swap.rs @@ -42,6 +42,7 @@ pub fn create_swap_instruction( swap_args: SwapArgs, user_ata_mint_user_override: Option, mint_fee_override: Option, + relayer_signer: Pubkey, ) -> Instruction { let express_relay_metadata = get_express_relay_metadata_key(); @@ -100,6 +101,7 @@ pub fn create_swap_instruction( token_program_user, token_program_fee, express_relay_metadata, + relayer_signer, } .to_account_metas(None); @@ -127,6 +129,7 @@ pub fn build_swap_instructions( swap_args: SwapArgs, user_ata_mint_user_override: Option, mint_fee_override: Option, + relayer_signer: Pubkey, ) -> Vec { let mut instructions: Vec = vec![]; @@ -183,6 +186,7 @@ pub fn build_swap_instructions( swap_args, user_ata_mint_user_override, mint_fee_override, + relayer_signer, )); instructions diff --git a/contracts/svm/testing/tests/swap.rs b/contracts/svm/testing/tests/swap.rs index cf34658d..bb3a903e 100644 --- a/contracts/svm/testing/tests/swap.rs +++ b/contracts/svm/testing/tests/swap.rs @@ -200,6 +200,7 @@ pub struct SwapSetupResult { pub token_user: Token, pub router_ta_mint_searcher: Pubkey, pub router_ta_mint_user: Pubkey, + pub relayer_signer: Keypair, } pub fn setup_swap(args: SwapSetupParams) -> SwapSetupResult { @@ -207,6 +208,7 @@ pub fn setup_swap(args: SwapSetupParams) -> SwapSetupResult { mut svm, admin, searcher, + relayer_signer, .. } = setup(None).expect("setup failed"); @@ -237,6 +239,7 @@ pub fn setup_swap(args: SwapSetupParams) -> SwapSetupResult { token_user, router_ta_mint_searcher, router_ta_mint_user, + relayer_signer, } } @@ -285,6 +288,7 @@ fn test_swap_fee_mint_searcher(args: SwapSetupParams) { token_user, router_ta_mint_searcher, router_ta_mint_user, + relayer_signer, } = setup_swap(args); let express_relay_metadata = get_express_relay_metadata(&mut svm); @@ -365,8 +369,15 @@ fn test_swap_fee_mint_searcher(args: SwapSetupParams) { swap_args, None, None, + relayer_signer.pubkey(), ); - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap(); + submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap(); // searcher token balances assert!(Token::token_balance_matches( @@ -432,6 +443,7 @@ fn test_swap_fee_mint_user(args: SwapSetupParams) { token_user, router_ta_mint_searcher, router_ta_mint_user, + relayer_signer, } = setup_swap(args); let express_relay_metadata = get_express_relay_metadata(&mut svm); @@ -512,8 +524,15 @@ fn test_swap_fee_mint_user(args: SwapSetupParams) { swap_args, None, None, + relayer_signer.pubkey(), ); - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap(); + submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap(); // searcher token balances assert!(Token::token_balance_matches( @@ -579,6 +598,7 @@ fn test_swap_expired_deadline() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -613,9 +633,15 @@ fn test_swap_expired_deadline() { swap_args, None, None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, @@ -632,6 +658,7 @@ fn test_swap_invalid_referral_fee_bps() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -665,9 +692,15 @@ fn test_swap_invalid_referral_fee_bps() { swap_args, None, None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, @@ -684,6 +717,7 @@ fn test_swap_fee_calculation_overflow() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 5000, // <--- high platform fee bps @@ -717,9 +751,15 @@ fn test_swap_fee_calculation_overflow() { swap_args, None, None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error(result.err, 4, InstructionError::ArithmeticOverflow); } @@ -732,6 +772,7 @@ fn test_swap_router_ta_has_wrong_mint() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -765,9 +806,15 @@ fn test_swap_router_ta_has_wrong_mint() { swap_args, None, None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, @@ -784,6 +831,7 @@ fn test_swap_searcher_ta_has_wrong_mint() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -820,9 +868,15 @@ fn test_swap_searcher_ta_has_wrong_mint() { swap_args, None, None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, @@ -839,6 +893,7 @@ fn test_swap_searcher_ta_wrong_owner() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -872,9 +927,15 @@ fn test_swap_searcher_ta_wrong_owner() { swap_args, None, None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, @@ -891,6 +952,7 @@ fn test_swap_wrong_express_relay_fee_receiver() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -922,9 +984,15 @@ fn test_swap_wrong_express_relay_fee_receiver() { swap_args, None, None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, @@ -941,6 +1009,7 @@ fn test_swap_user_ata_mint_user_is_not_ata() { token_searcher, token_user, router_ta_mint_user, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -975,9 +1044,15 @@ fn test_swap_user_ata_mint_user_is_not_ata() { swap_args, Some(user_ata_mint_user), // <--- user ata (of mint_user) is not an ata None, + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, @@ -994,6 +1069,7 @@ fn test_swap_wrong_mint_fee() { token_searcher, token_user, router_ta_mint_searcher, + relayer_signer, .. } = setup_swap(SwapSetupParams { platform_fee_bps: 1000, @@ -1027,9 +1103,15 @@ fn test_swap_wrong_mint_fee() { swap_args, None, Some(token_searcher.mint), // <--- wrong mint fee + relayer_signer.pubkey(), ); - let result = - submit_transaction(&mut svm, &instructions, &searcher, &[&searcher, &user]).unwrap_err(); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &relayer_signer], + ) + .unwrap_err(); assert_custom_error( result.err, 4, diff --git a/sdk/rust/simple-searcher/src/lib.rs b/sdk/rust/simple-searcher/src/lib.rs index ceb9196b..36452b58 100644 --- a/sdk/rust/simple-searcher/src/lib.rs +++ b/sdk/rust/simple-searcher/src/lib.rs @@ -215,16 +215,16 @@ impl SimpleSearcher { // .to_bytes() // .into(), // signers: vec![payer], + // relayer_signer: metadata + // .relayer_signer + // .to_bytes() + // .into(), // program_params: svm::ProgramParams::Limo( // svm::ProgramParamsLimo { // router: Pubkey::from_str( // "FjgAP9DWiSmULyUKwMrMTTfwdGJeMz22Bcibzq4ijzPR", // ) // .expect("Failed to parse pubkey"), - // relayer_signer: metadata - // .relayer_signer - // .to_bytes() - // .into(), // permission: order_address, // }, // ), @@ -266,6 +266,7 @@ impl SimpleSearcher { .to_bytes() .into(), signers: vec![payer], + relayer_signer: metadata.relayer_signer.to_bytes().into(), program_params: svm::ProgramParams::Swap( svm::ProgramParamsSwap {}, ), diff --git a/sdk/rust/src/lib.rs b/sdk/rust/src/lib.rs index 403f7235..0dfa1a71 100644 --- a/sdk/rust/src/lib.rs +++ b/sdk/rust/src/lib.rs @@ -731,7 +731,7 @@ impl Biddable for api_types::opportunity::OpportunitySvm { searcher: params.searcher, permission: program_params.permission, router: program_params.router, - relayer_signer: program_params.relayer_signer, + relayer_signer: params.relayer_signer, fee_receiver_relayer: params.fee_receiver_relayer, }, )?); @@ -799,6 +799,7 @@ impl Biddable for api_types::opportunity::OpportunitySvm { deadline: params.deadline, searcher: params.searcher, fee_receiver_relayer: params.fee_receiver_relayer, + relayer_signer: params.relayer_signer, })?); let mut transaction = Transaction::new_with_payer(instructions.as_slice(), Some(¶ms.payer)); diff --git a/sdk/rust/src/svm.rs b/sdk/rust/src/svm.rs index 2517b992..ca9a64e7 100644 --- a/sdk/rust/src/svm.rs +++ b/sdk/rust/src/svm.rs @@ -32,9 +32,8 @@ use { }; pub struct ProgramParamsLimo { - pub permission: Pubkey, - pub router: Pubkey, - pub relayer_signer: Pubkey, + pub permission: Pubkey, + pub router: Pubkey, } pub struct ProgramParamsSwap {} @@ -54,6 +53,7 @@ pub struct NewBidParams { pub searcher: Pubkey, pub signers: Vec, pub fee_receiver_relayer: Pubkey, + pub relayer_signer: Pubkey, pub program_params: ProgramParams, } @@ -74,6 +74,7 @@ pub struct GetSwapInstructionParams { pub bid_amount: u64, pub deadline: i64, pub fee_receiver_relayer: Pubkey, + pub relayer_signer: Pubkey, } struct OpportunitySwapData { @@ -299,7 +300,6 @@ impl Svm { let OpportunityParamsSvm::V1(opportunity_params) = params.opportunity_params; let chain_id = opportunity_params.chain_id; - let bid_amount = match (&swap_data.tokens.tokens, &swap_data.fee_token) { // scale bid amount by FEE_SPLIT_PRECISION/(FEE_SPLIT_PRECISION-fees) to account for fees (QuoteTokens::SearcherTokenSpecified { .. }, ApiFeeToken::UserToken) => { @@ -399,6 +399,7 @@ impl Svm { AccountMeta::new_readonly(token_program_user, false), AccountMeta::new_readonly(fee_token_program, false), AccountMeta::new_readonly(*express_relay_metadata, false), + AccountMeta::new_readonly(params.relayer_signer, true), ]; let swap_args = SwapArgs { diff --git a/tilt-scripts/svm/test_swap.py b/tilt-scripts/svm/test_swap.py index 785fc721..e60ab406 100644 --- a/tilt-scripts/svm/test_swap.py +++ b/tilt-scripts/svm/test_swap.py @@ -84,13 +84,15 @@ async def main(): response = result.json() logger.info(response) tx = SoldersTransaction.from_bytes(base64.b64decode(response["transaction"])) + accounts = tx.message.account_keys tx = Transaction.from_solders(tx) tx.sign_partial(kp_taker) + position = accounts.index(pk_taker) reference_id = response["reference_id"] payload = { "reference_id": reference_id, - "user_signature": str(tx.signatures[1]), + "user_signature": str(tx.signatures[position]), } await asyncio.sleep(3) result = await http_client.post( From a8f3db8c8b8a38975abbcc8967f26717d4895b26 Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Tue, 4 Feb 2025 14:28:13 +0100 Subject: [PATCH 2/6] Fix py and js sdks --- Tiltfile | 2 +- sdk/js/src/examples/simpleSearcherSvm.ts | 10 +- sdk/js/src/expressRelayTypes.d.ts | 7 +- sdk/js/src/idl/idlExpressRelay.json | 7 +- sdk/js/src/index.ts | 3 + sdk/js/src/serverTypes.d.ts | 119 +++- sdk/js/src/svm.ts | 8 +- sdk/python/README.md | 2 +- sdk/python/express_relay/client.py | 6 +- .../express_relay/idl/idlExpressRelay.json | 7 +- sdk/python/express_relay/models/base.py | 2 + sdk/python/express_relay/models/svm.py | 9 +- .../searcher/examples/simple_searcher_svm.py | 9 +- .../svm/generated/accounts/__init__.py | 2 + .../svm/generated/accounts/config_router.py | 85 +++ .../accounts/express_relay_metadata.py | 112 ++++ .../svm/generated/errors/__init__.py | 29 + .../svm/generated/errors/anchor.py | 590 ++++++++++++++++++ .../svm/generated/errors/custom.py | 114 ++++ .../express_relay/instructions/swap.py | 4 + .../svm/generated/instructions/__init__.py | 18 + .../instructions/check_permission.py | 41 ++ .../svm/generated/instructions/initialize.py | 55 ++ .../svm/generated/instructions/set_admin.py | 31 + .../svm/generated/instructions/set_relayer.py | 37 ++ .../instructions/set_router_split.py | 53 ++ .../svm/generated/instructions/set_splits.py | 43 ++ .../instructions/set_swap_platform_fee.py | 45 ++ .../svm/generated/instructions/submit_bid.py | 65 ++ .../svm/generated/instructions/swap.py | 107 ++++ .../generated/instructions/withdraw_fees.py | 33 + .../express_relay/svm/generated/program_id.py | 3 + .../svm/generated/types/__init__.py | 18 + .../svm/generated/types/fee_token.py | 75 +++ .../svm/generated/types/initialize_args.py | 45 ++ .../generated/types/set_router_split_args.py | 29 + .../svm/generated/types/set_splits_args.py | 45 ++ .../types/set_swap_platform_fee_args.py | 29 + .../svm/generated/types/submit_bid_args.py | 33 + .../svm/generated/types/swap_args.py | 70 +++ tilt-scripts/svm/initialize_programs.py | 14 +- tilt-scripts/svm/setup_accounts.py | 1 + 42 files changed, 1993 insertions(+), 24 deletions(-) create mode 100644 sdk/python/express_relay/svm/generated/accounts/__init__.py create mode 100644 sdk/python/express_relay/svm/generated/accounts/config_router.py create mode 100644 sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py create mode 100644 sdk/python/express_relay/svm/generated/errors/__init__.py create mode 100644 sdk/python/express_relay/svm/generated/errors/anchor.py create mode 100644 sdk/python/express_relay/svm/generated/errors/custom.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/__init__.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/check_permission.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/initialize.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/set_admin.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/set_relayer.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/set_router_split.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/set_splits.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/submit_bid.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/swap.py create mode 100644 sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py create mode 100644 sdk/python/express_relay/svm/generated/program_id.py create mode 100644 sdk/python/express_relay/svm/generated/types/__init__.py create mode 100644 sdk/python/express_relay/svm/generated/types/fee_token.py create mode 100644 sdk/python/express_relay/svm/generated/types/initialize_args.py create mode 100644 sdk/python/express_relay/svm/generated/types/set_router_split_args.py create mode 100644 sdk/python/express_relay/svm/generated/types/set_splits_args.py create mode 100644 sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py create mode 100644 sdk/python/express_relay/svm/generated/types/submit_bid_args.py create mode 100644 sdk/python/express_relay/svm/generated/types/swap_args.py diff --git a/Tiltfile b/Tiltfile index 10227352..54e475ec 100644 --- a/Tiltfile +++ b/Tiltfile @@ -186,7 +186,7 @@ local_resource( # need to run initialize instructions for the programs one time, script skips if already initialized local_resource( "svm-initialize-programs", - "poetry -C tilt-scripts run python3 -m tilt-scripts.svm.initialize_programs -v --file-private-key-payer keypairs/searcher_py.json --file-private-key-admin keypairs/admin.json --file-private-key-relayer-signer keypairs/relayer_signer.json --express-relay-program PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou --rpc-url %s" % rpc_url_solana, + "poetry -C tilt-scripts run python3 -m tilt-scripts.svm.initialize_programs -v --file-private-key-payer keypairs/searcher_py.json --file-private-key-admin keypairs/admin.json --file-private-key-relayer-signer keypairs/relayer_signer.json --file-private-key-fee-receiver-relayer keypairs/fee_receiver_relayer.json --express-relay-program PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou --rpc-url %s" % rpc_url_solana, resource_deps=["svm-setup-accounts"] ) diff --git a/sdk/js/src/examples/simpleSearcherSvm.ts b/sdk/js/src/examples/simpleSearcherSvm.ts index 9431dc36..3021e7cf 100644 --- a/sdk/js/src/examples/simpleSearcherSvm.ts +++ b/sdk/js/src/examples/simpleSearcherSvm.ts @@ -75,7 +75,14 @@ export class SimpleSearcherSvm { async bidStatusHandler(bidStatus: BidStatusUpdate) { let resultDetails = ""; - if (bidStatus.type == "submitted" || bidStatus.type == "won") { + if ( + bidStatus.type == "submitted" || + bidStatus.type == "won" || + bidStatus.type == "expired" || + bidStatus.type == "cancelled" || + bidStatus.type == "failed" || + bidStatus.type == "awaiting_signature" + ) { resultDetails = `, transaction ${bidStatus.result}`; } else if (bidStatus.type == "lost") { if (bidStatus.result) { @@ -163,6 +170,7 @@ export class SimpleSearcherSvm { bidAmount, new anchor.BN(Math.round(Date.now() / 1000 + DAY_IN_SECONDS)), this.chainId, + config.feeReceiverRelayer, config.relayerSigner, ); diff --git a/sdk/js/src/expressRelayTypes.d.ts b/sdk/js/src/expressRelayTypes.d.ts index 11f91ad9..6ef90e3c 100644 --- a/sdk/js/src/expressRelayTypes.d.ts +++ b/sdk/js/src/expressRelayTypes.d.ts @@ -8,7 +8,7 @@ export type ExpressRelay = { address: "PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou"; metadata: { name: "expressRelay"; - version: "0.5.0"; + version: "0.6.0"; spec: "0.1.0"; description: "Pyth Express Relay program for handling permissioning and bid distribution"; repository: "https://github.com/pyth-network/per"; @@ -694,6 +694,11 @@ export type ExpressRelay = { ]; }; }, + { + name: "relayerSigner"; + signer: true; + relations: ["expressRelayMetadata"]; + }, ]; args: [ { diff --git a/sdk/js/src/idl/idlExpressRelay.json b/sdk/js/src/idl/idlExpressRelay.json index 979a8280..267828c1 100644 --- a/sdk/js/src/idl/idlExpressRelay.json +++ b/sdk/js/src/idl/idlExpressRelay.json @@ -2,7 +2,7 @@ "address": "PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou", "metadata": { "name": "express_relay", - "version": "0.5.0", + "version": "0.6.0", "spec": "0.1.0", "description": "Pyth Express Relay program for handling permissioning and bid distribution", "repository": "https://github.com/pyth-network/per" @@ -535,6 +535,11 @@ } ] } + }, + { + "name": "relayer_signer", + "signer": true, + "relations": ["express_relay_metadata"] } ], "args": [ diff --git a/sdk/js/src/index.ts b/sdk/js/src/index.ts index 8192d0a5..57eb1b42 100644 --- a/sdk/js/src/index.ts +++ b/sdk/js/src/index.ts @@ -859,6 +859,7 @@ export class Client { * @param bidAmount The amount of the bid in either searcher side or user side tokens depending on the swap opportunity * @param deadline The deadline for the bid in seconds since Unix epoch * @param chainId The chain ID as a string, e.g. "solana" + * @param feeReceiverRelayer The fee collection address of the relayer * @param relayerSigner The address of the relayer that is handling the bid */ async constructSwapBid( @@ -868,6 +869,7 @@ export class Client { bidAmount: anchor.BN, deadline: anchor.BN, chainId: string, + feeReceiverRelayer: PublicKey, relayerSigner: PublicKey, ): Promise { return svm.constructSwapBid( @@ -877,6 +879,7 @@ export class Client { bidAmount, deadline, chainId, + feeReceiverRelayer, relayerSigner, ); } diff --git a/sdk/js/src/serverTypes.d.ts b/sdk/js/src/serverTypes.d.ts index ee389ab9..0d1580e5 100644 --- a/sdk/js/src/serverTypes.d.ts +++ b/sdk/js/src/serverTypes.d.ts @@ -86,6 +86,22 @@ export interface paths { /** Query the status of a specific bid. */ get: operations["get_bid_status"]; }; + "/v1/{chain_id}/bids/{bid_id}/cancel": { + /** + * Cancel a specific bid. + * @description Bids can only be cancelled if they are in the awaiting signature state. + * Only the user who created the bid can cancel it. + */ + post: operations["post_cancel_bid"]; + }; + "/v1/{chain_id}/quotes/submit": { + /** + * Signs and submits the transaction for the specified quote. + * @description Server will verify the quote and checks if the quote is still valid. + * If the quote is valid, the server will submit the transaction to the blockchain. + */ + post: operations["post_submit_quote"]; + }; } export type webhooks = Record; @@ -94,6 +110,19 @@ export interface components { schemas: { APIResponse: components["schemas"]["BidResult"]; Bid: components["schemas"]["BidEvm"] | components["schemas"]["BidSvm"]; + BidCancel: components["schemas"]["BidCancelSvm"]; + BidCancelSvm: { + /** + * @description The id of the bid to cancel. + * @example obo3ee3e-58cc-4372-a567-0e02b2c3d479 + */ + bid_id: string; + /** + * @description The chain id of the bid to cancel. + * @example solana + */ + chain_id: string; + }; BidCreate: | components["schemas"]["BidCreateEvm"] | components["schemas"]["BidCreateSvm"]; @@ -230,8 +259,8 @@ export interface components { status: string; }; BidStatus: - | components["schemas"]["BidStatusEvm"] - | components["schemas"]["BidStatusSvm"]; + | components["schemas"]["BidStatusSvm"] + | components["schemas"]["BidStatusEvm"]; BidStatusEvm: OneOf< [ { @@ -278,6 +307,12 @@ export interface components { /** @enum {string} */ type: "pending"; } + | { + /** @example Jb2urXPyEh4xiBgzYvwEFe4q1iMxG1DNxWGGQg94AmKgqFTwLAiTiHrYiYxwHUB4DV8u5ahNEVtMMDm3sNSRdTg */ + result: string; + /** @enum {string} */ + type: "awaiting_signature"; + } | { /** @example Jb2urXPyEh4xiBgzYvwEFe4q1iMxG1DNxWGGQg94AmKgqFTwLAiTiHrYiYxwHUB4DV8u5ahNEVtMMDm3sNSRdTg */ result?: string | null; @@ -307,6 +342,12 @@ export interface components { result: string; /** @enum {string} */ type: "expired"; + } + | { + /** @example Jb2urXPyEh4xiBgzYvwEFe4q1iMxG1DNxWGGQg94AmKgqFTwLAiTiHrYiYxwHUB4DV8u5ahNEVtMMDm3sNSRdTg */ + result: string; + /** @enum {string} */ + type: "cancelled"; }; BidStatusWithId: { bid_status: components["schemas"]["BidStatus"]; @@ -388,6 +429,13 @@ export interface components { opportunity_id: string; }; }, + { + /** @enum {string} */ + method: "cancel_bid"; + params: { + data: components["schemas"]["BidCancel"]; + }; + }, ] >; ClientRequest: components["schemas"]["ClientMessage"] & { @@ -857,6 +905,11 @@ export interface components { output_token: components["schemas"]["TokenAmountSvm"]; /** @description The token and amount of the platform fee paid to the Express Relay program and relayer. */ platform_fee: components["schemas"]["TokenAmountSvm"]; + /** + * @description The reference id for the quote. + * @example beedbeed-58cc-4372-a567-0e02b2c3d479 + */ + reference_id: string; /** @description The token and amount of the referral fee paid to the party that routed the swap request to Express Relay. */ referrer_fee: components["schemas"]["TokenAmountSvm"]; /** @@ -946,6 +999,28 @@ export interface components { }, ] >; + /** @description Parameters needed to submit a quote from server. */ + SubmitQuote: { + /** + * @description The reference id for the quote that should be submitted. + * @example beedbeed-58cc-4372-a567-0e02b2c3d479 + */ + reference_id: string; + /** + * @description The signature of the user for the quote. + * @example Jb2urXPyEh4xiBgzYvwEFe4q1iMxG1DNxWGGQg94AmKgqFTwLAiTiHrYiYxwHUB4DV8u5ahNEVtMMDm3sNSRdTg + */ + user_signature: string; + }; + /** @description Response to a quote submission. */ + SubmitQuoteResponse: { + /** + * @description The fully signed versioned transaction that was submitted. + * The transaction is encoded in base64. + * @example SGVsbG8sIFdvcmxkIQ== + */ + transaction: string; + }; SvmChainUpdate: { /** @example SLxp9LxX1eE9Z5v99Y92DaYEwyukFgMUF6zRerCF12j */ blockhash: string; @@ -1330,4 +1405,44 @@ export interface operations { }; }; }; + /** + * Cancel a specific bid. + * @description Bids can only be cancelled if they are in the awaiting signature state. + * Only the user who created the bid can cancel it. + */ + post_cancel_bid: { + responses: { + /** @description Bid was cancelled successfully */ + 200: { + content: never; + }; + 400: components["responses"]["ErrorBodyResponse"]; + /** @description Chain id was not found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorBodyResponse"]; + }; + }; + }; + }; + /** + * Signs and submits the transaction for the specified quote. + * @description Server will verify the quote and checks if the quote is still valid. + * If the quote is valid, the server will submit the transaction to the blockchain. + */ + post_submit_quote: { + requestBody: { + content: { + "application/json": components["schemas"]["SubmitQuote"]; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["SubmitQuoteResponse"]; + }; + }; + 400: components["responses"]["ErrorBodyResponse"]; + }; + }; } diff --git a/sdk/js/src/svm.ts b/sdk/js/src/svm.ts index 7f513002..7d85d65f 100644 --- a/sdk/js/src/svm.ts +++ b/sdk/js/src/svm.ts @@ -133,6 +133,7 @@ export async function constructSwapInstruction( bidAmount: anchor.BN, deadline: anchor.BN, chainId: string, + feeReceiverRelayer: PublicKey, relayerSigner: PublicKey, ): Promise { const expressRelay = new Program( @@ -222,7 +223,7 @@ export async function constructSwapInstruction( feeTokenProgram, ), relayerFeeReceiverAta: getAssociatedTokenAddress( - relayerSigner, + feeReceiverRelayer, mintFee, feeTokenProgram, ), @@ -233,6 +234,7 @@ export async function constructSwapInstruction( mintFee, feeTokenProgram, ), + relayerSigner, }) .instruction(); ixSwap.programId = svmConstants.expressRelayProgram; @@ -278,6 +280,7 @@ export async function constructSwapBid( bidAmount: anchor.BN, deadline: anchor.BN, chainId: string, + feeReceiverRelayer: PublicKey, relayerSigner: PublicKey, ): Promise { const expressRelayMetadata = getExpressRelayMetadataPda(chainId); @@ -290,7 +293,7 @@ export async function constructSwapBid( router, } = extractSwapInfo(swapOpportunity); const tokenAccountsToCreate = [ - { owner: relayerSigner, mint: mintFee, program: feeTokenProgram }, + { owner: feeReceiverRelayer, mint: mintFee, program: feeTokenProgram }, { owner: expressRelayMetadata, mint: mintFee, program: feeTokenProgram }, { owner: user, mint: userToken, program: tokenProgramUser }, ]; @@ -317,6 +320,7 @@ export async function constructSwapBid( bidAmount, deadline, chainId, + feeReceiverRelayer, relayerSigner, ); tx.instructions.push(swapInstruction); diff --git a/sdk/python/README.md b/sdk/python/README.md index eaedf302..ea3ceddd 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -19,7 +19,7 @@ You can use `anchorpy` to generate a Python client of the Express Relay program. You can generate the Python client from the IDL via: ```bash -anchorpy client-gen express_relay/idl/idlExpressRelay.json express_relay/svm/generated/ --program-id PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfountagged +poetry run anchorpy client-gen express_relay/idl/idlExpressRelay.json express_relay/svm/generated/express_relay --program-id PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou ``` ## Quickstart diff --git a/sdk/python/express_relay/client.py b/sdk/python/express_relay/client.py index 8904cbc5..0366b2a5 100644 --- a/sdk/python/express_relay/client.py +++ b/sdk/python/express_relay/client.py @@ -573,6 +573,7 @@ def get_svm_swap_instructions( deadline: int, chain_id: str, swap_opportunity: SwapOpportunitySvm, + fee_receiver_relayer: Pubkey, relayer_signer: Pubkey, ) -> List[Instruction]: if chain_id not in SVM_CONFIGS: @@ -612,7 +613,7 @@ def get_svm_swap_instructions( token_accounts_to_create = [ { - "owner": relayer_signer, + "owner": fee_receiver_relayer, "mint": accs["mint_fee"], "program": accs["fee_token_program"], }, @@ -679,7 +680,7 @@ def get_svm_swap_instructions( accs["router"], accs["mint_fee"], accs["fee_token_program"] ), "relayer_fee_receiver_ata": get_ata( - relayer_signer, accs["mint_fee"], accs["fee_token_program"] + fee_receiver_relayer, accs["mint_fee"], accs["fee_token_program"] ), "express_relay_fee_receiver_ata": get_ata( express_relay_metadata, accs["mint_fee"], accs["fee_token_program"] @@ -691,6 +692,7 @@ def get_svm_swap_instructions( "token_program_user": accs["token_program_user"], "token_program_fee": accs["fee_token_program"], "express_relay_metadata": express_relay_metadata, + "relayer_signer": relayer_signer, }, svm_config["express_relay_program"], ) diff --git a/sdk/python/express_relay/idl/idlExpressRelay.json b/sdk/python/express_relay/idl/idlExpressRelay.json index a5550ca1..34455439 100644 --- a/sdk/python/express_relay/idl/idlExpressRelay.json +++ b/sdk/python/express_relay/idl/idlExpressRelay.json @@ -1,5 +1,5 @@ { - "version": "0.5.0", + "version": "0.6.0", "name": "express_relay", "instructions": [ { @@ -383,6 +383,11 @@ "isMut": false, "isSigner": false, "docs": ["Express relay configuration"] + }, + { + "name": "relayerSigner", + "isMut": false, + "isSigner": true } ], "args": [ diff --git a/sdk/python/express_relay/models/base.py b/sdk/python/express_relay/models/base.py index 9e86ff9a..ecda8608 100644 --- a/sdk/python/express_relay/models/base.py +++ b/sdk/python/express_relay/models/base.py @@ -26,11 +26,13 @@ class BidStatusVariantsEvm(Enum): class BidStatusVariantsSvm(Enum): PENDING = "pending" + AWAITING_SIGNATURE = "awaiting_signature" SUBMITTED = "submitted" LOST = "lost" WON = "won" FAILED = "failed" EXPIRED = "expired" + CANCELLED = "cancelled" IntString = Annotated[int, PlainSerializer(lambda x: str(x), return_type=str)] diff --git a/sdk/python/express_relay/models/svm.py b/sdk/python/express_relay/models/svm.py index 4e49a713..3b6c14f6 100644 --- a/sdk/python/express_relay/models/svm.py +++ b/sdk/python/express_relay/models/svm.py @@ -359,7 +359,7 @@ class BidStatusSvm(BaseModel): """ Attributes: type: The current status of the bid. - result: The result of the bid: a transaction hash if the status is SUBMITTED or WON. + result: The result of the bid: a transaction hash if the status is not PENDING. The LOST status may have a result. """ @@ -368,13 +368,10 @@ class BidStatusSvm(BaseModel): @model_validator(mode="after") def check_result(self): - if ( - self.type == BidStatusVariantsSvm.WON - or self.type == BidStatusVariantsSvm.SUBMITTED - ): + if self.type not in [BidStatusVariantsSvm.PENDING, BidStatusVariantsSvm.LOST]: assert ( self.result is not None - ), "bid result should not be empty when status is won or submitted" + ), "bid result should not be empty when status is not pending or lost" return self diff --git a/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py b/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py index 2f03c534..e1d13889 100644 --- a/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py +++ b/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py @@ -122,10 +122,7 @@ async def bid_status_callback(self, bid_status_update: BidStatusUpdate): result = bid_status_update.bid_status.result result_details = "" - if ( - status == BidStatusVariantsSvm.SUBMITTED - or status == BidStatusVariantsSvm.WON - ): + if status not in [BidStatusVariantsSvm.PENDING, BidStatusVariantsSvm.LOST]: result_details = f", transaction {result}" elif status == BidStatusVariantsSvm.LOST: if result: @@ -190,6 +187,7 @@ async def generate_bid_limo(self, opp: LimoOpportunitySvm) -> OnChainBidSvm: async def generate_bid_swap(self, opp: SwapOpportunitySvm) -> SwapBidSvm: bid_amount = await self.get_bid_amount(opp) + metadata = await self.get_metadata() swap_ixs = self.client.get_svm_swap_instructions( searcher=self.private_key.pubkey(), @@ -197,7 +195,8 @@ async def generate_bid_swap(self, opp: SwapOpportunitySvm) -> SwapBidSvm: deadline=DEADLINE, chain_id=self.chain_id, swap_opportunity=opp, - relayer_signer=(await self.get_metadata()).relayer_signer, + fee_receiver_relayer=metadata.fee_receiver_relayer, + relayer_signer=metadata.relayer_signer, ) latest_chain_update = self.latest_chain_update[self.chain_id] fee_instruction = set_compute_unit_price( diff --git a/sdk/python/express_relay/svm/generated/accounts/__init__.py b/sdk/python/express_relay/svm/generated/accounts/__init__.py new file mode 100644 index 00000000..8136b66e --- /dev/null +++ b/sdk/python/express_relay/svm/generated/accounts/__init__.py @@ -0,0 +1,2 @@ +from .express_relay_metadata import ExpressRelayMetadata, ExpressRelayMetadataJSON +from .config_router import ConfigRouter, ConfigRouterJSON diff --git a/sdk/python/express_relay/svm/generated/accounts/config_router.py b/sdk/python/express_relay/svm/generated/accounts/config_router.py new file mode 100644 index 00000000..c02ff788 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/accounts/config_router.py @@ -0,0 +1,85 @@ +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 ConfigRouterJSON(typing.TypedDict): + router: str + split: int + + +@dataclass +class ConfigRouter: + discriminator: typing.ClassVar = b"\x87B\xf0\xa6^\xc6\xbb$" + layout: typing.ClassVar = borsh.CStruct("router" / BorshPubkey, "split" / borsh.U64) + router: Pubkey + split: int + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["ConfigRouter"]: + 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["ConfigRouter"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["ConfigRouter"]] = [] + 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) -> "ConfigRouter": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = ConfigRouter.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + router=dec.router, + split=dec.split, + ) + + def to_json(self) -> ConfigRouterJSON: + return { + "router": str(self.router), + "split": self.split, + } + + @classmethod + def from_json(cls, obj: ConfigRouterJSON) -> "ConfigRouter": + return cls( + router=Pubkey.from_string(obj["router"]), + split=obj["split"], + ) diff --git a/sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py b/sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py new file mode 100644 index 00000000..8b5fac49 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py @@ -0,0 +1,112 @@ +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 ExpressRelayMetadataJSON(typing.TypedDict): + admin: str + relayer_signer: str + fee_receiver_relayer: str + split_router_default: int + split_relayer: int + swap_platform_fee_bps: int + + +@dataclass +class ExpressRelayMetadata: + discriminator: typing.ClassVar = b"\xccK\x85\x07\xaf\xf1\x82\x0b" + layout: typing.ClassVar = borsh.CStruct( + "admin" / BorshPubkey, + "relayer_signer" / BorshPubkey, + "fee_receiver_relayer" / BorshPubkey, + "split_router_default" / borsh.U64, + "split_relayer" / borsh.U64, + "swap_platform_fee_bps" / borsh.U64, + ) + admin: Pubkey + relayer_signer: Pubkey + fee_receiver_relayer: Pubkey + split_router_default: int + split_relayer: int + swap_platform_fee_bps: int + + @classmethod + async def fetch( + cls, + conn: AsyncClient, + address: Pubkey, + commitment: typing.Optional[Commitment] = None, + program_id: Pubkey = PROGRAM_ID, + ) -> typing.Optional["ExpressRelayMetadata"]: + 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["ExpressRelayMetadata"]]: + infos = await get_multiple_accounts(conn, addresses, commitment=commitment) + res: typing.List[typing.Optional["ExpressRelayMetadata"]] = [] + 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) -> "ExpressRelayMetadata": + if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: + raise AccountInvalidDiscriminator( + "The discriminator for this account is invalid" + ) + dec = ExpressRelayMetadata.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) + return cls( + admin=dec.admin, + relayer_signer=dec.relayer_signer, + fee_receiver_relayer=dec.fee_receiver_relayer, + split_router_default=dec.split_router_default, + split_relayer=dec.split_relayer, + swap_platform_fee_bps=dec.swap_platform_fee_bps, + ) + + def to_json(self) -> ExpressRelayMetadataJSON: + return { + "admin": str(self.admin), + "relayer_signer": str(self.relayer_signer), + "fee_receiver_relayer": str(self.fee_receiver_relayer), + "split_router_default": self.split_router_default, + "split_relayer": self.split_relayer, + "swap_platform_fee_bps": self.swap_platform_fee_bps, + } + + @classmethod + def from_json(cls, obj: ExpressRelayMetadataJSON) -> "ExpressRelayMetadata": + return cls( + admin=Pubkey.from_string(obj["admin"]), + relayer_signer=Pubkey.from_string(obj["relayer_signer"]), + fee_receiver_relayer=Pubkey.from_string(obj["fee_receiver_relayer"]), + split_router_default=obj["split_router_default"], + split_relayer=obj["split_relayer"], + swap_platform_fee_bps=obj["swap_platform_fee_bps"], + ) diff --git a/sdk/python/express_relay/svm/generated/errors/__init__.py b/sdk/python/express_relay/svm/generated/errors/__init__.py new file mode 100644 index 00000000..421993d0 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/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/sdk/python/express_relay/svm/generated/errors/anchor.py b/sdk/python/express_relay/svm/generated/errors/anchor.py new file mode 100644 index 00000000..3f266ef0 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/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/sdk/python/express_relay/svm/generated/errors/custom.py b/sdk/python/express_relay/svm/generated/errors/custom.py new file mode 100644 index 00000000..f5cdf2cf --- /dev/null +++ b/sdk/python/express_relay/svm/generated/errors/custom.py @@ -0,0 +1,114 @@ +import typing +from anchorpy.error import ProgramError + + +class FeeSplitLargerThanPrecision(ProgramError): + def __init__(self) -> None: + super().__init__(6000, "Fee split(s) larger than fee precision") + + code = 6000 + name = "FeeSplitLargerThanPrecision" + msg = "Fee split(s) larger than fee precision" + + +class FeesHigherThanBid(ProgramError): + def __init__(self) -> None: + super().__init__(6001, "Fees higher than bid") + + code = 6001 + name = "FeesHigherThanBid" + msg = "Fees higher than bid" + + +class DeadlinePassed(ProgramError): + def __init__(self) -> None: + super().__init__(6002, "Deadline passed") + + code = 6002 + name = "DeadlinePassed" + msg = "Deadline passed" + + +class InvalidCPISubmitBid(ProgramError): + def __init__(self) -> None: + super().__init__(6003, "Invalid CPI into submit bid instruction") + + code = 6003 + name = "InvalidCPISubmitBid" + msg = "Invalid CPI into submit bid instruction" + + +class MissingPermission(ProgramError): + def __init__(self) -> None: + super().__init__(6004, "Missing permission") + + code = 6004 + name = "MissingPermission" + msg = "Missing permission" + + +class MultiplePermissions(ProgramError): + def __init__(self) -> None: + super().__init__(6005, "Multiple permissions") + + code = 6005 + name = "MultiplePermissions" + msg = "Multiple permissions" + + +class InsufficientSearcherFunds(ProgramError): + def __init__(self) -> None: + super().__init__(6006, "Insufficient searcher funds") + + code = 6006 + name = "InsufficientSearcherFunds" + msg = "Insufficient searcher funds" + + +class InsufficientRent(ProgramError): + def __init__(self) -> None: + super().__init__(6007, "Insufficient funds for rent") + + code = 6007 + name = "InsufficientRent" + msg = "Insufficient funds for rent" + + +class InvalidReferralFee(ProgramError): + def __init__(self) -> None: + super().__init__(6008, "Invalid referral fee") + + code = 6008 + name = "InvalidReferralFee" + msg = "Invalid referral fee" + + +CustomError = typing.Union[ + FeeSplitLargerThanPrecision, + FeesHigherThanBid, + DeadlinePassed, + InvalidCPISubmitBid, + MissingPermission, + MultiplePermissions, + InsufficientSearcherFunds, + InsufficientRent, + InvalidReferralFee, +] +CUSTOM_ERROR_MAP: dict[int, CustomError] = { + 6000: FeeSplitLargerThanPrecision(), + 6001: FeesHigherThanBid(), + 6002: DeadlinePassed(), + 6003: InvalidCPISubmitBid(), + 6004: MissingPermission(), + 6005: MultiplePermissions(), + 6006: InsufficientSearcherFunds(), + 6007: InsufficientRent(), + 6008: InvalidReferralFee(), +} + + +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/sdk/python/express_relay/svm/generated/express_relay/instructions/swap.py b/sdk/python/express_relay/svm/generated/express_relay/instructions/swap.py index c4e1d1cf..c64255b7 100644 --- a/sdk/python/express_relay/svm/generated/express_relay/instructions/swap.py +++ b/sdk/python/express_relay/svm/generated/express_relay/instructions/swap.py @@ -31,6 +31,7 @@ class SwapAccounts(typing.TypedDict): token_program_user: Pubkey token_program_fee: Pubkey express_relay_metadata: Pubkey + relayer_signer: Pubkey def swap( @@ -90,6 +91,9 @@ def swap( is_signer=False, is_writable=False, ), + AccountMeta( + pubkey=accounts["relayer_signer"], is_signer=True, is_writable=False + ), ] if remaining_accounts is not None: keys += remaining_accounts diff --git a/sdk/python/express_relay/svm/generated/instructions/__init__.py b/sdk/python/express_relay/svm/generated/instructions/__init__.py new file mode 100644 index 00000000..c8e99467 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/__init__.py @@ -0,0 +1,18 @@ +from .initialize import initialize, InitializeArgs, InitializeAccounts +from .set_admin import set_admin, SetAdminAccounts +from .set_relayer import set_relayer, SetRelayerAccounts +from .set_splits import set_splits, SetSplitsArgs, SetSplitsAccounts +from .set_swap_platform_fee import ( + set_swap_platform_fee, + SetSwapPlatformFeeArgs, + SetSwapPlatformFeeAccounts, +) +from .set_router_split import ( + set_router_split, + SetRouterSplitArgs, + SetRouterSplitAccounts, +) +from .submit_bid import submit_bid, SubmitBidArgs, SubmitBidAccounts +from .check_permission import check_permission, CheckPermissionAccounts +from .withdraw_fees import withdraw_fees, WithdrawFeesAccounts +from .swap import swap, SwapArgs, SwapAccounts diff --git a/sdk/python/express_relay/svm/generated/instructions/check_permission.py b/sdk/python/express_relay/svm/generated/instructions/check_permission.py new file mode 100644 index 00000000..cefd03c1 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/check_permission.py @@ -0,0 +1,41 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class CheckPermissionAccounts(typing.TypedDict): + sysvar_instructions: Pubkey + permission: Pubkey + router: Pubkey + config_router: Pubkey + express_relay_metadata: Pubkey + + +def check_permission( + accounts: CheckPermissionAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta( + pubkey=accounts["sysvar_instructions"], is_signer=False, is_writable=False + ), + AccountMeta(pubkey=accounts["permission"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["router"], is_signer=False, is_writable=False), + AccountMeta( + pubkey=accounts["config_router"], is_signer=False, is_writable=False + ), + AccountMeta( + pubkey=accounts["express_relay_metadata"], + is_signer=False, + is_writable=False, + ), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x9a\xc7\xe8\xf2`H\xc5\xec" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/initialize.py b/sdk/python/express_relay/svm/generated/instructions/initialize.py new file mode 100644 index 00000000..ff01ffd7 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/initialize.py @@ -0,0 +1,55 @@ +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 .. import types +from ..program_id import PROGRAM_ID + + +class InitializeArgs(typing.TypedDict): + data: types.initialize_args.InitializeArgs + + +layout = borsh.CStruct("data" / types.initialize_args.InitializeArgs.layout) + + +class InitializeAccounts(typing.TypedDict): + payer: Pubkey + express_relay_metadata: Pubkey + admin: Pubkey + relayer_signer: Pubkey + fee_receiver_relayer: Pubkey + + +def initialize( + args: InitializeArgs, + accounts: InitializeAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True), + AccountMeta( + pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True + ), + AccountMeta(pubkey=accounts["admin"], is_signer=False, is_writable=False), + AccountMeta( + pubkey=accounts["relayer_signer"], is_signer=False, is_writable=False + ), + AccountMeta( + pubkey=accounts["fee_receiver_relayer"], 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"\xaf\xafm\x1f\r\x98\x9b\xed" + encoded_args = layout.build( + { + "data": args["data"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_admin.py b/sdk/python/express_relay/svm/generated/instructions/set_admin.py new file mode 100644 index 00000000..b010c9a9 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/set_admin.py @@ -0,0 +1,31 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class SetAdminAccounts(typing.TypedDict): + admin: Pubkey + express_relay_metadata: Pubkey + admin_new: Pubkey + + +def set_admin( + accounts: SetAdminAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), + AccountMeta( + pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True + ), + AccountMeta(pubkey=accounts["admin_new"], is_signer=False, is_writable=False), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xfb\xa3\x004[\xc2\xbb\\" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_relayer.py b/sdk/python/express_relay/svm/generated/instructions/set_relayer.py new file mode 100644 index 00000000..03f178a8 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/set_relayer.py @@ -0,0 +1,37 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class SetRelayerAccounts(typing.TypedDict): + admin: Pubkey + express_relay_metadata: Pubkey + relayer_signer: Pubkey + fee_receiver_relayer: Pubkey + + +def set_relayer( + accounts: SetRelayerAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), + AccountMeta( + pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["relayer_signer"], is_signer=False, is_writable=False + ), + AccountMeta( + pubkey=accounts["fee_receiver_relayer"], is_signer=False, is_writable=False + ), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x17\xf3!XnT\xc4%" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_router_split.py b/sdk/python/express_relay/svm/generated/instructions/set_router_split.py new file mode 100644 index 00000000..c7524d96 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/set_router_split.py @@ -0,0 +1,53 @@ +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 .. import types +from ..program_id import PROGRAM_ID + + +class SetRouterSplitArgs(typing.TypedDict): + data: types.set_router_split_args.SetRouterSplitArgs + + +layout = borsh.CStruct("data" / types.set_router_split_args.SetRouterSplitArgs.layout) + + +class SetRouterSplitAccounts(typing.TypedDict): + admin: Pubkey + config_router: Pubkey + express_relay_metadata: Pubkey + router: Pubkey + + +def set_router_split( + args: SetRouterSplitArgs, + accounts: SetRouterSplitAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=True), + AccountMeta( + pubkey=accounts["config_router"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["express_relay_metadata"], + is_signer=False, + is_writable=False, + ), + AccountMeta(pubkey=accounts["router"], 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"\x10\x96j\r\x1b\xbfh\x08" + encoded_args = layout.build( + { + "data": args["data"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_splits.py b/sdk/python/express_relay/svm/generated/instructions/set_splits.py new file mode 100644 index 00000000..3ca8ba80 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/set_splits.py @@ -0,0 +1,43 @@ +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 SetSplitsArgs(typing.TypedDict): + data: types.set_splits_args.SetSplitsArgs + + +layout = borsh.CStruct("data" / types.set_splits_args.SetSplitsArgs.layout) + + +class SetSplitsAccounts(typing.TypedDict): + admin: Pubkey + express_relay_metadata: Pubkey + + +def set_splits( + args: SetSplitsArgs, + accounts: SetSplitsAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), + AccountMeta( + pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True + ), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xaf\x02V1\xe1\xca\xe8\xbd" + encoded_args = layout.build( + { + "data": args["data"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py b/sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py new file mode 100644 index 00000000..2b599463 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py @@ -0,0 +1,45 @@ +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 SetSwapPlatformFeeArgs(typing.TypedDict): + data: types.set_swap_platform_fee_args.SetSwapPlatformFeeArgs + + +layout = borsh.CStruct( + "data" / types.set_swap_platform_fee_args.SetSwapPlatformFeeArgs.layout +) + + +class SetSwapPlatformFeeAccounts(typing.TypedDict): + admin: Pubkey + express_relay_metadata: Pubkey + + +def set_swap_platform_fee( + args: SetSwapPlatformFeeArgs, + accounts: SetSwapPlatformFeeAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), + AccountMeta( + pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True + ), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x02\x87K\x0f\x08i\x8e/" + encoded_args = layout.build( + { + "data": args["data"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/submit_bid.py b/sdk/python/express_relay/svm/generated/instructions/submit_bid.py new file mode 100644 index 00000000..1c471429 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/submit_bid.py @@ -0,0 +1,65 @@ +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 .. import types +from ..program_id import PROGRAM_ID + + +class SubmitBidArgs(typing.TypedDict): + data: types.submit_bid_args.SubmitBidArgs + + +layout = borsh.CStruct("data" / types.submit_bid_args.SubmitBidArgs.layout) + + +class SubmitBidAccounts(typing.TypedDict): + searcher: Pubkey + relayer_signer: Pubkey + permission: Pubkey + router: Pubkey + config_router: Pubkey + express_relay_metadata: Pubkey + fee_receiver_relayer: Pubkey + sysvar_instructions: Pubkey + + +def submit_bid( + args: SubmitBidArgs, + accounts: SubmitBidAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["searcher"], is_signer=True, is_writable=True), + AccountMeta( + pubkey=accounts["relayer_signer"], is_signer=True, is_writable=False + ), + AccountMeta(pubkey=accounts["permission"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["router"], is_signer=False, is_writable=True), + AccountMeta( + pubkey=accounts["config_router"], is_signer=False, is_writable=False + ), + AccountMeta( + pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["fee_receiver_relayer"], is_signer=False, is_writable=True + ), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + AccountMeta( + pubkey=accounts["sysvar_instructions"], is_signer=False, is_writable=False + ), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\x13\xa4\xed\xfe@\x8b\xed]" + encoded_args = layout.build( + { + "data": args["data"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/swap.py b/sdk/python/express_relay/svm/generated/instructions/swap.py new file mode 100644 index 00000000..c64255b7 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/swap.py @@ -0,0 +1,107 @@ +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 SwapArgs(typing.TypedDict): + data: types.swap_args.SwapArgs + + +layout = borsh.CStruct("data" / types.swap_args.SwapArgs.layout) + + +class SwapAccounts(typing.TypedDict): + searcher: Pubkey + user: Pubkey + searcher_ta_mint_searcher: Pubkey + searcher_ta_mint_user: Pubkey + user_ata_mint_searcher: Pubkey + user_ata_mint_user: Pubkey + router_fee_receiver_ta: Pubkey + relayer_fee_receiver_ata: Pubkey + express_relay_fee_receiver_ata: Pubkey + mint_searcher: Pubkey + mint_user: Pubkey + mint_fee: Pubkey + token_program_searcher: Pubkey + token_program_user: Pubkey + token_program_fee: Pubkey + express_relay_metadata: Pubkey + relayer_signer: Pubkey + + +def swap( + args: SwapArgs, + accounts: SwapAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["searcher"], is_signer=True, is_writable=False), + AccountMeta(pubkey=accounts["user"], is_signer=True, is_writable=False), + AccountMeta( + pubkey=accounts["searcher_ta_mint_searcher"], + is_signer=False, + is_writable=True, + ), + AccountMeta( + pubkey=accounts["searcher_ta_mint_user"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["user_ata_mint_searcher"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["user_ata_mint_user"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["router_fee_receiver_ta"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["relayer_fee_receiver_ata"], + is_signer=False, + is_writable=True, + ), + AccountMeta( + pubkey=accounts["express_relay_fee_receiver_ata"], + is_signer=False, + is_writable=True, + ), + AccountMeta( + pubkey=accounts["mint_searcher"], is_signer=False, is_writable=False + ), + AccountMeta(pubkey=accounts["mint_user"], is_signer=False, is_writable=False), + AccountMeta(pubkey=accounts["mint_fee"], is_signer=False, is_writable=False), + AccountMeta( + pubkey=accounts["token_program_searcher"], + is_signer=False, + is_writable=False, + ), + AccountMeta( + pubkey=accounts["token_program_user"], is_signer=False, is_writable=False + ), + AccountMeta( + pubkey=accounts["token_program_fee"], is_signer=False, is_writable=False + ), + AccountMeta( + pubkey=accounts["express_relay_metadata"], + is_signer=False, + is_writable=False, + ), + AccountMeta( + pubkey=accounts["relayer_signer"], is_signer=True, is_writable=False + ), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xf8\xc6\x9e\x91\xe1u\x87\xc8" + encoded_args = layout.build( + { + "data": args["data"].to_encodable(), + } + ) + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py b/sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py new file mode 100644 index 00000000..610cc3e5 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py @@ -0,0 +1,33 @@ +from __future__ import annotations +import typing +from solders.pubkey import Pubkey +from solders.instruction import Instruction, AccountMeta +from ..program_id import PROGRAM_ID + + +class WithdrawFeesAccounts(typing.TypedDict): + admin: Pubkey + fee_receiver_admin: Pubkey + express_relay_metadata: Pubkey + + +def withdraw_fees( + accounts: WithdrawFeesAccounts, + program_id: Pubkey = PROGRAM_ID, + remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, +) -> Instruction: + keys: list[AccountMeta] = [ + AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), + AccountMeta( + pubkey=accounts["fee_receiver_admin"], is_signer=False, is_writable=True + ), + AccountMeta( + pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True + ), + ] + if remaining_accounts is not None: + keys += remaining_accounts + identifier = b"\xc6\xd4\xabm\x90\xd7\xaeY" + encoded_args = b"" + data = identifier + encoded_args + return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/program_id.py b/sdk/python/express_relay/svm/generated/program_id.py new file mode 100644 index 00000000..3deb17d5 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/program_id.py @@ -0,0 +1,3 @@ +from solders.pubkey import Pubkey + +PROGRAM_ID = Pubkey.from_string("PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfountagged") diff --git a/sdk/python/express_relay/svm/generated/types/__init__.py b/sdk/python/express_relay/svm/generated/types/__init__.py new file mode 100644 index 00000000..c0275600 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/__init__.py @@ -0,0 +1,18 @@ +import typing +from . import initialize_args +from .initialize_args import InitializeArgs, InitializeArgsJSON +from . import set_splits_args +from .set_splits_args import SetSplitsArgs, SetSplitsArgsJSON +from . import set_swap_platform_fee_args +from .set_swap_platform_fee_args import ( + SetSwapPlatformFeeArgs, + SetSwapPlatformFeeArgsJSON, +) +from . import set_router_split_args +from .set_router_split_args import SetRouterSplitArgs, SetRouterSplitArgsJSON +from . import submit_bid_args +from .submit_bid_args import SubmitBidArgs, SubmitBidArgsJSON +from . import swap_args +from .swap_args import SwapArgs, SwapArgsJSON +from . import fee_token +from .fee_token import FeeTokenKind, FeeTokenJSON diff --git a/sdk/python/express_relay/svm/generated/types/fee_token.py b/sdk/python/express_relay/svm/generated/types/fee_token.py new file mode 100644 index 00000000..b4b3091c --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/fee_token.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 SearcherJSON(typing.TypedDict): + kind: typing.Literal["Searcher"] + + +class UserJSON(typing.TypedDict): + kind: typing.Literal["User"] + + +@dataclass +class Searcher: + discriminator: typing.ClassVar = 0 + kind: typing.ClassVar = "Searcher" + + @classmethod + def to_json(cls) -> SearcherJSON: + return SearcherJSON( + kind="Searcher", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "Searcher": {}, + } + + +@dataclass +class User: + discriminator: typing.ClassVar = 1 + kind: typing.ClassVar = "User" + + @classmethod + def to_json(cls) -> UserJSON: + return UserJSON( + kind="User", + ) + + @classmethod + def to_encodable(cls) -> dict: + return { + "User": {}, + } + + +FeeTokenKind = typing.Union[Searcher, User] +FeeTokenJSON = typing.Union[SearcherJSON, UserJSON] + + +def from_decoded(obj: dict) -> FeeTokenKind: + if not isinstance(obj, dict): + raise ValueError("Invalid enum object") + if "Searcher" in obj: + return Searcher() + if "User" in obj: + return User() + raise ValueError("Invalid enum object") + + +def from_json(obj: FeeTokenJSON) -> FeeTokenKind: + if obj["kind"] == "Searcher": + return Searcher() + if obj["kind"] == "User": + return User() + kind = obj["kind"] + raise ValueError(f"Unrecognized enum kind: {kind}") + + +layout = EnumForCodegen("Searcher" / borsh.CStruct(), "User" / borsh.CStruct()) diff --git a/sdk/python/express_relay/svm/generated/types/initialize_args.py b/sdk/python/express_relay/svm/generated/types/initialize_args.py new file mode 100644 index 00000000..3164d8d0 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/initialize_args.py @@ -0,0 +1,45 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from construct import Container +import borsh_construct as borsh + + +class InitializeArgsJSON(typing.TypedDict): + split_router_default: int + split_relayer: int + + +@dataclass +class InitializeArgs: + layout: typing.ClassVar = borsh.CStruct( + "split_router_default" / borsh.U64, "split_relayer" / borsh.U64 + ) + split_router_default: int + split_relayer: int + + @classmethod + def from_decoded(cls, obj: Container) -> "InitializeArgs": + return cls( + split_router_default=obj.split_router_default, + split_relayer=obj.split_relayer, + ) + + def to_encodable(self) -> dict[str, typing.Any]: + return { + "split_router_default": self.split_router_default, + "split_relayer": self.split_relayer, + } + + def to_json(self) -> InitializeArgsJSON: + return { + "split_router_default": self.split_router_default, + "split_relayer": self.split_relayer, + } + + @classmethod + def from_json(cls, obj: InitializeArgsJSON) -> "InitializeArgs": + return cls( + split_router_default=obj["split_router_default"], + split_relayer=obj["split_relayer"], + ) diff --git a/sdk/python/express_relay/svm/generated/types/set_router_split_args.py b/sdk/python/express_relay/svm/generated/types/set_router_split_args.py new file mode 100644 index 00000000..0bb6b133 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/set_router_split_args.py @@ -0,0 +1,29 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from construct import Container +import borsh_construct as borsh + + +class SetRouterSplitArgsJSON(typing.TypedDict): + split_router: int + + +@dataclass +class SetRouterSplitArgs: + layout: typing.ClassVar = borsh.CStruct("split_router" / borsh.U64) + split_router: int + + @classmethod + def from_decoded(cls, obj: Container) -> "SetRouterSplitArgs": + return cls(split_router=obj.split_router) + + def to_encodable(self) -> dict[str, typing.Any]: + return {"split_router": self.split_router} + + def to_json(self) -> SetRouterSplitArgsJSON: + return {"split_router": self.split_router} + + @classmethod + def from_json(cls, obj: SetRouterSplitArgsJSON) -> "SetRouterSplitArgs": + return cls(split_router=obj["split_router"]) diff --git a/sdk/python/express_relay/svm/generated/types/set_splits_args.py b/sdk/python/express_relay/svm/generated/types/set_splits_args.py new file mode 100644 index 00000000..eedcb571 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/set_splits_args.py @@ -0,0 +1,45 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from construct import Container +import borsh_construct as borsh + + +class SetSplitsArgsJSON(typing.TypedDict): + split_router_default: int + split_relayer: int + + +@dataclass +class SetSplitsArgs: + layout: typing.ClassVar = borsh.CStruct( + "split_router_default" / borsh.U64, "split_relayer" / borsh.U64 + ) + split_router_default: int + split_relayer: int + + @classmethod + def from_decoded(cls, obj: Container) -> "SetSplitsArgs": + return cls( + split_router_default=obj.split_router_default, + split_relayer=obj.split_relayer, + ) + + def to_encodable(self) -> dict[str, typing.Any]: + return { + "split_router_default": self.split_router_default, + "split_relayer": self.split_relayer, + } + + def to_json(self) -> SetSplitsArgsJSON: + return { + "split_router_default": self.split_router_default, + "split_relayer": self.split_relayer, + } + + @classmethod + def from_json(cls, obj: SetSplitsArgsJSON) -> "SetSplitsArgs": + return cls( + split_router_default=obj["split_router_default"], + split_relayer=obj["split_relayer"], + ) diff --git a/sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py b/sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py new file mode 100644 index 00000000..b7471414 --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py @@ -0,0 +1,29 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass +from construct import Container +import borsh_construct as borsh + + +class SetSwapPlatformFeeArgsJSON(typing.TypedDict): + swap_platform_fee_bps: int + + +@dataclass +class SetSwapPlatformFeeArgs: + layout: typing.ClassVar = borsh.CStruct("swap_platform_fee_bps" / borsh.U64) + swap_platform_fee_bps: int + + @classmethod + def from_decoded(cls, obj: Container) -> "SetSwapPlatformFeeArgs": + return cls(swap_platform_fee_bps=obj.swap_platform_fee_bps) + + def to_encodable(self) -> dict[str, typing.Any]: + return {"swap_platform_fee_bps": self.swap_platform_fee_bps} + + def to_json(self) -> SetSwapPlatformFeeArgsJSON: + return {"swap_platform_fee_bps": self.swap_platform_fee_bps} + + @classmethod + def from_json(cls, obj: SetSwapPlatformFeeArgsJSON) -> "SetSwapPlatformFeeArgs": + return cls(swap_platform_fee_bps=obj["swap_platform_fee_bps"]) diff --git a/sdk/python/express_relay/svm/generated/types/submit_bid_args.py b/sdk/python/express_relay/svm/generated/types/submit_bid_args.py new file mode 100644 index 00000000..4061cd6c --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/submit_bid_args.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 SubmitBidArgsJSON(typing.TypedDict): + deadline: int + bid_amount: int + + +@dataclass +class SubmitBidArgs: + layout: typing.ClassVar = borsh.CStruct( + "deadline" / borsh.I64, "bid_amount" / borsh.U64 + ) + deadline: int + bid_amount: int + + @classmethod + def from_decoded(cls, obj: Container) -> "SubmitBidArgs": + return cls(deadline=obj.deadline, bid_amount=obj.bid_amount) + + def to_encodable(self) -> dict[str, typing.Any]: + return {"deadline": self.deadline, "bid_amount": self.bid_amount} + + def to_json(self) -> SubmitBidArgsJSON: + return {"deadline": self.deadline, "bid_amount": self.bid_amount} + + @classmethod + def from_json(cls, obj: SubmitBidArgsJSON) -> "SubmitBidArgs": + return cls(deadline=obj["deadline"], bid_amount=obj["bid_amount"]) diff --git a/sdk/python/express_relay/svm/generated/types/swap_args.py b/sdk/python/express_relay/svm/generated/types/swap_args.py new file mode 100644 index 00000000..783c770f --- /dev/null +++ b/sdk/python/express_relay/svm/generated/types/swap_args.py @@ -0,0 +1,70 @@ +from __future__ import annotations +from . import ( + fee_token, +) +import typing +from dataclasses import dataclass +from construct import Container +import borsh_construct as borsh + + +class SwapArgsJSON(typing.TypedDict): + deadline: int + amount_searcher: int + amount_user: int + referral_fee_bps: int + fee_token: fee_token.FeeTokenJSON + + +@dataclass +class SwapArgs: + layout: typing.ClassVar = borsh.CStruct( + "deadline" / borsh.I64, + "amount_searcher" / borsh.U64, + "amount_user" / borsh.U64, + "referral_fee_bps" / borsh.U16, + "fee_token" / fee_token.layout, + ) + deadline: int + amount_searcher: int + amount_user: int + referral_fee_bps: int + fee_token: fee_token.FeeTokenKind + + @classmethod + def from_decoded(cls, obj: Container) -> "SwapArgs": + return cls( + deadline=obj.deadline, + amount_searcher=obj.amount_searcher, + amount_user=obj.amount_user, + referral_fee_bps=obj.referral_fee_bps, + fee_token=fee_token.from_decoded(obj.fee_token), + ) + + def to_encodable(self) -> dict[str, typing.Any]: + return { + "deadline": self.deadline, + "amount_searcher": self.amount_searcher, + "amount_user": self.amount_user, + "referral_fee_bps": self.referral_fee_bps, + "fee_token": self.fee_token.to_encodable(), + } + + def to_json(self) -> SwapArgsJSON: + return { + "deadline": self.deadline, + "amount_searcher": self.amount_searcher, + "amount_user": self.amount_user, + "referral_fee_bps": self.referral_fee_bps, + "fee_token": self.fee_token.to_json(), + } + + @classmethod + def from_json(cls, obj: SwapArgsJSON) -> "SwapArgs": + return cls( + deadline=obj["deadline"], + amount_searcher=obj["amount_searcher"], + amount_user=obj["amount_user"], + referral_fee_bps=obj["referral_fee_bps"], + fee_token=fee_token.from_json(obj["fee_token"]), + ) diff --git a/tilt-scripts/svm/initialize_programs.py b/tilt-scripts/svm/initialize_programs.py index 6afa51a4..adbd3716 100644 --- a/tilt-scripts/svm/initialize_programs.py +++ b/tilt-scripts/svm/initialize_programs.py @@ -47,6 +47,12 @@ def parse_args() -> argparse.Namespace: required=True, help="JSON file containing the private key (as a byte array) of the relayer signer for express relay", ) + parser.add_argument( + "--file-private-key-fee-receiver-relayer", + type=str, + required=True, + help="JSON file containing the private key (as a byte array) of the fee receiver for the relayer", + ) parser.add_argument( "--express-relay-program", type=str, @@ -103,6 +109,12 @@ async def main(): pk_relayer_signer = kp_relayer_signer.pubkey() logger.info("Relayer signer pubkey: %s", pk_relayer_signer) + kp_fee_receiver_relayer = read_kp_from_json( + args.file_private_key_fee_receiver_relayer + ) + pk_fee_receiver_relayer = kp_fee_receiver_relayer.pubkey() + logger.info("Fee Receiver Relayer: %s", pk_fee_receiver_relayer) + client = AsyncClient(args.rpc_url, Confirmed) pk_express_relay_metadata = Pubkey.find_program_address( @@ -125,7 +137,7 @@ async def main(): express_relay_metadata=pk_express_relay_metadata, admin=pk_admin, relayer_signer=pk_relayer_signer, - fee_receiver_relayer=pk_relayer_signer, + fee_receiver_relayer=pk_fee_receiver_relayer, ), program_id=express_relay_pid, ) diff --git a/tilt-scripts/svm/setup_accounts.py b/tilt-scripts/svm/setup_accounts.py index 9fd62c45..8d2d5221 100644 --- a/tilt-scripts/svm/setup_accounts.py +++ b/tilt-scripts/svm/setup_accounts.py @@ -50,6 +50,7 @@ async def main(): "searcher_rust", "admin", "relayer_signer", + "fee_receiver_relayer", ]: file_path = keypairs_dir / f"{account}.json" if not file_path.exists(): From e34206607114531ca81dde84d76f2517f0ef8c91 Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Tue, 4 Feb 2025 14:40:15 +0100 Subject: [PATCH 3/6] Add test for relayer signer --- contracts/svm/testing/tests/swap.rs | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/contracts/svm/testing/tests/swap.rs b/contracts/svm/testing/tests/swap.rs index bb3a903e..8bef4f7b 100644 --- a/contracts/svm/testing/tests/swap.rs +++ b/contracts/svm/testing/tests/swap.rs @@ -1118,3 +1118,64 @@ fn test_swap_wrong_mint_fee() { InstructionError::Custom(AnchorErrorCode::ConstraintRaw.into()), ); } + + +#[test] +fn test_swap_fail_wrong_relayer_signer() { + let SwapSetupResult { + mut svm, + user, + searcher, + token_searcher, + token_user, + router_ta_mint_user, + .. + } = setup_swap(SwapSetupParams { + platform_fee_bps: 1000, + token_program_searcher: spl_token::ID, + token_decimals_searcher: 6, + token_program_user: spl_token::ID, + token_decimals_user: 6, + }); + + let express_relay_metadata = get_express_relay_metadata(&mut svm); + + // user token fee + let swap_args = SwapArgs { + deadline: svm.get_sysvar::().unix_timestamp, + amount_searcher: token_searcher.get_amount_with_decimals(1.), + amount_user: token_user.get_amount_with_decimals(1.), + referral_fee_bps: 1500, + fee_token: FeeToken::User, + }; + + let wrong_relayer_signer = Keypair::new(); + let instructions = build_swap_instructions( + searcher.pubkey(), + user.pubkey(), + None, + None, + router_ta_mint_user, + express_relay_metadata.fee_receiver_relayer, + token_searcher.mint, + token_user.mint, + Some(token_searcher.token_program), + Some(token_user.token_program), + swap_args, + None, + None, + wrong_relayer_signer.pubkey(), // <--- wrong relayer signer + ); + let result = submit_transaction( + &mut svm, + &instructions, + &searcher, + &[&searcher, &user, &wrong_relayer_signer], + ) + .unwrap_err(); + assert_custom_error( + result.err, + 4, + InstructionError::Custom(AnchorErrorCode::ConstraintHasOne.into()), + ); +} From 80737551b94e31c8d0c1ea0a6565e822f915d9f3 Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Tue, 4 Feb 2025 15:13:16 +0100 Subject: [PATCH 4/6] Remove extra generated files --- .../svm/generated/accounts/__init__.py | 2 - .../svm/generated/accounts/config_router.py | 85 --- .../accounts/express_relay_metadata.py | 112 ---- .../svm/generated/errors/__init__.py | 29 - .../svm/generated/errors/anchor.py | 590 ------------------ .../svm/generated/errors/custom.py | 114 ---- .../svm/generated/instructions/__init__.py | 18 - .../instructions/check_permission.py | 41 -- .../svm/generated/instructions/initialize.py | 55 -- .../svm/generated/instructions/set_admin.py | 31 - .../svm/generated/instructions/set_relayer.py | 37 -- .../instructions/set_router_split.py | 53 -- .../svm/generated/instructions/set_splits.py | 43 -- .../instructions/set_swap_platform_fee.py | 45 -- .../svm/generated/instructions/submit_bid.py | 65 -- .../svm/generated/instructions/swap.py | 107 ---- .../generated/instructions/withdraw_fees.py | 33 - .../svm/generated/types/__init__.py | 18 - .../svm/generated/types/fee_token.py | 75 --- .../svm/generated/types/initialize_args.py | 45 -- .../generated/types/set_router_split_args.py | 29 - .../svm/generated/types/set_splits_args.py | 45 -- .../types/set_swap_platform_fee_args.py | 29 - .../svm/generated/types/submit_bid_args.py | 33 - .../svm/generated/types/swap_args.py | 70 --- 25 files changed, 1804 deletions(-) delete mode 100644 sdk/python/express_relay/svm/generated/accounts/__init__.py delete mode 100644 sdk/python/express_relay/svm/generated/accounts/config_router.py delete mode 100644 sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py delete mode 100644 sdk/python/express_relay/svm/generated/errors/__init__.py delete mode 100644 sdk/python/express_relay/svm/generated/errors/anchor.py delete mode 100644 sdk/python/express_relay/svm/generated/errors/custom.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/__init__.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/check_permission.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/initialize.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/set_admin.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/set_relayer.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/set_router_split.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/set_splits.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/submit_bid.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/swap.py delete mode 100644 sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py delete mode 100644 sdk/python/express_relay/svm/generated/types/__init__.py delete mode 100644 sdk/python/express_relay/svm/generated/types/fee_token.py delete mode 100644 sdk/python/express_relay/svm/generated/types/initialize_args.py delete mode 100644 sdk/python/express_relay/svm/generated/types/set_router_split_args.py delete mode 100644 sdk/python/express_relay/svm/generated/types/set_splits_args.py delete mode 100644 sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py delete mode 100644 sdk/python/express_relay/svm/generated/types/submit_bid_args.py delete mode 100644 sdk/python/express_relay/svm/generated/types/swap_args.py diff --git a/sdk/python/express_relay/svm/generated/accounts/__init__.py b/sdk/python/express_relay/svm/generated/accounts/__init__.py deleted file mode 100644 index 8136b66e..00000000 --- a/sdk/python/express_relay/svm/generated/accounts/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .express_relay_metadata import ExpressRelayMetadata, ExpressRelayMetadataJSON -from .config_router import ConfigRouter, ConfigRouterJSON diff --git a/sdk/python/express_relay/svm/generated/accounts/config_router.py b/sdk/python/express_relay/svm/generated/accounts/config_router.py deleted file mode 100644 index c02ff788..00000000 --- a/sdk/python/express_relay/svm/generated/accounts/config_router.py +++ /dev/null @@ -1,85 +0,0 @@ -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 ConfigRouterJSON(typing.TypedDict): - router: str - split: int - - -@dataclass -class ConfigRouter: - discriminator: typing.ClassVar = b"\x87B\xf0\xa6^\xc6\xbb$" - layout: typing.ClassVar = borsh.CStruct("router" / BorshPubkey, "split" / borsh.U64) - router: Pubkey - split: int - - @classmethod - async def fetch( - cls, - conn: AsyncClient, - address: Pubkey, - commitment: typing.Optional[Commitment] = None, - program_id: Pubkey = PROGRAM_ID, - ) -> typing.Optional["ConfigRouter"]: - 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["ConfigRouter"]]: - infos = await get_multiple_accounts(conn, addresses, commitment=commitment) - res: typing.List[typing.Optional["ConfigRouter"]] = [] - 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) -> "ConfigRouter": - if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: - raise AccountInvalidDiscriminator( - "The discriminator for this account is invalid" - ) - dec = ConfigRouter.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) - return cls( - router=dec.router, - split=dec.split, - ) - - def to_json(self) -> ConfigRouterJSON: - return { - "router": str(self.router), - "split": self.split, - } - - @classmethod - def from_json(cls, obj: ConfigRouterJSON) -> "ConfigRouter": - return cls( - router=Pubkey.from_string(obj["router"]), - split=obj["split"], - ) diff --git a/sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py b/sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py deleted file mode 100644 index 8b5fac49..00000000 --- a/sdk/python/express_relay/svm/generated/accounts/express_relay_metadata.py +++ /dev/null @@ -1,112 +0,0 @@ -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 ExpressRelayMetadataJSON(typing.TypedDict): - admin: str - relayer_signer: str - fee_receiver_relayer: str - split_router_default: int - split_relayer: int - swap_platform_fee_bps: int - - -@dataclass -class ExpressRelayMetadata: - discriminator: typing.ClassVar = b"\xccK\x85\x07\xaf\xf1\x82\x0b" - layout: typing.ClassVar = borsh.CStruct( - "admin" / BorshPubkey, - "relayer_signer" / BorshPubkey, - "fee_receiver_relayer" / BorshPubkey, - "split_router_default" / borsh.U64, - "split_relayer" / borsh.U64, - "swap_platform_fee_bps" / borsh.U64, - ) - admin: Pubkey - relayer_signer: Pubkey - fee_receiver_relayer: Pubkey - split_router_default: int - split_relayer: int - swap_platform_fee_bps: int - - @classmethod - async def fetch( - cls, - conn: AsyncClient, - address: Pubkey, - commitment: typing.Optional[Commitment] = None, - program_id: Pubkey = PROGRAM_ID, - ) -> typing.Optional["ExpressRelayMetadata"]: - 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["ExpressRelayMetadata"]]: - infos = await get_multiple_accounts(conn, addresses, commitment=commitment) - res: typing.List[typing.Optional["ExpressRelayMetadata"]] = [] - 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) -> "ExpressRelayMetadata": - if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator: - raise AccountInvalidDiscriminator( - "The discriminator for this account is invalid" - ) - dec = ExpressRelayMetadata.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:]) - return cls( - admin=dec.admin, - relayer_signer=dec.relayer_signer, - fee_receiver_relayer=dec.fee_receiver_relayer, - split_router_default=dec.split_router_default, - split_relayer=dec.split_relayer, - swap_platform_fee_bps=dec.swap_platform_fee_bps, - ) - - def to_json(self) -> ExpressRelayMetadataJSON: - return { - "admin": str(self.admin), - "relayer_signer": str(self.relayer_signer), - "fee_receiver_relayer": str(self.fee_receiver_relayer), - "split_router_default": self.split_router_default, - "split_relayer": self.split_relayer, - "swap_platform_fee_bps": self.swap_platform_fee_bps, - } - - @classmethod - def from_json(cls, obj: ExpressRelayMetadataJSON) -> "ExpressRelayMetadata": - return cls( - admin=Pubkey.from_string(obj["admin"]), - relayer_signer=Pubkey.from_string(obj["relayer_signer"]), - fee_receiver_relayer=Pubkey.from_string(obj["fee_receiver_relayer"]), - split_router_default=obj["split_router_default"], - split_relayer=obj["split_relayer"], - swap_platform_fee_bps=obj["swap_platform_fee_bps"], - ) diff --git a/sdk/python/express_relay/svm/generated/errors/__init__.py b/sdk/python/express_relay/svm/generated/errors/__init__.py deleted file mode 100644 index 421993d0..00000000 --- a/sdk/python/express_relay/svm/generated/errors/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -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/sdk/python/express_relay/svm/generated/errors/anchor.py b/sdk/python/express_relay/svm/generated/errors/anchor.py deleted file mode 100644 index 3f266ef0..00000000 --- a/sdk/python/express_relay/svm/generated/errors/anchor.py +++ /dev/null @@ -1,590 +0,0 @@ -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/sdk/python/express_relay/svm/generated/errors/custom.py b/sdk/python/express_relay/svm/generated/errors/custom.py deleted file mode 100644 index f5cdf2cf..00000000 --- a/sdk/python/express_relay/svm/generated/errors/custom.py +++ /dev/null @@ -1,114 +0,0 @@ -import typing -from anchorpy.error import ProgramError - - -class FeeSplitLargerThanPrecision(ProgramError): - def __init__(self) -> None: - super().__init__(6000, "Fee split(s) larger than fee precision") - - code = 6000 - name = "FeeSplitLargerThanPrecision" - msg = "Fee split(s) larger than fee precision" - - -class FeesHigherThanBid(ProgramError): - def __init__(self) -> None: - super().__init__(6001, "Fees higher than bid") - - code = 6001 - name = "FeesHigherThanBid" - msg = "Fees higher than bid" - - -class DeadlinePassed(ProgramError): - def __init__(self) -> None: - super().__init__(6002, "Deadline passed") - - code = 6002 - name = "DeadlinePassed" - msg = "Deadline passed" - - -class InvalidCPISubmitBid(ProgramError): - def __init__(self) -> None: - super().__init__(6003, "Invalid CPI into submit bid instruction") - - code = 6003 - name = "InvalidCPISubmitBid" - msg = "Invalid CPI into submit bid instruction" - - -class MissingPermission(ProgramError): - def __init__(self) -> None: - super().__init__(6004, "Missing permission") - - code = 6004 - name = "MissingPermission" - msg = "Missing permission" - - -class MultiplePermissions(ProgramError): - def __init__(self) -> None: - super().__init__(6005, "Multiple permissions") - - code = 6005 - name = "MultiplePermissions" - msg = "Multiple permissions" - - -class InsufficientSearcherFunds(ProgramError): - def __init__(self) -> None: - super().__init__(6006, "Insufficient searcher funds") - - code = 6006 - name = "InsufficientSearcherFunds" - msg = "Insufficient searcher funds" - - -class InsufficientRent(ProgramError): - def __init__(self) -> None: - super().__init__(6007, "Insufficient funds for rent") - - code = 6007 - name = "InsufficientRent" - msg = "Insufficient funds for rent" - - -class InvalidReferralFee(ProgramError): - def __init__(self) -> None: - super().__init__(6008, "Invalid referral fee") - - code = 6008 - name = "InvalidReferralFee" - msg = "Invalid referral fee" - - -CustomError = typing.Union[ - FeeSplitLargerThanPrecision, - FeesHigherThanBid, - DeadlinePassed, - InvalidCPISubmitBid, - MissingPermission, - MultiplePermissions, - InsufficientSearcherFunds, - InsufficientRent, - InvalidReferralFee, -] -CUSTOM_ERROR_MAP: dict[int, CustomError] = { - 6000: FeeSplitLargerThanPrecision(), - 6001: FeesHigherThanBid(), - 6002: DeadlinePassed(), - 6003: InvalidCPISubmitBid(), - 6004: MissingPermission(), - 6005: MultiplePermissions(), - 6006: InsufficientSearcherFunds(), - 6007: InsufficientRent(), - 6008: InvalidReferralFee(), -} - - -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/sdk/python/express_relay/svm/generated/instructions/__init__.py b/sdk/python/express_relay/svm/generated/instructions/__init__.py deleted file mode 100644 index c8e99467..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -from .initialize import initialize, InitializeArgs, InitializeAccounts -from .set_admin import set_admin, SetAdminAccounts -from .set_relayer import set_relayer, SetRelayerAccounts -from .set_splits import set_splits, SetSplitsArgs, SetSplitsAccounts -from .set_swap_platform_fee import ( - set_swap_platform_fee, - SetSwapPlatformFeeArgs, - SetSwapPlatformFeeAccounts, -) -from .set_router_split import ( - set_router_split, - SetRouterSplitArgs, - SetRouterSplitAccounts, -) -from .submit_bid import submit_bid, SubmitBidArgs, SubmitBidAccounts -from .check_permission import check_permission, CheckPermissionAccounts -from .withdraw_fees import withdraw_fees, WithdrawFeesAccounts -from .swap import swap, SwapArgs, SwapAccounts diff --git a/sdk/python/express_relay/svm/generated/instructions/check_permission.py b/sdk/python/express_relay/svm/generated/instructions/check_permission.py deleted file mode 100644 index cefd03c1..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/check_permission.py +++ /dev/null @@ -1,41 +0,0 @@ -from __future__ import annotations -import typing -from solders.pubkey import Pubkey -from solders.instruction import Instruction, AccountMeta -from ..program_id import PROGRAM_ID - - -class CheckPermissionAccounts(typing.TypedDict): - sysvar_instructions: Pubkey - permission: Pubkey - router: Pubkey - config_router: Pubkey - express_relay_metadata: Pubkey - - -def check_permission( - accounts: CheckPermissionAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta( - pubkey=accounts["sysvar_instructions"], is_signer=False, is_writable=False - ), - AccountMeta(pubkey=accounts["permission"], is_signer=False, is_writable=False), - AccountMeta(pubkey=accounts["router"], is_signer=False, is_writable=False), - AccountMeta( - pubkey=accounts["config_router"], is_signer=False, is_writable=False - ), - AccountMeta( - pubkey=accounts["express_relay_metadata"], - is_signer=False, - is_writable=False, - ), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\x9a\xc7\xe8\xf2`H\xc5\xec" - encoded_args = b"" - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/initialize.py b/sdk/python/express_relay/svm/generated/instructions/initialize.py deleted file mode 100644 index ff01ffd7..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/initialize.py +++ /dev/null @@ -1,55 +0,0 @@ -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 .. import types -from ..program_id import PROGRAM_ID - - -class InitializeArgs(typing.TypedDict): - data: types.initialize_args.InitializeArgs - - -layout = borsh.CStruct("data" / types.initialize_args.InitializeArgs.layout) - - -class InitializeAccounts(typing.TypedDict): - payer: Pubkey - express_relay_metadata: Pubkey - admin: Pubkey - relayer_signer: Pubkey - fee_receiver_relayer: Pubkey - - -def initialize( - args: InitializeArgs, - accounts: InitializeAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True), - AccountMeta( - pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True - ), - AccountMeta(pubkey=accounts["admin"], is_signer=False, is_writable=False), - AccountMeta( - pubkey=accounts["relayer_signer"], is_signer=False, is_writable=False - ), - AccountMeta( - pubkey=accounts["fee_receiver_relayer"], 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"\xaf\xafm\x1f\r\x98\x9b\xed" - encoded_args = layout.build( - { - "data": args["data"].to_encodable(), - } - ) - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_admin.py b/sdk/python/express_relay/svm/generated/instructions/set_admin.py deleted file mode 100644 index b010c9a9..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/set_admin.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations -import typing -from solders.pubkey import Pubkey -from solders.instruction import Instruction, AccountMeta -from ..program_id import PROGRAM_ID - - -class SetAdminAccounts(typing.TypedDict): - admin: Pubkey - express_relay_metadata: Pubkey - admin_new: Pubkey - - -def set_admin( - accounts: SetAdminAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), - AccountMeta( - pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True - ), - AccountMeta(pubkey=accounts["admin_new"], is_signer=False, is_writable=False), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\xfb\xa3\x004[\xc2\xbb\\" - encoded_args = b"" - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_relayer.py b/sdk/python/express_relay/svm/generated/instructions/set_relayer.py deleted file mode 100644 index 03f178a8..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/set_relayer.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import annotations -import typing -from solders.pubkey import Pubkey -from solders.instruction import Instruction, AccountMeta -from ..program_id import PROGRAM_ID - - -class SetRelayerAccounts(typing.TypedDict): - admin: Pubkey - express_relay_metadata: Pubkey - relayer_signer: Pubkey - fee_receiver_relayer: Pubkey - - -def set_relayer( - accounts: SetRelayerAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), - AccountMeta( - pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["relayer_signer"], is_signer=False, is_writable=False - ), - AccountMeta( - pubkey=accounts["fee_receiver_relayer"], is_signer=False, is_writable=False - ), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\x17\xf3!XnT\xc4%" - encoded_args = b"" - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_router_split.py b/sdk/python/express_relay/svm/generated/instructions/set_router_split.py deleted file mode 100644 index c7524d96..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/set_router_split.py +++ /dev/null @@ -1,53 +0,0 @@ -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 .. import types -from ..program_id import PROGRAM_ID - - -class SetRouterSplitArgs(typing.TypedDict): - data: types.set_router_split_args.SetRouterSplitArgs - - -layout = borsh.CStruct("data" / types.set_router_split_args.SetRouterSplitArgs.layout) - - -class SetRouterSplitAccounts(typing.TypedDict): - admin: Pubkey - config_router: Pubkey - express_relay_metadata: Pubkey - router: Pubkey - - -def set_router_split( - args: SetRouterSplitArgs, - accounts: SetRouterSplitAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=True), - AccountMeta( - pubkey=accounts["config_router"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["express_relay_metadata"], - is_signer=False, - is_writable=False, - ), - AccountMeta(pubkey=accounts["router"], 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"\x10\x96j\r\x1b\xbfh\x08" - encoded_args = layout.build( - { - "data": args["data"].to_encodable(), - } - ) - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_splits.py b/sdk/python/express_relay/svm/generated/instructions/set_splits.py deleted file mode 100644 index 3ca8ba80..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/set_splits.py +++ /dev/null @@ -1,43 +0,0 @@ -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 SetSplitsArgs(typing.TypedDict): - data: types.set_splits_args.SetSplitsArgs - - -layout = borsh.CStruct("data" / types.set_splits_args.SetSplitsArgs.layout) - - -class SetSplitsAccounts(typing.TypedDict): - admin: Pubkey - express_relay_metadata: Pubkey - - -def set_splits( - args: SetSplitsArgs, - accounts: SetSplitsAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), - AccountMeta( - pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True - ), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\xaf\x02V1\xe1\xca\xe8\xbd" - encoded_args = layout.build( - { - "data": args["data"].to_encodable(), - } - ) - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py b/sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py deleted file mode 100644 index 2b599463..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/set_swap_platform_fee.py +++ /dev/null @@ -1,45 +0,0 @@ -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 SetSwapPlatformFeeArgs(typing.TypedDict): - data: types.set_swap_platform_fee_args.SetSwapPlatformFeeArgs - - -layout = borsh.CStruct( - "data" / types.set_swap_platform_fee_args.SetSwapPlatformFeeArgs.layout -) - - -class SetSwapPlatformFeeAccounts(typing.TypedDict): - admin: Pubkey - express_relay_metadata: Pubkey - - -def set_swap_platform_fee( - args: SetSwapPlatformFeeArgs, - accounts: SetSwapPlatformFeeAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), - AccountMeta( - pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True - ), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\x02\x87K\x0f\x08i\x8e/" - encoded_args = layout.build( - { - "data": args["data"].to_encodable(), - } - ) - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/submit_bid.py b/sdk/python/express_relay/svm/generated/instructions/submit_bid.py deleted file mode 100644 index 1c471429..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/submit_bid.py +++ /dev/null @@ -1,65 +0,0 @@ -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 .. import types -from ..program_id import PROGRAM_ID - - -class SubmitBidArgs(typing.TypedDict): - data: types.submit_bid_args.SubmitBidArgs - - -layout = borsh.CStruct("data" / types.submit_bid_args.SubmitBidArgs.layout) - - -class SubmitBidAccounts(typing.TypedDict): - searcher: Pubkey - relayer_signer: Pubkey - permission: Pubkey - router: Pubkey - config_router: Pubkey - express_relay_metadata: Pubkey - fee_receiver_relayer: Pubkey - sysvar_instructions: Pubkey - - -def submit_bid( - args: SubmitBidArgs, - accounts: SubmitBidAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["searcher"], is_signer=True, is_writable=True), - AccountMeta( - pubkey=accounts["relayer_signer"], is_signer=True, is_writable=False - ), - AccountMeta(pubkey=accounts["permission"], is_signer=False, is_writable=False), - AccountMeta(pubkey=accounts["router"], is_signer=False, is_writable=True), - AccountMeta( - pubkey=accounts["config_router"], is_signer=False, is_writable=False - ), - AccountMeta( - pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["fee_receiver_relayer"], is_signer=False, is_writable=True - ), - AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), - AccountMeta( - pubkey=accounts["sysvar_instructions"], is_signer=False, is_writable=False - ), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\x13\xa4\xed\xfe@\x8b\xed]" - encoded_args = layout.build( - { - "data": args["data"].to_encodable(), - } - ) - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/swap.py b/sdk/python/express_relay/svm/generated/instructions/swap.py deleted file mode 100644 index c64255b7..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/swap.py +++ /dev/null @@ -1,107 +0,0 @@ -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 SwapArgs(typing.TypedDict): - data: types.swap_args.SwapArgs - - -layout = borsh.CStruct("data" / types.swap_args.SwapArgs.layout) - - -class SwapAccounts(typing.TypedDict): - searcher: Pubkey - user: Pubkey - searcher_ta_mint_searcher: Pubkey - searcher_ta_mint_user: Pubkey - user_ata_mint_searcher: Pubkey - user_ata_mint_user: Pubkey - router_fee_receiver_ta: Pubkey - relayer_fee_receiver_ata: Pubkey - express_relay_fee_receiver_ata: Pubkey - mint_searcher: Pubkey - mint_user: Pubkey - mint_fee: Pubkey - token_program_searcher: Pubkey - token_program_user: Pubkey - token_program_fee: Pubkey - express_relay_metadata: Pubkey - relayer_signer: Pubkey - - -def swap( - args: SwapArgs, - accounts: SwapAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["searcher"], is_signer=True, is_writable=False), - AccountMeta(pubkey=accounts["user"], is_signer=True, is_writable=False), - AccountMeta( - pubkey=accounts["searcher_ta_mint_searcher"], - is_signer=False, - is_writable=True, - ), - AccountMeta( - pubkey=accounts["searcher_ta_mint_user"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["user_ata_mint_searcher"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["user_ata_mint_user"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["router_fee_receiver_ta"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["relayer_fee_receiver_ata"], - is_signer=False, - is_writable=True, - ), - AccountMeta( - pubkey=accounts["express_relay_fee_receiver_ata"], - is_signer=False, - is_writable=True, - ), - AccountMeta( - pubkey=accounts["mint_searcher"], is_signer=False, is_writable=False - ), - AccountMeta(pubkey=accounts["mint_user"], is_signer=False, is_writable=False), - AccountMeta(pubkey=accounts["mint_fee"], is_signer=False, is_writable=False), - AccountMeta( - pubkey=accounts["token_program_searcher"], - is_signer=False, - is_writable=False, - ), - AccountMeta( - pubkey=accounts["token_program_user"], is_signer=False, is_writable=False - ), - AccountMeta( - pubkey=accounts["token_program_fee"], is_signer=False, is_writable=False - ), - AccountMeta( - pubkey=accounts["express_relay_metadata"], - is_signer=False, - is_writable=False, - ), - AccountMeta( - pubkey=accounts["relayer_signer"], is_signer=True, is_writable=False - ), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\xf8\xc6\x9e\x91\xe1u\x87\xc8" - encoded_args = layout.build( - { - "data": args["data"].to_encodable(), - } - ) - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py b/sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py deleted file mode 100644 index 610cc3e5..00000000 --- a/sdk/python/express_relay/svm/generated/instructions/withdraw_fees.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations -import typing -from solders.pubkey import Pubkey -from solders.instruction import Instruction, AccountMeta -from ..program_id import PROGRAM_ID - - -class WithdrawFeesAccounts(typing.TypedDict): - admin: Pubkey - fee_receiver_admin: Pubkey - express_relay_metadata: Pubkey - - -def withdraw_fees( - accounts: WithdrawFeesAccounts, - program_id: Pubkey = PROGRAM_ID, - remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None, -) -> Instruction: - keys: list[AccountMeta] = [ - AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False), - AccountMeta( - pubkey=accounts["fee_receiver_admin"], is_signer=False, is_writable=True - ), - AccountMeta( - pubkey=accounts["express_relay_metadata"], is_signer=False, is_writable=True - ), - ] - if remaining_accounts is not None: - keys += remaining_accounts - identifier = b"\xc6\xd4\xabm\x90\xd7\xaeY" - encoded_args = b"" - data = identifier + encoded_args - return Instruction(program_id, data, keys) diff --git a/sdk/python/express_relay/svm/generated/types/__init__.py b/sdk/python/express_relay/svm/generated/types/__init__.py deleted file mode 100644 index c0275600..00000000 --- a/sdk/python/express_relay/svm/generated/types/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -import typing -from . import initialize_args -from .initialize_args import InitializeArgs, InitializeArgsJSON -from . import set_splits_args -from .set_splits_args import SetSplitsArgs, SetSplitsArgsJSON -from . import set_swap_platform_fee_args -from .set_swap_platform_fee_args import ( - SetSwapPlatformFeeArgs, - SetSwapPlatformFeeArgsJSON, -) -from . import set_router_split_args -from .set_router_split_args import SetRouterSplitArgs, SetRouterSplitArgsJSON -from . import submit_bid_args -from .submit_bid_args import SubmitBidArgs, SubmitBidArgsJSON -from . import swap_args -from .swap_args import SwapArgs, SwapArgsJSON -from . import fee_token -from .fee_token import FeeTokenKind, FeeTokenJSON diff --git a/sdk/python/express_relay/svm/generated/types/fee_token.py b/sdk/python/express_relay/svm/generated/types/fee_token.py deleted file mode 100644 index b4b3091c..00000000 --- a/sdk/python/express_relay/svm/generated/types/fee_token.py +++ /dev/null @@ -1,75 +0,0 @@ -from __future__ import annotations -import typing -from dataclasses import dataclass -from anchorpy.borsh_extension import EnumForCodegen -import borsh_construct as borsh - - -class SearcherJSON(typing.TypedDict): - kind: typing.Literal["Searcher"] - - -class UserJSON(typing.TypedDict): - kind: typing.Literal["User"] - - -@dataclass -class Searcher: - discriminator: typing.ClassVar = 0 - kind: typing.ClassVar = "Searcher" - - @classmethod - def to_json(cls) -> SearcherJSON: - return SearcherJSON( - kind="Searcher", - ) - - @classmethod - def to_encodable(cls) -> dict: - return { - "Searcher": {}, - } - - -@dataclass -class User: - discriminator: typing.ClassVar = 1 - kind: typing.ClassVar = "User" - - @classmethod - def to_json(cls) -> UserJSON: - return UserJSON( - kind="User", - ) - - @classmethod - def to_encodable(cls) -> dict: - return { - "User": {}, - } - - -FeeTokenKind = typing.Union[Searcher, User] -FeeTokenJSON = typing.Union[SearcherJSON, UserJSON] - - -def from_decoded(obj: dict) -> FeeTokenKind: - if not isinstance(obj, dict): - raise ValueError("Invalid enum object") - if "Searcher" in obj: - return Searcher() - if "User" in obj: - return User() - raise ValueError("Invalid enum object") - - -def from_json(obj: FeeTokenJSON) -> FeeTokenKind: - if obj["kind"] == "Searcher": - return Searcher() - if obj["kind"] == "User": - return User() - kind = obj["kind"] - raise ValueError(f"Unrecognized enum kind: {kind}") - - -layout = EnumForCodegen("Searcher" / borsh.CStruct(), "User" / borsh.CStruct()) diff --git a/sdk/python/express_relay/svm/generated/types/initialize_args.py b/sdk/python/express_relay/svm/generated/types/initialize_args.py deleted file mode 100644 index 3164d8d0..00000000 --- a/sdk/python/express_relay/svm/generated/types/initialize_args.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations -import typing -from dataclasses import dataclass -from construct import Container -import borsh_construct as borsh - - -class InitializeArgsJSON(typing.TypedDict): - split_router_default: int - split_relayer: int - - -@dataclass -class InitializeArgs: - layout: typing.ClassVar = borsh.CStruct( - "split_router_default" / borsh.U64, "split_relayer" / borsh.U64 - ) - split_router_default: int - split_relayer: int - - @classmethod - def from_decoded(cls, obj: Container) -> "InitializeArgs": - return cls( - split_router_default=obj.split_router_default, - split_relayer=obj.split_relayer, - ) - - def to_encodable(self) -> dict[str, typing.Any]: - return { - "split_router_default": self.split_router_default, - "split_relayer": self.split_relayer, - } - - def to_json(self) -> InitializeArgsJSON: - return { - "split_router_default": self.split_router_default, - "split_relayer": self.split_relayer, - } - - @classmethod - def from_json(cls, obj: InitializeArgsJSON) -> "InitializeArgs": - return cls( - split_router_default=obj["split_router_default"], - split_relayer=obj["split_relayer"], - ) diff --git a/sdk/python/express_relay/svm/generated/types/set_router_split_args.py b/sdk/python/express_relay/svm/generated/types/set_router_split_args.py deleted file mode 100644 index 0bb6b133..00000000 --- a/sdk/python/express_relay/svm/generated/types/set_router_split_args.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations -import typing -from dataclasses import dataclass -from construct import Container -import borsh_construct as borsh - - -class SetRouterSplitArgsJSON(typing.TypedDict): - split_router: int - - -@dataclass -class SetRouterSplitArgs: - layout: typing.ClassVar = borsh.CStruct("split_router" / borsh.U64) - split_router: int - - @classmethod - def from_decoded(cls, obj: Container) -> "SetRouterSplitArgs": - return cls(split_router=obj.split_router) - - def to_encodable(self) -> dict[str, typing.Any]: - return {"split_router": self.split_router} - - def to_json(self) -> SetRouterSplitArgsJSON: - return {"split_router": self.split_router} - - @classmethod - def from_json(cls, obj: SetRouterSplitArgsJSON) -> "SetRouterSplitArgs": - return cls(split_router=obj["split_router"]) diff --git a/sdk/python/express_relay/svm/generated/types/set_splits_args.py b/sdk/python/express_relay/svm/generated/types/set_splits_args.py deleted file mode 100644 index eedcb571..00000000 --- a/sdk/python/express_relay/svm/generated/types/set_splits_args.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations -import typing -from dataclasses import dataclass -from construct import Container -import borsh_construct as borsh - - -class SetSplitsArgsJSON(typing.TypedDict): - split_router_default: int - split_relayer: int - - -@dataclass -class SetSplitsArgs: - layout: typing.ClassVar = borsh.CStruct( - "split_router_default" / borsh.U64, "split_relayer" / borsh.U64 - ) - split_router_default: int - split_relayer: int - - @classmethod - def from_decoded(cls, obj: Container) -> "SetSplitsArgs": - return cls( - split_router_default=obj.split_router_default, - split_relayer=obj.split_relayer, - ) - - def to_encodable(self) -> dict[str, typing.Any]: - return { - "split_router_default": self.split_router_default, - "split_relayer": self.split_relayer, - } - - def to_json(self) -> SetSplitsArgsJSON: - return { - "split_router_default": self.split_router_default, - "split_relayer": self.split_relayer, - } - - @classmethod - def from_json(cls, obj: SetSplitsArgsJSON) -> "SetSplitsArgs": - return cls( - split_router_default=obj["split_router_default"], - split_relayer=obj["split_relayer"], - ) diff --git a/sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py b/sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py deleted file mode 100644 index b7471414..00000000 --- a/sdk/python/express_relay/svm/generated/types/set_swap_platform_fee_args.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations -import typing -from dataclasses import dataclass -from construct import Container -import borsh_construct as borsh - - -class SetSwapPlatformFeeArgsJSON(typing.TypedDict): - swap_platform_fee_bps: int - - -@dataclass -class SetSwapPlatformFeeArgs: - layout: typing.ClassVar = borsh.CStruct("swap_platform_fee_bps" / borsh.U64) - swap_platform_fee_bps: int - - @classmethod - def from_decoded(cls, obj: Container) -> "SetSwapPlatformFeeArgs": - return cls(swap_platform_fee_bps=obj.swap_platform_fee_bps) - - def to_encodable(self) -> dict[str, typing.Any]: - return {"swap_platform_fee_bps": self.swap_platform_fee_bps} - - def to_json(self) -> SetSwapPlatformFeeArgsJSON: - return {"swap_platform_fee_bps": self.swap_platform_fee_bps} - - @classmethod - def from_json(cls, obj: SetSwapPlatformFeeArgsJSON) -> "SetSwapPlatformFeeArgs": - return cls(swap_platform_fee_bps=obj["swap_platform_fee_bps"]) diff --git a/sdk/python/express_relay/svm/generated/types/submit_bid_args.py b/sdk/python/express_relay/svm/generated/types/submit_bid_args.py deleted file mode 100644 index 4061cd6c..00000000 --- a/sdk/python/express_relay/svm/generated/types/submit_bid_args.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations -import typing -from dataclasses import dataclass -from construct import Container -import borsh_construct as borsh - - -class SubmitBidArgsJSON(typing.TypedDict): - deadline: int - bid_amount: int - - -@dataclass -class SubmitBidArgs: - layout: typing.ClassVar = borsh.CStruct( - "deadline" / borsh.I64, "bid_amount" / borsh.U64 - ) - deadline: int - bid_amount: int - - @classmethod - def from_decoded(cls, obj: Container) -> "SubmitBidArgs": - return cls(deadline=obj.deadline, bid_amount=obj.bid_amount) - - def to_encodable(self) -> dict[str, typing.Any]: - return {"deadline": self.deadline, "bid_amount": self.bid_amount} - - def to_json(self) -> SubmitBidArgsJSON: - return {"deadline": self.deadline, "bid_amount": self.bid_amount} - - @classmethod - def from_json(cls, obj: SubmitBidArgsJSON) -> "SubmitBidArgs": - return cls(deadline=obj["deadline"], bid_amount=obj["bid_amount"]) diff --git a/sdk/python/express_relay/svm/generated/types/swap_args.py b/sdk/python/express_relay/svm/generated/types/swap_args.py deleted file mode 100644 index 783c770f..00000000 --- a/sdk/python/express_relay/svm/generated/types/swap_args.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import annotations -from . import ( - fee_token, -) -import typing -from dataclasses import dataclass -from construct import Container -import borsh_construct as borsh - - -class SwapArgsJSON(typing.TypedDict): - deadline: int - amount_searcher: int - amount_user: int - referral_fee_bps: int - fee_token: fee_token.FeeTokenJSON - - -@dataclass -class SwapArgs: - layout: typing.ClassVar = borsh.CStruct( - "deadline" / borsh.I64, - "amount_searcher" / borsh.U64, - "amount_user" / borsh.U64, - "referral_fee_bps" / borsh.U16, - "fee_token" / fee_token.layout, - ) - deadline: int - amount_searcher: int - amount_user: int - referral_fee_bps: int - fee_token: fee_token.FeeTokenKind - - @classmethod - def from_decoded(cls, obj: Container) -> "SwapArgs": - return cls( - deadline=obj.deadline, - amount_searcher=obj.amount_searcher, - amount_user=obj.amount_user, - referral_fee_bps=obj.referral_fee_bps, - fee_token=fee_token.from_decoded(obj.fee_token), - ) - - def to_encodable(self) -> dict[str, typing.Any]: - return { - "deadline": self.deadline, - "amount_searcher": self.amount_searcher, - "amount_user": self.amount_user, - "referral_fee_bps": self.referral_fee_bps, - "fee_token": self.fee_token.to_encodable(), - } - - def to_json(self) -> SwapArgsJSON: - return { - "deadline": self.deadline, - "amount_searcher": self.amount_searcher, - "amount_user": self.amount_user, - "referral_fee_bps": self.referral_fee_bps, - "fee_token": self.fee_token.to_json(), - } - - @classmethod - def from_json(cls, obj: SwapArgsJSON) -> "SwapArgs": - return cls( - deadline=obj["deadline"], - amount_searcher=obj["amount_searcher"], - amount_user=obj["amount_user"], - referral_fee_bps=obj["referral_fee_bps"], - fee_token=fee_token.from_json(obj["fee_token"]), - ) From cfc2c1c4190b4eeebacc51d59e6d17663526df89 Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Tue, 4 Feb 2025 15:14:40 +0100 Subject: [PATCH 5/6] Remove more --- sdk/python/express_relay/svm/generated/program_id.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 sdk/python/express_relay/svm/generated/program_id.py diff --git a/sdk/python/express_relay/svm/generated/program_id.py b/sdk/python/express_relay/svm/generated/program_id.py deleted file mode 100644 index 3deb17d5..00000000 --- a/sdk/python/express_relay/svm/generated/program_id.py +++ /dev/null @@ -1,3 +0,0 @@ -from solders.pubkey import Pubkey - -PROGRAM_ID = Pubkey.from_string("PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfountagged") From 8f5b386693dc7685014f1fd77ac436f5d45740b2 Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Tue, 4 Feb 2025 15:40:40 +0100 Subject: [PATCH 6/6] Address more comments --- contracts/svm/testing/tests/swap.rs | 2 ++ scripts/dex-router/src/index.ts | 10 +-------- sdk/js/README.md | 4 +++- sdk/js/src/examples/simpleSearcherEvm.ts | 18 +++------------ sdk/js/src/examples/simpleSearcherSvm.ts | 18 ++------------- .../searcher/examples/simple_searcher_evm.py | 22 ++----------------- .../searcher/examples/simple_searcher_svm.py | 15 +++---------- 7 files changed, 16 insertions(+), 73 deletions(-) diff --git a/contracts/svm/testing/tests/swap.rs b/contracts/svm/testing/tests/swap.rs index 8bef4f7b..4af3b723 100644 --- a/contracts/svm/testing/tests/swap.rs +++ b/contracts/svm/testing/tests/swap.rs @@ -1179,3 +1179,5 @@ fn test_swap_fail_wrong_relayer_signer() { InstructionError::Custom(AnchorErrorCode::ConstraintHasOne.into()), ); } + +// TODO Add test for having no relayer signer diff --git a/scripts/dex-router/src/index.ts b/scripts/dex-router/src/index.ts index adc4bb65..2b762779 100644 --- a/scripts/dex-router/src/index.ts +++ b/scripts/dex-router/src/index.ts @@ -81,16 +81,8 @@ export class DexRouter { } async bidStatusHandler(bidStatus: BidStatusUpdate) { - let resultDetails = ""; - if (bidStatus.type == "submitted" || bidStatus.type == "won") { - resultDetails = `, transaction ${bidStatus.result}`; - } else if (bidStatus.type == "lost") { - if (bidStatus.result) { - resultDetails = `, transaction ${bidStatus.result}`; - } - } console.log( - `Bid status for bid ${bidStatus.id}: ${bidStatus.type}${resultDetails}`, + `Bid status for bid ${bidStatus.id}: ${JSON.stringify(bidStatus)}`, ); } diff --git a/sdk/js/README.md b/sdk/js/README.md index 2f498c75..349d1a3e 100644 --- a/sdk/js/README.md +++ b/sdk/js/README.md @@ -45,7 +45,9 @@ function calculateOpportunityBid(opportunity: Opportunity): BidParams | null { } async function bidStatusCallback(bidStatus: BidStatusUpdate) { - console.log(`Bid status for bid ${bidStatus.id}: ${bidStatus.status.status}`); + console.log( + `Bid status for bid ${bidStatus.id}: ${JSON.stringify(bidStatus)}`, + ); } async function opportunityCallback(opportunity: Opportunity) { diff --git a/sdk/js/src/examples/simpleSearcherEvm.ts b/sdk/js/src/examples/simpleSearcherEvm.ts index c386776e..20c947d4 100644 --- a/sdk/js/src/examples/simpleSearcherEvm.ts +++ b/sdk/js/src/examples/simpleSearcherEvm.ts @@ -1,6 +1,6 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { BidStatusUpdateEvm, checkHex, Client } from "../index"; +import { checkHex, Client } from "../index"; import { privateKeyToAccount } from "viem/accounts"; import { isHex } from "viem"; import { BidStatusUpdate, Opportunity } from "../types"; @@ -35,21 +35,9 @@ class SimpleSearcherEvm { process.exit(1); } - async bidStatusHandler(_bidStatus: BidStatusUpdate) { - const bidStatus = _bidStatus as BidStatusUpdateEvm; - let resultDetails = ""; - if (bidStatus.type == "submitted" || bidStatus.type == "won") { - resultDetails = `, transaction ${bidStatus.result}, index ${bidStatus.index} of multicall`; - } else if (bidStatus.type == "lost") { - if (bidStatus.result) { - resultDetails = `, transaction ${bidStatus.result}`; - } - if (bidStatus.index) { - resultDetails += `, index ${bidStatus.index} of multicall`; - } - } + async bidStatusHandler(bidStatus: BidStatusUpdate) { console.log( - `Bid status for bid ${bidStatus.id}: ${bidStatus.type}${resultDetails}`, + `Bid status for bid ${bidStatus.id}: ${JSON.stringify(bidStatus)}`, ); } diff --git a/sdk/js/src/examples/simpleSearcherSvm.ts b/sdk/js/src/examples/simpleSearcherSvm.ts index 3021e7cf..9dc4a8c3 100644 --- a/sdk/js/src/examples/simpleSearcherSvm.ts +++ b/sdk/js/src/examples/simpleSearcherSvm.ts @@ -74,23 +74,9 @@ export class SimpleSearcherSvm { } async bidStatusHandler(bidStatus: BidStatusUpdate) { - let resultDetails = ""; - if ( - bidStatus.type == "submitted" || - bidStatus.type == "won" || - bidStatus.type == "expired" || - bidStatus.type == "cancelled" || - bidStatus.type == "failed" || - bidStatus.type == "awaiting_signature" - ) { - resultDetails = `, transaction ${bidStatus.result}`; - } else if (bidStatus.type == "lost") { - if (bidStatus.result) { - resultDetails = `, transaction ${bidStatus.result}`; - } - } + console.log("hiiiii daniiiiii"); console.log( - `Bid status for bid ${bidStatus.id}: ${bidStatus.type}${resultDetails}`, + `Bid status for bid ${bidStatus.id}: ${JSON.stringify(bidStatus)}`, ); } diff --git a/sdk/python/express_relay/searcher/examples/simple_searcher_evm.py b/sdk/python/express_relay/searcher/examples/simple_searcher_evm.py index 1dc642e1..a7e692b3 100644 --- a/sdk/python/express_relay/searcher/examples/simple_searcher_evm.py +++ b/sdk/python/express_relay/searcher/examples/simple_searcher_evm.py @@ -8,8 +8,7 @@ from express_relay.client import ExpressRelayClient, sign_bid from express_relay.constants import OPPORTUNITY_ADAPTER_CONFIGS from express_relay.models import BidStatusUpdate, Opportunity, OpportunityBidParams -from express_relay.models.base import BidStatusVariantsEvm -from express_relay.models.evm import BidEvm, BidStatusEvm, Bytes32, OpportunityEvm +from express_relay.models.evm import BidEvm, Bytes32, OpportunityEvm logger = logging.getLogger(__name__) @@ -84,25 +83,8 @@ async def bid_status_callback(self, bid_status_update: BidStatusUpdate): Args: bid_status_update: An object representing an update to the status of a bid. """ - id = bid_status_update.id - bid_status = typing.cast(BidStatusEvm, bid_status_update.bid_status) - status = bid_status.type - result = bid_status.result - index = bid_status.index - - result_details = "" - if ( - status == BidStatusVariantsEvm.SUBMITTED - or status == BidStatusVariantsEvm.WON - ): - result_details = f", transaction {result}, index {index} of multicall" - elif status == BidStatusVariantsEvm.LOST: - if result: - result_details = f", transaction {result}" - if index: - result_details += f", index {index} of multicall" logger.info( - f"Bid status for bid {id}: {status.value.replace('_', ' ')}{result_details}" + f"Bid status for bid {bid_status_update.id}: {bid_status_update.bid_status}" ) diff --git a/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py b/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py index e1d13889..43351c7e 100644 --- a/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py +++ b/sdk/python/express_relay/searcher/examples/simple_searcher_svm.py @@ -8,7 +8,6 @@ from express_relay.client import ExpressRelayClient from express_relay.constants import SVM_CONFIGS from express_relay.models import BidStatusUpdate, Opportunity, OpportunityDelete -from express_relay.models.base import BidStatusVariantsSvm from express_relay.models.svm import ( BidSvm, LimoOpportunitySvm, @@ -117,17 +116,9 @@ async def bid_status_callback(self, bid_status_update: BidStatusUpdate): Args: bid_status_update: An object representing an update to the status of a bid. """ - id = bid_status_update.id - status = bid_status_update.bid_status.type - result = bid_status_update.bid_status.result - - result_details = "" - if status not in [BidStatusVariantsSvm.PENDING, BidStatusVariantsSvm.LOST]: - result_details = f", transaction {result}" - elif status == BidStatusVariantsSvm.LOST: - if result: - result_details = f", transaction {result}" - self.logger.info(f"Bid status for bid {id}: {status.value}{result_details}") + self.logger.info( + f"Bid status for bid {bid_status_update.id}: {bid_status_update.bid_status}" + ) async def get_mint_decimals(self, mint: Pubkey) -> int: if str(mint) not in self.mint_decimals_cache: