Pyth NetworkのAccount調査
Solanaで完結した状態で各価格情報を欲しかったのでその調査メモ
Accountデータの構造
詳細は上記を参照すること。
AccountデータはFsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH
のプログラムで作られるデータであり、getProgramAccounts
で一括取得が可能。ただし、データ量が大きいため専用のノードは必要になる。
Mappingデータ
ProductデータへのN件の参照(Pubkey)を持つ構造。
Mapping → Mappingの連結リスト構造を持ち、Mappingの持つProductデータへの参照が溢れたら次のMappingを作りリストに追加する。
Accountはbytemuckでバイト化されており、client側を見て分かる通りstruct構造そのままの形になっている。
保存されるバイトはLE(リトルエンディアン)なのに注意
Productデータ
通貨のペア情報を持ち、1件のPriceデータの参照(Pubkey)を持つ構造。
ペア情報はPROD_ATTR_SIZE
の長さの動的なKey-Valueであり、KeyとValueそれぞれの先頭バイトに長さが入っている。
プログラム/クライアント側の型定義を見て分かる通り、このペア情報は型がなく何が入るかは不明。(というほどでもないけど、KVの追加、削除が起こり得るので信用はできない)
この動的な性質からgetProgramAccounts
のfilter
などで特定の通貨ペアの情報だけを取得するなどはできず、全ての情報を取得する必要がある。Hermes経由なら取得できるかもしれないが興味ないので調べていない。
Priceデータ
通貨ペアの価格情報を持つ構造。
pyth-sdk-rsとpyth-client-jsで微妙に型定義が違いそうに見える。
Price Feed ID一覧
Account Address一覧
getProgramAccountsで絞り込み付きで取得する参考実装
const u32 = (n: number) => {
const buffer = new ArrayBuffer(4);
const dataView = new DataView(buffer);
dataView.setUint32(0, n, true);
const array = new Uint8Array(buffer);
return array
};
const connection = useConnection();
const accounts = await connection.getProgramAccounts(new PublicKey("FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"), {
filters: [
{
memcmp: {
offset: 0,
bytes: bs58.encode(u32(Magic)),
},
},
{
memcmp: {
offset: 4,
bytes: bs58.encode(u32(Version2)),
},
},
{
memcmp: {
offset: 8,
bytes: bs58.encode(u32(AccountType.Product)),
},
}
]
});
accounts.forEach(({account, pubkey}) => {
const product = parseProductData(account.data);
console.log('pubkey', pubkey.toString());
console.log('product', product);
});
3つ目のmemcmp
の値を変える、parseProductData
を対応するparseに変更することで他のデータも取得できる。
Discussion