Skip to content

Commit 3a47faf

Browse files
committed
update mapping account size, add support for update price
1 parent fc513f0 commit 3a47faf

File tree

5 files changed

+150
-9
lines changed

5 files changed

+150
-9
lines changed

program_admin/__init__.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ async def fetch_minimum_balance(self, size: int) -> int:
114114

115115
async def refresh_program_accounts(self):
116116
async with AsyncClient(self.rpc_endpoint) as client:
117-
logger.info("Refreshing program accounts")
117+
logger.info(f"Refreshing program accounts for {self.program_key}")
118118
result = (
119119
await client.get_program_accounts(
120120
pubkey=self.program_key,
@@ -395,7 +395,9 @@ async def sync_mapping_instructions(
395395
)
396396
)
397397

398-
logger.debug("Building pyth_program.init_mapping instruction")
398+
logger.debug(
399+
f"Building pyth_program.init_mapping instruction: {funding_keypair.public_key}, {mapping_0_keypair.public_key}"
400+
)
399401
instructions.append(
400402
pyth_program.init_mapping(
401403
self.program_key,
@@ -603,6 +605,28 @@ async def sync_price_instructions(
603605

604606
return (instructions, [funding_keypair, price_keypair])
605607

608+
def update_price_instructions(
609+
self,
610+
publisher_keypair: Keypair,
611+
price_pubkey: PublicKey,
612+
price: int,
613+
confidence: int,
614+
price_slot: int,
615+
) -> Tuple[List[TransactionInstruction], List[Keypair]]:
616+
instructions = []
617+
instructions.append(
618+
pyth_program.upd_price(
619+
self.program_key,
620+
publisher_keypair.public_key,
621+
price_pubkey,
622+
1,
623+
price,
624+
confidence,
625+
price_slot,
626+
)
627+
)
628+
return (instructions, [publisher_keypair])
629+
606630
async def sync_authority_permissions_instructions(
607631
self,
608632
reference_authority_permissions: ReferenceAuthorityPermissions,

program_admin/cli.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,23 +297,31 @@ def list_accounts(network, rpc_endpoint, program_key, keys, publishers, commitme
297297

298298
for product_key in mapping_account.data.product_account_keys:
299299
product_account = program_admin.get_product_account(product_key)
300+
print(f" Product Public Key: {product_account.public_key}")
300301
print(f" Product: {product_account.data.metadata['symbol']}")
301302

302303
if product_account.data.first_price_account_key != PublicKey(0):
303304
price_account = program_admin.get_price_account(
304305
product_account.data.first_price_account_key
305306
)
307+
print(f" Price Account: {price_account.public_key}")
306308
print(
307309
f" Price: {price_account.data.exponent} exponent ({price_account.data.components_count} components)"
308310
)
311+
print(f" numPublishers: {price_account.data.components_count}")
312+
print(f" numPrices: {price_account.data.quoters_count}")
313+
print(f" numComponents: {len(price_account.data.price_components)}")
314+
print(f" Aggregate: {price_account.data.aggregate}")
309315

310316
for component in price_account.data.price_components:
311317
try:
312318
name = publishers_map["names"][component.publisher_key]
313319
except KeyError:
314320
name = f"??? ({component.publisher_key})"
315321

316-
print(f" Publisher: {name}")
322+
print(
323+
f" Publisher: {name}: {component.latest_price} {component.aggregate_price}"
324+
)
317325

318326
mapping_key = mapping_account.data.next_mapping_account_key
319327

@@ -462,11 +470,9 @@ def sync(
462470
ref_permissions = parse_permissions_with_overrides(
463471
Path(permissions), Path(overrides), network
464472
)
465-
466473
ref_authority_permissions = parse_authority_permissions_json(
467474
Path(authority_permissions)
468475
)
469-
470476
asyncio.run(
471477
program_admin.sync(
472478
ref_products=ref_products,
@@ -480,6 +486,41 @@ def sync(
480486
)
481487

482488

489+
@click.command()
490+
@click.option("--network", help="Solana network", envvar="NETWORK")
491+
@click.option("--rpc-endpoint", help="Solana RPC endpoint", envvar="RPC_ENDPOINT")
492+
@click.option("--program-key", help="Pyth program key", envvar="PROGRAM_KEY")
493+
@click.option("--keys", help="Path to keys directory", envvar="KEYS")
494+
@click.option("--publisher", help="key file of the publisher")
495+
@click.option("--price-account", help="Public key of the price account")
496+
@click.option("--price", help="Price to set")
497+
@click.option("--price-slot", help="Price slot to set")
498+
def update_price(
499+
network,
500+
rpc_endpoint,
501+
program_key,
502+
keys,
503+
publisher,
504+
price_account,
505+
price,
506+
price_slot,
507+
):
508+
program_admin = ProgramAdmin(
509+
network=network,
510+
rpc_endpoint=rpc_endpoint,
511+
key_dir=keys,
512+
program_key=program_key,
513+
price_store_key=None,
514+
commitment="confirmed",
515+
)
516+
publisher_keypair = load_keypair(publisher, key_dir=keys)
517+
price_account = PublicKey(price_account)
518+
(instructions, signers,) = program_admin.update_price_instructions(
519+
publisher_keypair, price_account, int(price), 100, int(price_slot)
520+
)
521+
asyncio.run(program_admin.send_transaction(instructions, signers))
522+
523+
483524
@click.command()
484525
@click.option("--network", help="Solana network", envvar="NETWORK")
485526
@click.option("--rpc-endpoint", help="Solana RPC endpoint", envvar="RPC_ENDPOINT")
@@ -578,5 +619,6 @@ def resize_price_accounts_v2(
578619
cli.add_command(update_product_metadata)
579620
cli.add_command(migrate_upgrade_authority)
580621
cli.add_command(resize_price_accounts_v2)
622+
cli.add_command(update_price)
581623
logger.remove()
582624
logger.add(sys.stdout, serialize=(not os.environ.get("DEV_MODE")))

program_admin/instructions.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from typing import Dict
22

3-
from construct import Bytes, Int32sl, Int32ul, Struct
3+
from construct import Bytes, Int32sl, Int32ul, Int64sl, Struct
44
from solana.publickey import PublicKey
55
from solana.system_program import SYS_PROGRAM_ID
6+
from solana.sysvar import SYSVAR_CLOCK_PUBKEY
67
from solana.transaction import AccountMeta, TransactionInstruction
78

89
from program_admin.types import ReferenceAuthorityPermissions
@@ -16,6 +17,8 @@
1617
COMMAND_ADD_PRICE = 4
1718
COMMAND_ADD_PUBLISHER = 5
1819
COMMAND_DEL_PUBLISHER = 6
20+
COMMAND_UPD_PRICE = 7
21+
COMMAND_INIT_PRICE = 9
1922
COMMAND_MIN_PUBLISHERS = 12
2023
COMMAND_RESIZE_PRICE_ACCOUNT = 14
2124
COMMAND_DEL_PRICE = 15
@@ -297,6 +300,79 @@ def toggle_publisher(
297300
)
298301

299302

303+
def init_price(
304+
program_key: PublicKey,
305+
funding_key: PublicKey,
306+
price_account_key: PublicKey,
307+
) -> TransactionInstruction:
308+
layout = Struct(
309+
"version" / Int32ul, "command" / Int32sl, "exponent" / Int32sl, "type" / Int32ul
310+
)
311+
data = layout.build(
312+
dict(
313+
version=PROGRAM_VERSION,
314+
command=COMMAND_INIT_PRICE,
315+
exponent=8,
316+
type=PRICE_TYPE_PRICE,
317+
)
318+
)
319+
320+
permissions_account = get_permissions_account(
321+
program_key, AUTHORITY_PERMISSIONS_PDA_SEED
322+
)
323+
324+
return TransactionInstruction(
325+
data=data,
326+
keys=[
327+
AccountMeta(pubkey=funding_key, is_signer=True, is_writable=True),
328+
AccountMeta(pubkey=price_account_key, is_signer=True, is_writable=True),
329+
AccountMeta(pubkey=permissions_account, is_signer=False, is_writable=True),
330+
],
331+
program_id=program_key,
332+
)
333+
334+
335+
def upd_price(
336+
program_key: PublicKey,
337+
funding_key: PublicKey,
338+
price_account_key: PublicKey,
339+
status: int,
340+
price: int,
341+
confidence: int,
342+
publish_slot: int,
343+
) -> TransactionInstruction:
344+
layout = Struct(
345+
"version" / Int32ul,
346+
"command" / Int32sl,
347+
"status" / Int32sl,
348+
"unused" / Int32sl,
349+
"price" / Int64sl,
350+
"confidence" / Int64sl,
351+
"publish_slot" / Int64sl,
352+
)
353+
data = layout.build(
354+
dict(
355+
version=PROGRAM_VERSION,
356+
command=COMMAND_UPD_PRICE,
357+
unused=0,
358+
status=status,
359+
price=price,
360+
confidence=confidence,
361+
publish_slot=publish_slot,
362+
)
363+
)
364+
365+
return TransactionInstruction(
366+
data=data,
367+
keys=[
368+
AccountMeta(pubkey=funding_key, is_signer=True, is_writable=True),
369+
AccountMeta(pubkey=price_account_key, is_signer=False, is_writable=True),
370+
AccountMeta(pubkey=SYSVAR_CLOCK_PUBKEY, is_signer=False, is_writable=False),
371+
],
372+
program_id=program_key,
373+
)
374+
375+
300376
def upd_permissions(
301377
program_key: PublicKey,
302378
upgrade_authority: PublicKey,

program_admin/keys.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def load_keypair(
3939
return Keypair.from_secret_key(data)
4040
else:
4141
file_path = Path(key_dir) / f"{label_or_pubkey}.json"
42-
4342
if not file_path.exists():
4443
if generate:
4544
return generate_keypair(label_or_pubkey, key_dir)

program_admin/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
ReferencePermissions,
1515
)
1616

17-
MAPPING_ACCOUNT_SIZE = 20536 # https://github.com/pyth-network/pyth-client/blob/b49f73afe32ce8685a3d05e32d8f3bb51909b061/program/src/oracle/oracle.h#L88
18-
MAPPING_ACCOUNT_PRODUCT_LIMIT = 640
17+
MAPPING_ACCOUNT_SIZE = 160056 # https://github.com/pyth-network/pyth-client/blob/main/program/c/src/oracle/oracle.h#L120
18+
MAPPING_ACCOUNT_PRODUCT_LIMIT = 5000
1919
PRICE_ACCOUNT_V1_SIZE = 3312
2020
PRICE_ACCOUNT_V2_SIZE = 12576
2121
PRICE_V1_COMP_COUNT = 32

0 commit comments

Comments
 (0)