-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Support create
and update
token metadata in stake-pool python bindings
#3978
Support create
and update
token metadata in stake-pool python bindings
#3978
Conversation
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.
This is on the right track! You'll need to be careful on the instruction encoding, but other than that, all good
@@ -17,6 +17,9 @@ | |||
MINIMUM_ACTIVE_STAKE: int = MINIMUM_DELEGATION | |||
"""Minimum active delegated staked required in a stake account""" | |||
|
|||
METADATA_PROGRAM_ID: PublicKey = PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s") | |||
"""Public key that identifies the SPL Token Metadata program.""" |
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.
nit: this is the metaplex metadata program
"""Public key that identifies the SPL Token Metadata program.""" | |
"""Public key that identifies the Metaplex Token Metadata program.""" |
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 sure, C/P mistake 😅
(withdraw_authority, _seed) = find_withdraw_authority_program_address(params.program_id, params.stake_pool) | ||
(token_metadata, _seed) = find_metadata_account(params.pool_mint) | ||
|
||
keys = [ | ||
AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=False), | ||
AccountMeta(pubkey=params.manager, is_signer=True, is_writable=False), | ||
AccountMeta(pubkey=withdraw_authority, is_signer=False, is_writable=False), | ||
AccountMeta(pubkey=params.pool_mint, is_signer=False, is_writable=False), | ||
AccountMeta(pubkey=params.payer, is_signer=True, is_writable=True), | ||
AccountMeta(pubkey=token_metadata, is_signer=False, is_writable=True), | ||
AccountMeta(pubkey=METADATA_PROGRAM_ID, is_signer=False, is_writable=False), | ||
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), | ||
AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), | ||
] |
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.
nit: I know it's not the easiest usage pattern, but to make this consistent with the other instruction creators, can you provide the ability to specify all accounts?
@joncinque |
The idea is to test that the new instruction bindings work, and that you can create and update token metadata through the stake pool program. The You can see the metadata rust tests at https://github.com/solana-labs/solana-program-library/blob/master/stake-pool/program/tests/create_pool_token_metadata.rs and https://github.com/solana-labs/solana-program-library/blob/master/stake-pool/program/tests/update_pool_token_metadata.rs. Feel free to add And finally, you'll need to add the token metadata program to the test validator when it's booted for testing, so be sure to change this in conftest.py:
|
f5d6e61
to
760639d
Compare
@joncinque I added actions for Btw sorry for rebases, I added ref to the issue in some commits that were missing it. |
0a9bb5a
to
a231551
Compare
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'm not so sure about the signers in send_transaction, ' cause i saw that in Rust code there's also the stake pool manager as signer, but in python it is actually a PublicKey and not a Keypair (as expected by the function itself).
The action
is a simplified wrapper that assumes the payer
is actually the manager, and there is no analogue to the Rust side, since it's also signing and sending the transaction, whereas the Rust version is just creating the instruction.
stake-pool/py/stake_pool/actions.py
Outdated
symbol=symbol, | ||
uri=uri, | ||
withdraw_authority=withdraw_authority, | ||
token_metadata=METADATA_PROGRAM_ID, |
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.
This should be the actual metadata account, and not the metadata program id.
stake-pool/py/stake_pool/actions.py
Outdated
|
||
txn = Transaction() | ||
txn.add( | ||
sp.CreateTokenMetadataParams( |
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.
Maybe I'm missing something, but this just gives a tuple, and not an instruction. You'll need to call create_metadata_account
with sp.CreateTokenMetadataParams
as a parameter.
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.
Yep sorry, missed it
if params.withdraw_authority: | ||
withdraw_authority = params.withdraw_authority | ||
else: | ||
(withdraw_authority, _seed) = find_withdraw_authority_program_address(params.program_id, params.stake_pool) | ||
|
||
if params.token_metadata: | ||
token_metadata = params.token_metadata | ||
else: | ||
(token_metadata, _seed) = find_metadata_account(params.pool_mint) |
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.
To avoid the earlier footgun, let's keep this logic as dumb as possible and put all parameters in CreateTokenMetadataParams
, including the rent sysvar, system program id, and metadata program id, and not make any of them optional.
Essentially, let's make this the same as all of the other instruction creators, and then the action
can fill in the right parameters
Btw, looking through your PR made me realize that we're behind in the stake pool program, so I've updated to the newest bindings at #4012 -- you'll just need to remove the sysvar rent account during "create metadata". |
a45222a
to
9ea6458
Compare
@joncinque Thanks, I did some updates following your guidelines, hope they're correct. I also added a simple test, can you check if it's ok? |
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.
It's looking close! Once the create test works, then you just need an update test, then this should be good to go!
stake-pool/py/stake_pool/actions.py
Outdated
async def create_token_metadata(client: AsyncClient, payer: Keypair, stake_pool_program_id: PublicKey, | ||
stake_pool_address: PublicKey, token_program_id: PublicKey, | ||
withdraw_authority: PublicKey, name: str, symbol: str, uri: str): |
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.
nit: For the actions, let's keep it simpler, same as you're using it in the test, and in this function you can derive the missing parameters:
async def create_token_metadata(client: AsyncClient, payer: Keypair, stake_pool_program_id: PublicKey, | |
stake_pool_address: PublicKey, token_program_id: PublicKey, | |
withdraw_authority: PublicKey, name: str, symbol: str, uri: str): | |
async def create_token_metadata(client: AsyncClient, payer: Keypair, | |
stake_pool_address: PublicKey, | |
name: str, symbol: str, uri: str): |
data = resp['result']['value']['data'] | ||
assert data[0] == name | ||
assert data[1] == symbol | ||
assert data[2] == uri |
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.
You'll need a way to deserialize the data in the metadata account, which will be a bit annoying. Looking at the struct space definitions at https://github.com/metaplex-foundation/metaplex-program-library/blob/0e999e2507118a7e930c3a176709d4ab559e060b/token-metadata/program/src/state/metadata.rs#L17, looks like the name should be between indexes 69 and 101, the symbol between 105 and 115, and the uri between 119 and 319, and I think you can interpret those bytes as utf8, so just directly pull out those ranges
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 I saw that data in Rust code are deserialized in the Metadata struct, I felt something was definitely missing. I did some change at the test and reverted the last commit on actions.
Hi @joncinque , sorry to bother...did you read my last comment? If you can, please check the latest commit so I can move forward following you direction. Thanks a lot. |
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.
Sorry, I thought you were still working on it. Once you fix the issues, get the create test working, and add an update test, this should be good to go!
stake-pool/py/stake_pool/actions.py
Outdated
symbol=symbol, | ||
uri=uri, | ||
withdraw_authority=withdraw_authority, | ||
token_metadata=TOKEN_PROGRAM_ID, |
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.
token_metadata
should be the result of find_metadata_account(stake_pool.pool_mint)
, and then you still need to add the system program id and token metadata program id
stake-pool/py/stake_pool/actions.py
Outdated
symbol=symbol, | ||
uri=uri, | ||
withdraw_authority=withdraw_authority, | ||
token_metadata=TOKEN_PROGRAM_ID, |
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, you'll need find_metadata_account(stake_pool.pool_mint)
and the metadata program id
4571a8e
to
6e73e00
Compare
@joncinque Hi, I updated Giving you more info, I'm working in a VirtualBox Ubuntu machine, don' t know if it's related to this. Hope this can be relevant info, sorry to bother you :) |
It looks like there was a bug in your test, since it's trying to decode the wrong part of the response. Be sure to check the errors reported when you run Here's a patch that will fix your test and make everything work:
After that, you just need an update test, then this will be good to go! |
04decaf
to
dd1046e
Compare
@joncinque Hi! Rebased, fixed the create test and added the update one. Thanks for your support! |
Thanks for all of your patience and for integrating all of my suggestions -- this is finally good to go! |
Problem
#3335 added new instructions (
create_metadata
andupdate_metadata
) to the stake-pool, while these are not supported in python.Solution
Add python bindings
create_token_metadata
andupdate_token_metadata
in stake-pool, with their relative tests.Fixes #3370