port and improve inline-spl from agave#70
Conversation
862db78 to
3ea338c
Compare
| if is_initialized && is_token_2022_account { | ||
| account_data.resize(SplAccount::LEN + 2, 0); | ||
| set_account_type::<SplAccount2022>(&mut account_data).unwrap(); |
There was a problem hiding this comment.
to be honest i couldnt figure out why set_account_type() requires there to be 167 bytes instead of 166
There was a problem hiding this comment.
I think that's actually an off-by-one error in type_and_tlv_indices, and the <= should be <: https://github.com/solana-program/token-2022/blob/f2341f9d06abc0f0781cec5948232169d5e372a2/program/src/extension/mod.rs#L315
I put in solana-program/token-2022#369 to fix it
joncinque
left a comment
There was a problem hiding this comment.
Looks great overall! Mostly small things
| pub mod program_v1_1_0 { | ||
| solana_pubkey::declare_id!("NatA1Zyo48dJ7yuwR7cGURwhskKA8ywUyxb9GvG7mTC"); | ||
| } |
There was a problem hiding this comment.
We can probably remove this, since it was just used for the program upgrade
| @@ -0,0 +1,25 @@ | |||
| # this package prevents a (future) circular dependency between spl_generic_token and spl_token | |||
There was a problem hiding this comment.
Makes sense if we imagine that programs will implement the traits
There was a problem hiding this comment.
yea, the programs already impl their own versions of the traits distinct from inline-spl so the code that makes up generic-token presently is copy-pasted in three places, my thinking was by having no dev dependency we can delete the code not just in inline-spl but in the token programs too and we have one and only one impl
generic-token/Cargo.toml
Outdated
| ] } | ||
|
|
||
| [lib] | ||
| crate-type = ["cdylib", "lib"] |
There was a problem hiding this comment.
This can just be an rlib or lib, no need for cdylib
generic-token/README.md
Outdated
| generic_token::Account { | ||
| mint: Pubkey, | ||
| owner: Pubkey, | ||
| amount: u64, | ||
| } | ||
|
|
||
| generic_token::Mint { | ||
| supply: u64, | ||
| decimals: u8, | ||
| } |
There was a problem hiding this comment.
nit: Maybe we should give the full path for users? On the flip-side, just seeing the path makes me wonder if we should change the filename from generic_token.rs to state.rs or something. What do you think?
| generic_token::Account { | |
| mint: Pubkey, | |
| owner: Pubkey, | |
| amount: u64, | |
| } | |
| generic_token::Mint { | |
| supply: u64, | |
| decimals: u8, | |
| } | |
| spl_generic_token::generic_token::Account { | |
| mint: Pubkey, | |
| owner: Pubkey, | |
| amount: u64, | |
| } | |
| spl_generic_token::generic_token::Mint { | |
| supply: u64, | |
| decimals: u8, | |
| } |
There was a problem hiding this comment.
what i was imagining is a user doing use spl_generic_token::{generic_token, token::{self, GenericTokenAccount}, .. }. the existing pattern for token and token_2022 is that the structs are all named Mint and Account, so i kept the pattern so users can clearly distinguish their imported types without aliasing (generic_token::Account vs token::Account etc)
i think generic::Account and state::Account would both be confusing to users of the library if they import that way. however we do already have token::native as a module, so we could do token::generic::Account. i think a distinct toplevel (generic_token::Account) is preferable though because this overloads "token" to mean "the tokenkeg program" as well as "the concept of a token"
There was a problem hiding this comment.
Gotcha, that makes sense to me!
generic-token/src/token.rs
Outdated
| pub mod program_v3_4_0 { | ||
| solana_pubkey::declare_id!("NToK4t5AQzxPNpUA84DkxgfXaVDbDQQjpHKCqsbY46B"); | ||
| } |
generic-token/src/token.rs
Outdated
| // Call after account length has already been verified | ||
| fn unpack_account_amount_unchecked(account_data: &[u8]) -> u64 { | ||
| let offset = SPL_TOKEN_ACCOUNT_AMOUNT_OFFSET; | ||
| *bytemuck::from_bytes(&account_data[offset..offset.wrapping_add(mem::size_of::<u64>())]) |
There was a problem hiding this comment.
nit: Since account data is stored as little-endian, and this code could run on big-endian systems, I'm thinking we should use u64::from_le_bytes instead to be totally safe, similar to unpack_mint_supply_unchecked
| ); | ||
| define_checked_getter!(unpack_account_amount, unpack_account_amount_unchecked, u64); | ||
|
|
||
| // Call after account length has already been verified |
generic-token/src/token.rs
Outdated
|
|
||
| pub struct Account; | ||
| impl Account { | ||
| pub fn get_packed_len() -> usize { |
There was a problem hiding this comment.
nit: I don't see where this is used downstream, but wanna make this const?
generic-token/src/generic_token.rs
Outdated
| /// Minimum viable SPL Token parsers to avoid a dependency on the spl-token and spl-token-2022 crates. | ||
| /// Users may use the generic traits directly, but this requires them to select the correct implementation | ||
| /// based on the account's program id. `generic_token::Account` and `generic_token::Mint` abstract over | ||
| /// this and require no knowledge of the different token programs on the part of the caller at all. | ||
| /// | ||
| /// We provide the minimum viable interface to determine balances and ownership. For more advanced use-cases, | ||
| /// it is recommended to use to full token program crates instead. |
There was a problem hiding this comment.
nit: I believe these comments should have //! at the start of each line instead
There was a problem hiding this comment.
oh this syntax is actually new to me!
| if is_initialized && is_token_2022_account { | ||
| account_data.resize(SplAccount::LEN + 2, 0); | ||
| set_account_type::<SplAccount2022>(&mut account_data).unwrap(); |
There was a problem hiding this comment.
I think that's actually an off-by-one error in type_and_tlv_indices, and the <= should be <: https://github.com/solana-program/token-2022/blob/f2341f9d06abc0f0781cec5948232169d5e372a2/program/src/extension/mod.rs#L315
I put in solana-program/token-2022#369 to fix it
|
ok that should be everything! unless you have thoughts on changing the module name/structure |
due to the exigencies of history and the tumult of our modern world, we will need to parse token accounts and mints inside svm. the reasons for this are out of scope
agave has a small crate
solana_inline_spl, which provides a thin bytemuck view overspl_tokenandspl_token_2022accounts. i intended to use this mostly as-is, but it turns out we are splitting the agave and svm repos, so putting it in either of them would introduce a circular dependency. we dont want to put it in the token repos because it uses elements from all of tokenkeg, token22, and ata. we were going to put it in sdk, but everyone who approved of this approved tepidly at best. it seems silly to give it its own repo because it is so small. this feels like the perfect place, particularly since the workspace lets packages control their own dependencies seperatelychanges from the existing
solana_inline_spl:amountsupplyanddecimalsgeneric_token::Accountandgeneric_token::Mintwhich provideunpack(). this is because as-designed the generic trait expects callers to know what token programs they are working with and choose the correct trait implementation. instead, we accept the program id and outside callers do not need to know about specific token programs at all. we heavily restrict the fields we make available: if you need mint authority, account delegation, etc, you are doing something more complicated than this package is meant to coverspl_token_ids()andis_known_spl_token_id()fromsolana_account_decoderto consolidate in one placewe also use the token22 implementation of
verify_account_data()which fixes a bug found in the inline-spl versionto see only my changes to the original agave impl:
git diff ca57aea..8e1aa5a