Conversation
Add points type as fourth distribution paradigm — pure u64 PDA ledger with no token programs. Authority issues/closes, user cosigns use/transfer. Accounts: PointsConfig, UserPointsAccount Instructions: init_points, issue_points, use_points, transfer_points, close_points_account, close_points_config
Authority can force-burn a user's points and close their account when config.revocable is set. Gated on validate_revocable check. Revoked balance counted as used. Also adds intentional-design comment to close_points_config explaining admin authority over lifecycle.
7 fixture files, 8 test files covering all points instructions. Includes generic constraint tests, business logic error paths, PDA mismatch validation, and end-to-end lifecycle test.
|
|
||
| #[derive(CodamaType)] | ||
| pub struct PointsAccountClosedEvent { | ||
| pub points_config: Address, |
There was a problem hiding this comment.
Feels like it would be better to actually show the points config instead of just the address? Else indexers have to fetch an extra acc to get the configs
|
|
||
| #[derive(CodamaType)] | ||
| pub struct PointsConfigClosedEvent { | ||
| pub points_config: Address, |
There was a problem hiding this comment.
same here, won't do it on all the events, but I think it should apply accross
| assert_eq!(data.claimed_amount, expected_claimed_amount); | ||
| } | ||
|
|
||
| pub struct ExpectedPointsConfig<'a> { |
There was a problem hiding this comment.
we don't really use struct to compare vs the expected, might be better to either move all of it to that, or keep following our current implementation so its coherent
| user_account.balance = | ||
| user_account.balance.checked_sub(ix.data.quantity).ok_or(RewardsProgramError::MathOverflow)?; | ||
|
|
||
| config.total_used = config.total_used.checked_add(ix.data.quantity).ok_or(RewardsProgramError::MathOverflow)?; |
There was a problem hiding this comment.
just as an fyi, having a global config file that needs updating per instruction, means we won't be able ot use svm's parallelism as much, since write lock on the config for all point related ixs
| }; | ||
|
|
||
| // Transfer balances | ||
| from_account.balance = |
There was a problem hiding this comment.
need to check that the 2 accounts are different, else from_account's data change will be overwritten below when you save to_account
| drop(user_data); | ||
|
|
||
| // Require zero balance to close | ||
| if user_account.balance != 0 { |
There was a problem hiding this comment.
might want to make it a util like
#[inline(always)]
pub fn validate_balance(&self, amount: u64) -> Result<(), ProgramError> {
if self.balance < amount {
return Err(RewardsProgramError::InsufficientPointsBalance.into());
}
Ok(())
}
|
|
||
| // Count revoked points as used | ||
| if revoked_balance > 0 { | ||
| config.total_used = config.total_used.checked_add(revoked_balance).ok_or(RewardsProgramError::MathOverflow)?; |
There was a problem hiding this comment.
should this be added to total used ? coz they're not really "used", if they're revoked?
Summary
Test plan
cargo clippy -D warningsclean on program and testscargo fmt --checkcleanCloses TOO-197