Conversation
fa0b257 to
1e0b60b
Compare
5ff8680 to
310dc5c
Compare
310dc5c to
5542960
Compare
joncinque
left a comment
There was a problem hiding this comment.
Looks really great! Just a couple of small things
| } | ||
|
|
||
| interface DepositSolParams { | ||
| rpc: Rpc<GetAccountInfoApi & GetMinimumBalanceForRentExemptionApi & GetStakeMinimumDelegationApi>; |
There was a problem hiding this comment.
nit: I think this only needs GetAccountInfoApi
| rpc: Rpc<GetAccountInfoApi & GetMinimumBalanceForRentExemptionApi & GetStakeMinimumDelegationApi>; | |
| rpc: Rpc<GetAccountInfoApi>; |
| // we round division down and reject deposits too small to generate a fee | ||
| // this is to avoid pathological cases where eg someone deposits 2 lamps and pays 50% | ||
| let deposit_sol_fee = raw_tokens | ||
| .checked_mul(DEPOSIT_SOL_FEE_BPS) | ||
| .and_then(|n| n.checked_div(MAX_BPS)) | ||
| .ok_or(SinglePoolError::UnexpectedMathError)?; |
There was a problem hiding this comment.
I would recommend a ceil_div on this calculation so that we always take a little bit more.
Because of the 0 check later, it's impossible for someone to deposit less than 100 lamports anyway, which is a slick touch
There was a problem hiding this comment.
Because of the 0 check later, it's impossible for someone to deposit less than 100 lamports anyway
this would no longer be true if we used ceiling division though because the fee would always be at least 1. idk i think its more straightforward doing it this way, you can only game it for 1 lamport which doesnt matter for large deposits, and we can easily reject dust (microdust?) deposits. given 5000 lamps per signature, there isnt any reason to deposit 1/50 of that to play games over 1/5000 of it
There was a problem hiding this comment.
I'm mostly suggesting it for consistency with other protocols which typically ceiling fee calculations. We can keep it this way if you prefer
| // replenish to delegate the deposit. this safely returns Ok if onramp doesnt meet minimum delegation | ||
| invoke( | ||
| &svsp_instruction::replenish_pool(program_id, vote_account_info.key), | ||
| &[ | ||
| vote_account_info.clone(), | ||
| pool_info.clone(), | ||
| pool_stake_info.clone(), | ||
| pool_onramp_info.clone(), | ||
| pool_stake_authority_info.clone(), | ||
| clock_info.clone(), | ||
| stake_history_info.clone(), | ||
| stake_config_info.clone(), | ||
| stake_program_info.clone(), | ||
| ], | ||
| )?; |
There was a problem hiding this comment.
We don't typically perform re-entrancy in our programs, so just flagging the behavior, but I can't see a reason why it would be a problem
There was a problem hiding this comment.
do you think its worth making a hard rule that we dont? i considered using instruction introspection to verify a replenish follows, because i hate how many accounts this instruction requires that it only uses for this cpi. i decided it would only add complexity for no benefit since the transaction would need the accounts anyway. but the point that we would avoid a potentially risky self-cpi does mean that there is a real tradeoff beyond aesthetics
There was a problem hiding this comment.
I've thought about it a bit more, and maybe it's less risky to self-cpi, since we should get additional checks from the runtime. Let's check with the runtime team and see what they think?
There was a problem hiding this comment.
ok how do you feel about this concept d0bfddb i think i prefer ixn introspection now. the thing is if we mess up reentry it could have catastrophic consequences. if we mess up checking for a replenish... it doesnt really matter. it just means the pool is less fresh than we would prefer
There was a problem hiding this comment.
I kind of worry about transaction introspection, since it doesn't work with CPI use-cases. This should be a pretty low-level primitive, so easy to compose in defi and whatnot.
I'd lean more towards the re-entrancy or just calling process_replenish directly
There was a problem hiding this comment.
i reverted the ixn introspection commit
| AccountMeta::new_readonly(system_program::id(), false), | ||
| AccountMeta::new_readonly(spl_token::id(), false), | ||
| AccountMeta::new_readonly(stake::program::id(), false), | ||
| AccountMeta::new_readonly(*program_id, false), |
There was a problem hiding this comment.
Is this actually needed for re-entrancy? Since the JS client seem ok without it, I'm going to guess not
There was a problem hiding this comment.
hana@laptop:program$ git diff
diff --git a/program/src/instruction.rs b/program/src/instruction.rs
index fc2a356..b70cc72 100644
--- a/program/src/instruction.rs
+++ b/program/src/instruction.rs
@@ -425,7 +425,7 @@ pub fn deposit_sol(
AccountMeta::new_readonly(system_program::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
AccountMeta::new_readonly(stake::program::id(), false),
- AccountMeta::new_readonly(*program_id, false),
+ //AccountMeta::new_readonly(*program_id, false),
];
Instruction {
hana@laptop:program$ cargo test-sbf --test deposit_sol success::stakeprogramversion_stable_test_stake_amount_0_expects 2> /dev/null
running 1 test
test success::stakeprogramversion_stable_test_stake_amount_0_expects ... FAILED
failures:
---- success::stakeprogramversion_stable_test_stake_amount_0_expects stdout ----
thread 'success::stakeprogramversion_stable_test_stake_amount_0_expects' (26256) panicked at program/tests/deposit_sol.rs:102:10:
called `Result::unwrap()` on an `Err` value: TransactionError(InstructionError(1, MissingAccount))
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thats an interesting point with the js though i didnt notice that...
There was a problem hiding this comment.
well i did confirm that we get the same failure if we omit the program account and use the spl-single-pool cli against solana-test-validator. i also confirmed that the program does not need the extra account when running the js test and that replenish succeeds
this means it is a) a bug in the js client to not pass the account, which is b) hidden by either a bug in litesvm, or a semantic difference in all svm-based testing frameworks, which causes the cpi to succeed when it should fail
ill wait for resolution on #631 (comment) before addressing it one way or the other
There was a problem hiding this comment.
Oh interesting, sounds like it might be a bug in litesvm then!
There was a problem hiding this comment.
5e9dfae added the account to js and added a rust test that will tell us whether this is litesvm or svm in general. ill test out mollusk separately to see if it does this too
There was a problem hiding this comment.
37ffca0 nevermind i deleted the test, theres no way mollusk has this. i was confused thinking litesvm used a stripped-down real svm that somehow elided program-runtime prechecks and maybe the issue may show up elsewhere, i didnt realize it actually used an entirely fake svm
d0bfddb to
3f645ec
Compare
joncinque
left a comment
There was a problem hiding this comment.
Looks good to me, let's go with this! There's a merge conflict and a few uses of nev in this PR in case you want to update that -- once it's all good, I'll approve
`DepositSol` is a new instruction that allows depositing liquid sol directly into the pool onramp for a fee, calculated by underminting tokens to spread the benefit to all existing holders
37ffca0 to
b8335c6
Compare
the latest. the greatest. it needs no further introduction. god knows ive talked about it too much already. deposit sol
closes #46