-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Swap js integration #320
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,8 +115,8 @@ local_resource( | |
# setup limo global config and vaults for buy and sell tokens | ||
RUN_CLI= "ADMIN=../../keypairs/admin.json RPC_ENV=localnet npm exec limo-cli --" | ||
SET_GLOBAL_CONFIG = "LIMO_GLOBAL_CONFIG=$(solana-keygen pubkey ../../keypairs/limo_global_config.json)" | ||
MINT_SELL= "$(solana-keygen pubkey ../../keypairs/mint_sell.json)" | ||
MINT_BUY= "$(solana-keygen pubkey ../../keypairs/mint_buy.json)" | ||
MINT_SELL= "$(solana-keygen pubkey %s/keypairs/mint_sell.json)" % config.main_dir | ||
MINT_BUY= "$(solana-keygen pubkey %s/keypairs/mint_buy.json)" % config.main_dir | ||
local_resource( | ||
"svm-limo-setup", | ||
"""solana-keygen new -o ../../keypairs/limo_global_config.json -f --no-bip39-passphrase \ | ||
|
@@ -211,14 +211,21 @@ local_resource( | |
|
||
local_resource( | ||
"svm-searcher-py", | ||
serve_cmd="poetry run python3 -m express_relay.searcher.examples.testing_searcher_svm --endpoint-express-relay http://127.0.0.1:9000 --chain-id development-solana --private-key-json-file ../../keypairs/searcher_js.json --endpoint-svm http://127.0.0.1:8899 --bid 10000000 --fill-rate 4 --bid-margin 100 --with-latency", | ||
serve_cmd="poetry run python3 -m express_relay.searcher.examples.testing_searcher_svm --endpoint-express-relay http://127.0.0.1:9000 --chain-id development-solana --private-key-json-file ../../keypairs/searcher_py.json --endpoint-svm http://127.0.0.1:8899 --bid 10000000 --fill-rate 4 --bid-margin 100 --with-latency", | ||
serve_dir="sdk/python", | ||
resource_deps=["svm-initialize-programs", "auction-server"], | ||
) | ||
|
||
local_resource( | ||
"svm-searcher-js", | ||
serve_cmd="pnpm run testing-searcher-limo --endpoint-express-relay http://127.0.0.1:9000 --chain-id development-solana --private-key-json-file ../../keypairs/searcher_py.json --endpoint-svm http://127.0.0.1:8899 --bid 10000000 --fill-rate 4 --bid-margin 100 --with-latency", | ||
serve_cmd="pnpm run testing-searcher-limo --endpoint-express-relay http://127.0.0.1:9000 --chain-id development-solana --private-key-json-file ../../keypairs/searcher_js.json --endpoint-svm http://127.0.0.1:8899 --bid 1000 --fill-rate 4 --bid-margin 100", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mint more tokens to everyone and revert bid number to the higher value There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason you are setting lower bid number here? if the bid isn't high enough, you may not be paying for the rent of the fee receiver if it doesn't already have the funds for rent exemption. i think it's fine here bc we airdrop, but worth checking and figuring out the possible scenarios |
||
serve_dir="sdk/js", | ||
resource_deps=["svm-initialize-programs", "auction-server"], | ||
) | ||
|
||
local_resource( | ||
"svm-test-swap-endpoint", | ||
"poetry -C tilt-scripts run python3 -m tilt-scripts.svm.test_swap --file-private-key-taker keypairs/searcher_py.json --auction-server-url http://localhost:9000 --input-mint {MINT_SELL} --output-mint {MINT_BUY} --rpc-url {RPC_URL}" | ||
.format(RPC_URL=rpc_url_solana, MINT_SELL=MINT_SELL, MINT_BUY=MINT_BUY), | ||
resource_deps=["svm-searcher-js"], | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,13 +61,9 @@ pub struct OpportunityBidResult { | |
} | ||
|
||
#[derive(Serialize, Deserialize, ToSchema, Clone, PartialEq, Debug, Display)] | ||
#[serde(rename_all = "lowercase")] | ||
#[serde(rename_all = "snake_case")] | ||
pub enum ProgramSvm { | ||
#[serde(rename = "swap_kamino")] | ||
#[strum(serialize = "swap_kamino")] | ||
SwapKamino, | ||
#[serde(rename = "limo")] | ||
#[strum(serialize = "limo")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. strum and serde are doing diff stuff. Are you sure it's safe to remove the strum? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think strum here will affect the |
||
Limo, | ||
} | ||
|
||
|
@@ -298,12 +294,11 @@ pub struct OpportunityEvm { | |
/// Program specific parameters for the opportunity. | ||
#[serde_as] | ||
#[derive(Serialize, Deserialize, ToSchema, Clone, PartialEq, Debug, ToResponse)] | ||
#[serde(tag = "program")] | ||
#[serde(tag = "program", rename_all = "snake_case")] | ||
pub enum OpportunityParamsV1ProgramSvm { | ||
/// Limo program specific parameters for the opportunity. | ||
/// It contains the Limo order to be executed, encoded in base64. | ||
/// SDKs will decode this order and create transaction for bidding on the opportunity. | ||
#[serde(rename = "limo")] | ||
#[schema(title = "limo")] | ||
Limo { | ||
/// The Limo order to be executed, encoded in base64. | ||
|
@@ -316,7 +311,6 @@ pub enum OpportunityParamsV1ProgramSvm { | |
order_address: Pubkey, | ||
}, | ||
/// Swap program specific parameters for the opportunity. | ||
#[serde(rename = "swap")] | ||
#[schema(title = "swap")] | ||
Swap { | ||
/// The user wallet address which requested the quote from the wallet. | ||
|
@@ -341,6 +335,7 @@ pub enum OpportunityParamsV1ProgramSvm { | |
} | ||
|
||
#[derive(Serialize, Deserialize, ToSchema, Clone, PartialEq, Debug, ToResponse)] | ||
#[serde(tag = "type", rename_all = "snake_case")] | ||
pub enum QuoteTokens { | ||
InputTokenSpecified { | ||
input_token: TokenAmountSvm, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,6 +77,7 @@ use { | |
transaction::VersionedTransaction, | ||
}, | ||
std::{ | ||
str::FromStr, | ||
sync::Arc, | ||
time::Duration, | ||
}, | ||
|
@@ -546,22 +547,6 @@ impl Service<Svm> { | |
(Err(_), Ok(swap_instruction)) => { | ||
let swap_data = Self::extract_swap_data(&swap_instruction)?; | ||
|
||
let router = self | ||
.extract_account( | ||
&transaction, | ||
&swap_instruction, | ||
self.config | ||
.chain_config | ||
.express_relay | ||
.router_account_position_swap, | ||
) | ||
.await?; | ||
if router != self.config.chain_config.wallet_program_router_account { | ||
return Err(RestError::BadParameters( | ||
"Must use approved router for swap instruction".to_string(), | ||
)); | ||
} | ||
|
||
let user_wallet = self | ||
.extract_account( | ||
&transaction, | ||
|
@@ -616,23 +601,71 @@ impl Service<Svm> { | |
}, | ||
), | ||
}; | ||
let mint_fee = match swap_data.fee_token { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think some of this server stuff may be unnecessary once you pull main? pushed some updates recently |
||
FeeToken::Input => mint_input, | ||
FeeToken::Output => mint_output, | ||
}; | ||
|
||
let permission_account = get_quote_permission_key(&tokens, &user_wallet); | ||
let router_fee_receiver_ta = self | ||
.extract_account( | ||
&transaction, | ||
&swap_instruction, | ||
self.config | ||
.chain_config | ||
.express_relay | ||
.router_account_position_swap, | ||
) | ||
.await?; | ||
|
||
//TODO* : do not hardcode the token program and refactor into separate function | ||
let fee_token_program = Pubkey::from_str( | ||
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", | ||
) | ||
.map_err(|e| { | ||
RestError::BadParameters(format!("Invalid token program address: {:?}", e)) | ||
})?; | ||
let associated_token_program = Pubkey::from_str( | ||
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", | ||
) | ||
.map_err(|e| { | ||
RestError::BadParameters(format!( | ||
"Invalid associated token program address: {:?}", | ||
e | ||
)) | ||
})?; | ||
let expected_router_fee_receiver_ta = Pubkey::find_program_address( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should use this address for creating the permission key There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think the whole point of making the router fee receiver ta generic as opposed to constraining it to be the ATA was so that routers could provide arbitrary token accounts also the wallet_program_router_account is no longer in the config |
||
&[ | ||
&self | ||
.config | ||
.chain_config | ||
.wallet_program_router_account | ||
.to_bytes(), | ||
&fee_token_program.to_bytes(), | ||
&mint_fee.to_bytes(), | ||
], | ||
&associated_token_program, | ||
) | ||
.0; | ||
|
||
if router_fee_receiver_ta != expected_router_fee_receiver_ta { | ||
return Err(RestError::BadParameters( | ||
"Must use approved router token account for swap instruction".to_string(), | ||
)); | ||
} | ||
|
||
let permission_account = get_quote_permission_key(&tokens, &user_wallet); | ||
Ok(BidDataSvm { | ||
amount: bid_amount, | ||
permission_account, | ||
router, | ||
// TODO*: to fix once deadline param added to swap instruction--just set this way to make sure compiles | ||
deadline: OffsetDateTime::now_utc(), | ||
// deadline: OffsetDateTime::from_unix_timestamp(swap_data.deadline).map_err( | ||
// |e| { | ||
// RestError::BadParameters(format!( | ||
// "Invalid deadline: {:?} {:?}", | ||
// swap_data.deadline, e | ||
// )) | ||
// }, | ||
// )?, | ||
router: self.config.chain_config.wallet_program_router_account, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a good point, we should probably include the router in the |
||
deadline: OffsetDateTime::from_unix_timestamp(swap_data.deadline).map_err( | ||
|e| { | ||
RestError::BadParameters(format!( | ||
"Invalid deadline: {:?} {:?}", | ||
swap_data.deadline, e | ||
)) | ||
}, | ||
)?, | ||
submit_type: SubmitType::ByOther, | ||
}) | ||
} | ||
|
@@ -642,12 +675,10 @@ impl Service<Svm> { | |
} | ||
} | ||
|
||
fn all_signatures_exists( | ||
fn relayer_signer_exists( | ||
&self, | ||
message_bytes: &[u8], | ||
accounts: &[Pubkey], | ||
signatures: &[Signature], | ||
missing_signers: &[Pubkey], | ||
) -> Result<(), RestError> { | ||
let relayer_pubkey = self.config.chain_config.express_relay.relayer.pubkey(); | ||
let relayer_exists = accounts[..signatures.len()] | ||
|
@@ -660,9 +691,17 @@ impl Service<Svm> { | |
relayer_pubkey | ||
))); | ||
} | ||
|
||
Ok(()) | ||
} | ||
fn all_signatures_exists( | ||
&self, | ||
message_bytes: &[u8], | ||
accounts: &[Pubkey], | ||
signatures: &[Signature], | ||
missing_signers: &[Pubkey], | ||
) -> Result<(), RestError> { | ||
for (signature, pubkey) in signatures.iter().zip(accounts.iter()) { | ||
if missing_signers.contains(pubkey) || pubkey.eq(&relayer_pubkey) { | ||
if missing_signers.contains(pubkey) { | ||
continue; | ||
} | ||
if !signature.verify(pubkey.as_ref(), message_bytes) { | ||
|
@@ -714,7 +753,13 @@ impl Service<Svm> { | |
) | ||
} | ||
SubmitType::ByServer => { | ||
self.all_signatures_exists(&message_bytes, accounts, &signatures, &[]) | ||
self.relayer_signer_exists(accounts, &signatures)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the relayer exist at this point? |
||
self.all_signatures_exists( | ||
&message_bytes, | ||
accounts, | ||
&signatures, | ||
&[self.config.chain_config.express_relay.relayer.pubkey()], | ||
) | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -207,20 +207,14 @@ pub async fn get_opportunities( | |
(status = 404, description = "No quote available right now", body = ErrorBodyResponse), | ||
),)] | ||
pub async fn post_quote( | ||
auth: Auth, | ||
State(store): State<Arc<StoreNew>>, | ||
Json(params): Json<QuoteCreate>, | ||
) -> Result<Json<Quote>, RestError> { | ||
let program = get_program(&auth)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's better to make it permissioned at the beginnig |
||
if program != ProgramSvm::SwapKamino { | ||
return Err(RestError::Forbidden); | ||
} | ||
|
||
let quote = store | ||
.opportunity_service_svm | ||
.get_quote(GetQuoteInput { | ||
quote_create: params.into(), | ||
program, | ||
program: ProgramSvm::SwapKamino, | ||
}) | ||
.await?; | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,10 +28,12 @@ export const SVM_CONSTANTS: Record<string, SvmConstantsConfig> = { | |
expressRelayProgram: new PublicKey( | ||
"PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou" | ||
), | ||
walletRouter: new PublicKey("3hv8L8UeBbyM3M25dF3h2C5p8yA4FptD7FFZu4Z1jCMn"), | ||
}, | ||
solana: { | ||
expressRelayProgram: new PublicKey( | ||
"PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou" | ||
), | ||
walletRouter: new PublicKey("3hv8L8UeBbyM3M25dF3h2C5p8yA4FptD7FFZu4Z1jCMn"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add todo to change later There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. merge main and get rid of |
||
}, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix local pre-commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had the same issue. Maybe if you upgrade the pre-commit to
4.0.1
or later, it works.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, this issue popped up for me out of the blue yesterday. updating pre commit resolved it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes you should run this hook when
Cargo.toml
orCargo.lock
get updated