fix(learning-examples): repair crashing listeners and decoders, prune obsolete paths, unify naming (#181)

Audited every script in learning-examples/ against mainnet.

Broken — found by running them, all invisible offline:

- listen_geyser.py crashed with IndexError after ~11 coins: it never resolved
  v0 address-lookup-table accounts, which geyser reports in
  meta.loaded_writable_addresses / loaded_readonly_addresses. Resolving them
  removes the crash and brings detections level with the WebSocket listeners,
  35 coins each per 150 s.
- compare_listeners.py logged 13,090,862 error lines / 888 MB in 150 s and never
  printed its own 30-second report: the inner recv() loop caught ConnectionClosed
  in a broad handler that only logged, so every following recv() raised at once
  and the outer reconnect handler was unreachable. Now 12 KB and exit 0. Same
  shape fixed in compare_migration_listeners.py, listen_blocksubscribe.py and
  extract_blocksubscribe_transactions.py; the last two also gained the reconnect
  loop their siblings already had.
- decode_from_gettransaction.py matched instructions on account count instead of
  discriminator, reporting a real 19-account create_v2 as claim_cashback with
  every account under the wrong name. It also walked only top-level
  instructions, and in 40 consecutive pump.fun transactions there was 1
  top-level pump instruction against 8 inner ones.
- decode_from_blocksubscribe.py crashed on every real create_v2: on chain the
  trailing args are variable length, 0001 in one tx and 00 in another, so
  is_cashback_enabled can be absent entirely.
- poll_bonding_curve_progress.py polled a hardcoded dead mint and took no argv.

Obsolete:

- Delete listen_blocksubscribe_old_raydium.py. Seven minutes on mainnet produced
  0 initialize2 events while the wrapper listener caught 3 real migrations.
- Delete the duplicate geyser stubs and protos under listen-new-tokens/. The
  protos were byte-identical to src/geyser/proto and the stubs had drifted; both
  geyser examples now import src.geyser.generated.
- Recapture all four fixtures. The old ones were from Aug 2024 and included a
  49-byte pre-creator bonding curve.

Behind the protocol:

- fetch_price.py, get_bonding_curve_status.py, poll_bonding_curve_progress.py
  and decode_from_getaccountinfo.py never read quote_mint and scaled by a
  hardcoded 1e9. Against a live USDC-paired curve the price was off by 1000x.
- get_pumpswap_pools.py stopped parsing at coin_creator and missed the i128
  virtual_quote_reserves. Live pools carry 17.5845 SOL of them, which
  under-prices by 3.5-23.9% when ignored.

Duplication and naming:

- Merge manual_buy_cu_optimized.py into manual_buy.py --cu-optimized. The
  deleted file's docstring said 512 KB while its code used 16 MB; simulation
  confirms 512 KB and 4 MB both fail MaxLoadedAccountsDataSizeExceeded on
  Token-2022 mints, so 16 MB is the correct value.
- Merge listen_logsubscribe_abc.py into listen_logsubscribe.py. Its ATA
  derivation hardcoded the legacy token program, so every Associated BC it
  printed for a Token2022 coin was an address that does not exist on chain.
  Fixed on merge and cross-checked 59/59 against on-chain accounts.
- Remove 19 dead symbols. BREAKING_FEE_RECIPIENTS is still live in the PumpSwap
  scripts and stays there.
- Normalize naming: kebab-case directories, RPC method names as one lowercase
  token, scripts verb-first. Rules documented in CLAUDE.md.

get_graduating_tokens.py is knowingly left broken: getProgramAccounts over the
whole pump program is now rejected by providers and it needs a
getProgramAccountsV2 rewrite, which belongs in its own PR.

Verified: both offline gates pass, all 41 examples parse, every read-only script
exercised on mainnet against SOL- and USDC-paired coins, no new ruff findings
(427 -> 413). No script that spends real funds was run.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Anton Sauchyk
2026-07-29 15:26:26 +02:00
committed by GitHub
parent 5c1fb7eb28
commit a33f4fd035
44 changed files with 3255 additions and 5022 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
trades/*
# written by learning-examples/blockSubscribe_extract_transactions.py
blockSubscribe-transactions/
# written by learning-examples/extract_blocksubscribe_transactions.py
blocksubscribe-transactions/
.vscode
.pylintrc
+79 -5
View File
@@ -38,6 +38,23 @@ registry in `platforms/__init__.py`. Listeners and the trader are
platform-agnostic (`Universal*`); anything platform-shaped belongs under
`platforms/<name>/`.
### Naming inside `learning-examples/`
- **Directories are kebab-case** (`bonding-curve-progress`, `listen-new-tokens`,
`copy-trading`). A single-token product name stays one word (`pumpswap`).
- **Files are snake_case, verb first** — `fetch_price.py`, `decode_from_*.py`,
`extract_blocksubscribe_transactions.py`, `verify_*.py`, `simulate_*.py`.
Exceptions are the shared helper modules `pump_v2.py` and `tx_status.py`, which
are libraries rather than runnable scripts.
- **RPC and service names are lowercased into one token**, never camelCase:
`blocksubscribe`, `logsubscribe`, `programsubscribe`, `getaccountinfo`,
`gettransaction`, `pumpportal`. So `decode_from_gettransaction.py`, not
`decode_from_getTransaction.py`.
- Fixtures are `raw_<what>_from_<method>.json` next to the script that reads
them, under the same rules.
- `live_*` marks a script that spends real funds; `simulate_*` and `verify_*`
never do.
## Commands
```bash
@@ -67,8 +84,11 @@ commented-out code). Type-hint public functions, Google-style docstrings, and
Python 3.11+ (`requires-python = ">=3.11"`, matching ruff's target). Runtime
deps are declared in `[project.dependencies]`; `ruff` and `grpcio-tools` live in
`[dependency-groups] dev`, which `uv sync` installs by default. `grpcio-tools`
is protoc — needed only to regenerate the `geyser_pb2` stubs from `proto/`, never
at runtime.
is protoc — needed only to regenerate the `geyser_pb2` stubs in
`src/geyser/generated/` from `src/geyser/proto/`, never at runtime. That is the
**only** copy: the geyser examples reach it by putting the repo root on
`sys.path` and importing `src.geyser.generated`. Don't add a second copy under
`learning-examples/` — the last one drifted out of sync with the protos.
### Verifying pump.fun v2 trade instructions
@@ -121,6 +141,47 @@ with `BuybackFeeRecipientMissing` (6062) printed as confirmed buys.
and `str()` on it is empty, so the caller logs a blank reason. A slow
`getAccountInfo` is enough to take down a whole listener run this way.
### Listener and decoder pitfalls
Each of these was a live bug in `learning-examples/`, all of them invisible
offline and only visible after a couple of minutes against mainnet.
- **A `while True: recv()` loop must break out on `websockets.ConnectionClosed`.**
Catching it in a broad `except Exception` that only logs makes the next `recv()`
raise immediately, forever: `compare_listeners.py` produced **13,090,862 error
lines / 888 MB in 150 s** and never reached its own 30-second report. The outer
reconnect handler with its `sleep` is unreachable in that shape. A narrow
`except TimeoutError` or `except json.JSONDecodeError` is fine to swallow —
those are per-message, not per-connection.
- **Resolve v0 lookup-table accounts before indexing them.** An instruction's
account indices can point past `message.account_keys` into the address lookup
table, which geyser reports in `meta.loaded_writable_addresses` then
`loaded_readonly_addresses` (that order). Ignoring them crashed the geyser
example with `IndexError` after ~11 coins in 150 s; resolving them removed the
crash and brought its detection count level with the WebSocket listeners
(35 coins each over the same window).
- **Identify an instruction by its 8-byte discriminator, never by account count.**
Several pump.fun instructions share a count, so counting mislabels them and
then prints every account under the wrong name — a real 19-account `create_v2`
was reported as `claim_cashback`. Note `buy_exact_sol_in` is also 18 accounts
on chain, same as legacy `buy`.
- **Walk `meta.innerInstructions`, not just `message.instructions`.** Most trades
reach the program as a CPI from a router or aggregator: in 40 consecutive
pump.fun transactions there was **1 top-level** pump instruction against
**8 inner** ones. Anchor's event-CPI prefix (`e445a52e51cb9a1d`) accounts for a
good share of the inner instructions; the event's own discriminator follows it.
- **`getProgramAccounts` over the whole pump program is rejected** by current
providers: *"Too many accounts requested (10000001 pubkeys) … use
getProgramAccountsV2 with pagination"*. It still works against pump-amm, which
is small enough. `bonding-curve-progress/get_graduating_tokens.py` is knowingly
broken on this and needs the V2 pagination rewrite.
- **`SetLoadedAccountsDataSizeLimit` must stay generous: 16 MB, not 512 KB.**
Verified by simulation on a Token-2022 mint with extensions — 512 KB and 4 MB
both fail `MaxLoadedAccountsDataSizeExceeded` with `unitsConsumed=0` (never
executed), while 16 MB reaches the buy instruction and is still 4x under the
64 MB default. solders has no builder for it; encode `struct.pack("<BI", 4, n)`
against the compute-budget program.
## Pump.fun protocol notes (gotchas)
The IDLs under `idl/` are vendored verbatim from `github.com/pump-fun/pump-public-docs`
@@ -185,11 +246,24 @@ The IDLs under `idl/` are vendored verbatim from `github.com/pump-fun/pump-publi
symbol (str), uri (str), creator (pubkey), is_mayhem_mode (bool),
is_cashback_enabled (OptionBool 1B)`. `OptionBool` is a struct wrapping a single
bool — serialized as 1 byte, not 2.
- **`is_cashback_enabled` can be absent from the wire entirely.** Two mainnet
`create_v2` instructions carry `0001` and `00` after `creator`: one sends both
trailing args, the other omits the last. A decoder that reads a fixed number of
trailing bytes raises `IndexError` on roughly half of all coins. Decode
trailing args defensively and report a missing one as unset.
- `create_v2` accounts 1-16 are in the IDL; accounts **17-19 are optional
remaining accounts** (`quote_mint`, `associated_quote_bonding_curve`,
`quote_token_program`) appended only for a non-SOL quote mint. All three or
none. This is the only way to read a new coin's quote asset from the
instruction rather than the event.
`quote_token_program`). All three or none. This is the only way to read a new
coin's quote asset from the instruction rather than the event. In practice they
are appended for **SOL-paired coins too**, carrying wrapped SOL — a live
SOL-paired `create_v2` was observed with 19 accounts and account 17 = WSOL — so
do not treat a 19-account `create_v2` as proof of a non-SOL quote asset. Read
`quote_mint` off the curve instead.
- The **associated bonding curve is an ordinary ATA**, so its address depends on
which token program owns the mint: Token2022 for `create_v2` coins, SPL Token
for legacy `create`. Deriving with the wrong program returns a valid-looking
address that does not exist on chain. Verified: curve `3jJ83ND…` derives to
`Cd4iC3Jn…` under Token2022 (matches chain) and `AhNzZsBp…` under SPL Token.
- `extreme_fast_mode` skips the curve-state price fetch but still refreshes
mayhem/cashback/creator/**quote_mint** from chain, because the wrong quote mint
means spending the wrong balance entirely. Event parsers also populate
+8 -3
View File
@@ -120,16 +120,21 @@ Standalone scripts, runnable with `uv run <path>`. No bot config needed — they
| Path | What it covers |
|---|---|
| `listen-new-tokens/` | One listener per method (`logs`, `blocks`, `geyser`, `pumpportal`) plus `compare_listeners.py` to race them |
| `listen-migrations/` | Detect a token graduating from the bonding curve to PumpSwap |
| `listen-migrations/` | Detect a token graduating from the bonding curve to PumpSwap, via the migration wrapper program or new pool accounts |
| `bonding-curve-progress/` | Curve state, progress polling, and tokens close to graduating |
| `pumpswap/` | Manual buy/sell against the PumpSwap AMM, and pool discovery |
| `letsbonk-buy-sell/` | Manual exact-in / exact-out buys and sells on letsbonk.fun |
| `copytrading/` | Watch another wallet's transactions |
| `manual_buy.py`, `manual_sell.py`, `fetch_price.py` | The minimal pump.fun trade and price path |
| `copy-trading/` | Watch another wallet's transactions |
| `manual_buy.py`, `manual_sell.py`, `fetch_price.py` | The minimal pump.fun trade and price path. `manual_buy.py --cu-optimized` adds a `SetLoadedAccountsDataSizeLimit` instruction |
| `mint_and_buy_v2.py` | Create a coin and buy it in one go |
| `decode_from_*.py`, `calculate_discriminator.py` | Decoding account data, transactions, and Anchor discriminators |
| `cleanup_accounts.py` | Close leftover empty token accounts |
Most of these take the mint or curve address as the first argument, and print usage if
you leave it off. The `decode_from_*.py` scripts fall back to the saved fixtures beside
them (`raw_*.json`), which are recaptured from mainnet rather than hand-edited — a
stale fixture makes a working decoder look broken and a broken one look fine.
Two examples double as verification scripts to run after any pump.fun program upgrade:
```bash
@@ -1,274 +0,0 @@
{
"transaction": [
"AYqt4iSMLUKIiCn+roUn59P7c0BroL8VCv5X+0515tjH9d5OCez5MIQdftuWcDwEymBNZMWiqy51LDU76WpahAMBAAoTcFi8Lm3PgW7X4XZm7q8+G4Jf4IaSLzptQdkNfSFrd2kW7510gs4rvSfIQ6BD7SbUQJaGC396SVFLuDF387+XgV1pfIfVUZFTFHxe1tb+5NIGBoToM9rJFbh9akpqDSa8XwszrDDJuVPznYGftPUIqlfBd55SSEGIUQWL6ZogaoujB/IYgIAD1tGqXa268xcm661aIHELJcoHVKW8TJPIRaOJkcMpfWvPuYxyTGf253mdFudiJ5NiHvVmi0CTGjvCsU4N5V6fuoY5br/VSM/4ySAR6se3W6qbLZxqhvWhcUHXqo+wYNgpG0xNR12v92LJa9wNrOs2wBLq0S7TqUhBYfprphss/CT2/qy59h94SA3zpgqeFhalg6tebfEaQX2yAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVuD2k2Zaz0TbFWi/F1uqUYnLl/XS/ztlXSu2/W0YsAMGRm/lIRcy/+ytunLDm+e8jOW7xfcSayxDmzpAAAAABt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKkG3fbh7nWP3hhCXbzkbM3athr8TYO5DSf+vfko2KGL/Ai2qPUzOEL8dkpbTkkIfplULeP8horDFNap3dmbsYVGOoZeae4PVIDKvPZjV+TcLxjVjUXB6nSJ+zcj2Xk8cqZE+dQlVubfmlZx8g4Yr7VZS6dIqY5CCXXxzYTAYMWwb4yXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZrPE26wH8HE6IPSPItYRKtZo39mrdV8XprDtT4FnTXGT58ypqlPJGff+K9zL4EgTVmKxLEmG7xOccSwzdPrM4LwULAAUCiIoBAAsACQM83OEAAAAAAAkCAAYMAgAAAAAbtwAAAAAAEQYABQAQCQwBAA4PCQwKAgABBQMNDwcQCAQSXgAA4DIpAAAAAAAAAAAAAAAAAMGhI2gAAAAADAkBCgALAQAIDAAABgAEAAIBAQ0ADgEAAxgAZgY9EgHa6+quClnNAQIAAGjN5REAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"base64"
],
"meta": {
"err": null,
"status": {
"Ok": null
},
"fee": 1500000,
"preBalances": [
2005440908,
0,
4696550893895,
13463471281,
377180764,
0,
57019670,
4441807831495,
2039280,
1,
1141440,
1,
934087680,
1141440,
1141440,
290898417,
1461600,
731913600,
137104014
],
"postBalances": [
1686928628,
0,
4696553593895,
13760771281,
377329414,
2039280,
69019670,
4441810655845,
2039280,
1,
1141440,
1,
934087680,
1141440,
1141440,
290898417,
1461600,
731913600,
137104014
],
"innerInstructions": [
{
"index": 3,
"instructions": [
{
"programIdIndex": 12,
"accounts": [
16
],
"data": "84eT",
"stackHeight": 2
},
{
"programIdIndex": 9,
"accounts": [
0,
5
],
"data": "11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL",
"stackHeight": 2
},
{
"programIdIndex": 12,
"accounts": [
5
],
"data": "P",
"stackHeight": 2
},
{
"programIdIndex": 12,
"accounts": [
5,
16
],
"data": "6UhFp3r3cKbQWwHQYPuDqtb5CAdjXP45vy8Z8DQwgGRSQ",
"stackHeight": 2
}
]
},
{
"index": 4,
"instructions": [
{
"programIdIndex": 9,
"accounts": [
0,
2
],
"data": "3Bxs4eMeB358Cb5h",
"stackHeight": 2
},
{
"programIdIndex": 10,
"accounts": [
15,
7,
16,
3,
8,
5,
0,
9,
12,
4,
18,
10
],
"data": "AJTQ2h9DXrBo1MiibpgfkQHmpSKmNnQgP",
"stackHeight": 2
},
{
"programIdIndex": 12,
"accounts": [
8,
5,
3
],
"data": "3SpdELLWnXkK",
"stackHeight": 3
},
{
"programIdIndex": 9,
"accounts": [
0,
4
],
"data": "3Bxs4VLT5WjmR4oh",
"stackHeight": 3
},
{
"programIdIndex": 9,
"accounts": [
0,
3
],
"data": "3Bxs46HNXQ8jq79R",
"stackHeight": 3
},
{
"programIdIndex": 9,
"accounts": [
0,
7
],
"data": "3Bxs4TJNecvxKcVV",
"stackHeight": 3
},
{
"programIdIndex": 10,
"accounts": [
18
],
"data": "2zjR1PvPvgqdhPdZLxuWCL7GiE5h1bKn4ziAcRd2FBFaC3kf2EYsG31a2aigsk9mgAfieqmo561JLMNk2uSKF65QKzv64GtLAULg9zNrDFfLe7DrBDcgQBwTwRqqLVkWBrksYNBFeyBeSPwcQe5DNEEqwfSowV6pk2t9QuN6JDSpxRegP8ekTV5zwc3ytD2hSo7wu9s4ynRb5ccHwRaoy9Lzm7M66sikRLa74mXuFzdjzGuq454PDDP8eqUSWxt1ddTchsUvqsAnv92vMN2BLu7XZ3UcTv96fz8KrV93qqHSsNwfKdCsY7QMwxbCE7R",
"stackHeight": 3
}
]
}
],
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]",
"Program log: Create",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 93653 compute units",
"Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeImmutableOwner",
"Program log: Please upgrade to SPL Token 2022 for immutable owner support",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 87066 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeAccount3",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 83184 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 21837 of 100550 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program b1oomGGqPKGD6errbyfbVMBuzSC8WtAAYo8MwNafWW1 invoke [1]",
"Program log: Powered by https://telegram.bloombot.app",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program log: Instruction: Buy",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 49415 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program data: vdt/007mYe5E+dQlVubfmlZx8g4Yr7VZS6dIqY5CCXXxzYTAYMWwbyBwuBEAAAAAT+SenZMEAAABcFi8Lm3PgW7X4XZm7q8+G4Jf4IaSLzptQdkNfSFrd2m6oSNoAAAAALHaOjAKAAAAgP3BigudAgCxLhc0AwAAAIBlrz56ngEA16qPsGDYKRtMTUddr/diyWvcDazrNsAS6tEu06lIQWFfAAAAAAAAAJ4YKwAAAAAAkJajVbvLxqgCZ/z53+NIXoh5GMXQLRXjoGjmO6GR/6UFAAAAAAAAAKpEAgAAAAAA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [3]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2006 of 33261 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 40072 of 70491 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program b1oomGGqPKGD6errbyfbVMBuzSC8WtAAYo8MwNafWW1 consumed 48895 of 78713 compute units",
"Program b1oomGGqPKGD6errbyfbVMBuzSC8WtAAYo8MwNafWW1 success"
],
"preTokenBalances": [
{
"accountIndex": 8,
"mint": "5eFg3giaX2c3RydHvx1S3yEKpYjBuwtLUsmbAAG9pump",
"uiTokenAmount": {
"uiAmount": 667654902.731215,
"decimals": 6,
"amount": "667654902731215",
"uiAmountString": "667654902.731215"
},
"owner": "7Q1e26aB8kpyamjKPCt5oD73b2Hx7nAEjAMUwfHmZy7G",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
],
"postTokenBalances": [
{
"accountIndex": 5,
"mint": "5eFg3giaX2c3RydHvx1S3yEKpYjBuwtLUsmbAAG9pump",
"uiTokenAmount": {
"uiAmount": 5032051.139663,
"decimals": 6,
"amount": "5032051139663",
"uiAmountString": "5032051.139663"
},
"owner": "8ZZ97eWp2k8gfoK2Jk2WQcdofk9hyJpEGDPGiqFryH1S",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 8,
"mint": "5eFg3giaX2c3RydHvx1S3yEKpYjBuwtLUsmbAAG9pump",
"uiTokenAmount": {
"uiAmount": 662622851.591552,
"decimals": 6,
"amount": "662622851591552",
"uiAmountString": "662622851.591552"
},
"owner": "7Q1e26aB8kpyamjKPCt5oD73b2Hx7nAEjAMUwfHmZy7G",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
],
"rewards": null,
"loadedAddresses": {
"writable": [],
"readonly": []
},
"computeUnitsConsumed": 71182
},
"version": "legacy"
}
@@ -0,0 +1,481 @@
{
"transaction": [
"AtN2HVLNE5opUmngSFetR7lSQu7SZ8CssT5BsuqzkfAojSt18r380T01phxmbrBeKyLv/biulLSRd5eJaYo5HwQrVF3qv963GFTiJcxq4TYHech9QJrYenLiDSQjpOIMjxyoqV81Xx0qKxZEEb+PMn0E3WDy7W7zUp4V3mWI5JIPgAIACRlKQnktFp8fJjipwOpWq+KMs6dxuCT7xE1ftg2m5Ok4dmEkzaw3g7FEdwckLSh+VEI69Gdj+i5xuPZtldUKMuN/BSrl16fapySm6rCnKVSRhVrUoGcWYGdMTgNFWYA9ZaMMNf+pBVqOVo2o97wHVhUnTPHJLKQfQACcUWqkFMJ8cEJDhOG2exOSEqFEYkIFmA7a6IBpWg1QX7Ma05yqMBbGQ55lEMA9ZfrZMeidBL4Ltw1Rlx9RxBX7NEwH20GfISJWguZwRf+BTo08nZUIE1WYnLa7Vc4fD5WvzZwdQsj/YG0+2tkv8bg4waXv2CUBhL8mBfSDgMle1qOWj41yPavDb5q0pPGVjcCpyUw/tywHmVhD7aSF46JPEMaTmfgZlA9ywCps9gXMwprJyuPYimFyhbKnNpz8Jr5L+L5eo+IYNIFJhkVt+i1i+C6+DWShYUbqdjWAHXlzbyrS1zIKfxGqootf0mq0eaapzGy/awsj62GIWjceASCsqRO+7z0TiniyAz6mHIpGfJpPWgEvmMSP2ryJuB99oUO53ulKEcHgi+AEyHzrmPpc5H+AOAb9LHlF0pUklZrsAN7ZeBTzj3hG+gkRpUhjQS1jH04HhwMpbANfDRMzoNnIg41ztxD+bi38dEArL/cxv8VWJEJxTeLXWy2Il8/jfL4srbpuQyN/RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK2uon2zxvPQTlzwogKfA+M5jwhTle/v7xcfxkr4F0EBVuD2k2Zaz0TbFWi/F1uqUYnLl/XS/ztlXSu2/W0YsAbFwc5jjSVn0mRosF65UdGijcxuEjSCtcZ1FJdw5ivyBt324e51j94YQl285GzN2rYa/E2DuQ0n/r35KNihi/w6hl5p7g9UgMq89mNX5NwvGNWNRcHqdIn7NyPZeTxypoyXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZmvId+FScLqAFyZZGD98s4aLo3WKmwZtOLpMYGA8Q/jes8TbrAfwcTog9I8i1hEq1mjf2at1XxemsO1PgWdNcZEVspp6AJZZQmzmcHbqPffgZh4ufjf2eSNKlcWhS9VN9AxIQARMKDxUAEBQWAhELBgQYEpEB1pBM7F+LMbQGAAAATllYT1JBBgAAAE5ZWE9SQVAAAABodHRwczovL2lwZnMuaW8vaXBmcy9iYWZrcmVpZ3V0dGlpdWZjbDI0eHRuemd4dnZvbmg3YjUzNWEzZGg2dHhyamd3YXgyaHllY3N5ajQ2aUpCeS0Wnx8mOKnA6lar4oyzp3G4JPvETV+2Dabk6Th2ABYGAAkAARAUAQESEhUNAQoPCQAQFAcYEg4MCAMXBRhmBj0SAdrr6oOjd6YzAwAAAPNvBgAAAAAA",
"base64"
],
"meta": {
"err": null,
"status": {
"Ok": null
},
"fee": 10000,
"preBalances": [
3490250000,
0,
11149834,
6046720,
0,
1283540085,
0,
0,
37290293,
0,
0,
46722001573954,
0,
9339816446339,
17016138,
0,
1,
3104160,
8502112342,
1020235880,
70128637,
4089612038,
3388605256,
0,
168261371
],
"postBalances": [
3377936405,
3744480,
11149834,
6046720,
0,
1284009148,
0,
1187131,
37290293,
2074080,
100441298,
46722001573954,
1844400,
9339816915402,
17016138,
2074080,
1,
3104160,
8502112342,
1020235880,
70128637,
4089612038,
3388605256,
0,
168261371
],
"innerInstructions": [
{
"index": 0,
"instructions": [
{
"programIdIndex": 16,
"accounts": [
0,
1
],
"data": "11119EX7m7cQ1gzrTFmsb4bvG4q3n4AV3ZE5kapx4y1d1P2PRtFmcfWj9wWQ7kkadAvgLT",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
1
],
"data": "GC3i2jSx8awwe9xBfbR9LBTrzgFPUE9b56kGnez3cWMeYXGJnPmgtY5rED1m4XsF3X2uSDMFJ4bev8UjGefVNKbRM8",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
1
],
"data": "2zt6UCCHp66bJGRS4G7bTsjdxFh6FQ9sBEyRfGyPQKxYisAw",
"stackHeight": 2
},
{
"programIdIndex": 16,
"accounts": [
0,
10
],
"data": "11116K5vvUmhADFUYqW7YpVsZyjKkmyUr9Lhhg2Ww93d5ByeoqECM3GbgJVXShFbqLT6Yw",
"stackHeight": 2
},
{
"programIdIndex": 22,
"accounts": [
0,
15,
10,
1,
16,
20
],
"data": "1",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
1
],
"data": "84eT",
"stackHeight": 3
},
{
"programIdIndex": 16,
"accounts": [
0,
15
],
"data": "11119ExAoTptm6xKUTUcw2V69MKmyEdDmRins3j3bK43o9nHeiYUtSiaT9pc292PhNQvxj",
"stackHeight": 3
},
{
"programIdIndex": 20,
"accounts": [
15
],
"data": "P",
"stackHeight": 3
},
{
"programIdIndex": 20,
"accounts": [
15,
1
],
"data": "6VqPHofMMfuQJAEzZzrsRAXUWdRq24z8HgDFhn2YiSXg5",
"stackHeight": 3
},
{
"programIdIndex": 16,
"accounts": [
0,
1
],
"data": "3Bxs3zyNSVVdrTVR",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
1,
19,
1,
19
],
"data": "gbNssdUdrb5FEGwgyBjJC33hzHi7xbozKF4q9fv3KVnZZbJ1tVcJ2ngaKcLfZzLmXdi9suAGYxA7tJa2dP5Z9EXNKmWbWw5HkvJd7MVpxraVGy12dWPgmzYCnYcoe5vJjxDTmv4vVEHrop9nAEM75C6Ve",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
1,
19
],
"data": "BjBG9fDQbu1raSNbBZQYubkmLijGDjgXJHpedBBGGrFrgSFFPaBAwnF",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
1,
15,
19
],
"data": "6ApXSNCamGdm",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
1,
19
],
"data": "31tb",
"stackHeight": 2
},
{
"programIdIndex": 18,
"accounts": [
24
],
"data": "4yiadJPqQG9uR3FVF217CVcHf3EYXokPGmBLocJxofbVKdZCq5CYegE5y5jdZjmYkQPm6knX6BWfEJVL6jxVN1xo1YMHCSUcwMhF1VDHgCQJAzhBUN2SKFfrDfZZprQZXnNeXrEX6kzFFNNHgZFWDSgzsDUbdE5tKi8kJjeuZ3P8jdkeB7g5cAdWKtvxLA8Z5k8VeXh8FNp5p6fxSLeNQLNTcRZRcvdsv1sUK8bF4ozUJXk55QrUQoU822HUdCe9AVEg2xY75vTVJUaBB2eBoC2YY9vmUcxkdWk3vojUVCCH3bdqALTDffhuwNstu7zFJRTbFA7WubupHct1qnxdeEtM4SfsxBReT7GqCxD1tZYkWmV8cGzP4sKkqivqPijMUrnnxkBoY5MijwoZjCLVkB4K8qYrf97zrYA3T49ipoXjpv6U4nHCatKs5DBNPA5CRwWBQJncVnE2H8UxWZzx8P1ZyXv1FP3jKN2sXzo449RUVPV",
"stackHeight": 2
}
]
},
{
"index": 1,
"instructions": [
{
"programIdIndex": 20,
"accounts": [
1
],
"data": "84eT",
"stackHeight": 2
},
{
"programIdIndex": 16,
"accounts": [
0,
9
],
"data": "11119ExAoTptm6xKUTUcw2V69MKmyEdDmRins3j3bK43o9nHeiYUtSiaT9pc292PhNQvxj",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
9
],
"data": "P",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
9,
1
],
"data": "6S8adZGM4f3gfDTREGfkUZkdqtkpDDBMjf9SeEQBuYaQ5",
"stackHeight": 2
}
]
},
{
"index": 2,
"instructions": [
{
"programIdIndex": 16,
"accounts": [
0,
12
],
"data": "11117Tknd8jUGTWe4i7BMwMh7mt2ibJWfGb66m7z4y7euUA7hvsZ7X6HejbWyRL9L9YtX1",
"stackHeight": 2
},
{
"programIdIndex": 3,
"accounts": [
8,
18
],
"data": "6E5CZKNB2G93HVu9Syn6kkEUE5ZYBEkjrAWuGVNiSRvGq99",
"stackHeight": 2
},
{
"programIdIndex": 20,
"accounts": [
15,
1,
9,
10
],
"data": "hn8daBDCC8gkd",
"stackHeight": 2
},
{
"programIdIndex": 16,
"accounts": [
0,
7
],
"data": "3Bxs3zxRSzKmp61u",
"stackHeight": 2
},
{
"programIdIndex": 16,
"accounts": [
0,
7
],
"data": "3Bxs4Ap5JCUQX88o",
"stackHeight": 2
},
{
"programIdIndex": 16,
"accounts": [
0,
10
],
"data": "3Bxs4C2nMw6T8d83",
"stackHeight": 2
},
{
"programIdIndex": 16,
"accounts": [
0,
5
],
"data": "3Bxs4CkxzAs8qffV",
"stackHeight": 2
},
{
"programIdIndex": 16,
"accounts": [
0,
13
],
"data": "3Bxs4CkxzAs8qffV",
"stackHeight": 2
},
{
"programIdIndex": 18,
"accounts": [
24
],
"data": "T2jLjveMmM4gJ1fdXs3mfxY8kBWUQACBFmi2dJ8xHBEAbW2nH477LPqiGr2ayJz4FXgjjWBDKS6HwE8t3d6u499nNkzEJJNQXwEUweGnq91fy1vVX31TYSCU3FYa52enUzYUy8REpA7k1mg9uKQFskuMQuAX4k4aa5mv6PJvkfKbfu2oNo1k4Miej9ziFJzbPcxbE1uW5wyV4WiRUmHk4XJ7jPSJodPtB8weghgo4GnrU6VSV67HeJ1VmP7ExfkmvvN5qABdYwYm9eKbsEp48oJrz7nFgjrg5Hmp9sn5YfqYLs4xwCddTtuoFJdad7jn2BTJgkqNSZ3Jueps3bwrNdVK2KK54wbMkovfUaBuKX12br61rM8uZjYYb6RT7BeKZbtCNYqa6QKTsTZeSiq2e1gYCn6R15usAcPgX9azUocZreapm6oGByRKmFZCKFuMP7YjHw6tM5oT7Lm79oVUwN5d7LMMmHdXwcoHYiygMDmPiiLmznZd",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: CreateV2",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: MetadataPointerInstruction::Initialize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 925 of 587718 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: InitializeMint2",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1772 of 585130 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]",
"Program log: Create",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1447 of 563891 compute units",
"Program return: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb qgAAAAAAAAA=",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]",
"Program log: Instruction: InitializeImmutableOwner",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 736 of 557622 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]",
"Program log: Instruction: InitializeAccount3",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1969 of 554550 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 16947 of 569224 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: TokenMetadataInstruction: Initialize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 3514 of 529205 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: TokenMetadataInstruction: UpdateAuthority",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 3871 of 523441 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: MintTo",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1714 of 517396 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: SetAuthority",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1044 of 513743 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program data: G3KpTd7rY3YGAAAATllYT1JBBgAAAE5ZWE9SQVAAAABodHRwczovL2lwZnMuaW8vaXBmcy9iYWZrcmVpZ3V0dGlpdWZjbDI0eHRuemd4dnZvbmg3YjUzNWEzZGg2dHhyamd3YXgyaHllY3N5ajQ2aWEkzaw3g7FEdwckLSh+VEI69Gdj+i5xuPZtldUKMuN/gUmGRW36LWL4Lr4NZKFhRup2NYAdeXNvKtLXMgp/EapKQnktFp8fJjipwOpWq+KMs6dxuCT7xE1ftg2m5Ok4dkpCeS0Wnx8mOKnA6lar4oyzp3G4JPvETV+2Dabk6Th23/NpagAAAAAAENhH488DAACsI/wGAAAAAHjF+1HRAgAAgMakfo0DAAbd9uHudY/eGEJdvORszdq2GvxNg7kNJ/69+SjYoYv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsI/wGAAAA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2125 of 506400 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 96852 of 600000 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]",
"Program log: CreateIdempotent",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1523 of 497888 compute units",
"Program return: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb qgAAAAAAAAA=",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: InitializeImmutableOwner",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 736 of 491543 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: InitializeAccount3",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2153 of 488474 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 17110 of 503148 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Buy",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ invoke [2]",
"Program log: Instruction: GetFees",
"Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ consumed 3302 of 446130 compute units",
"Program return: pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ AAAAAAAAAABfAAAAAAAAAB4AAAAAAAAA",
"Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: TransferChecked",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2562 of 439352 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program data: vdt/007mYe5hJM2sN4OxRHcHJC0oflRCOvRnY/oucbj2bZXVCjLjf0LO4gUAAAAAg6N3pjMDAAABSkJ5LRafHyY4qcDqVqvijLOncbgk+8RNX7YNpuTpOHbf82lqAAAAAEJ6BgIHAAAAfWxgoa/MAwBCzuIFAAAAAH3UTVUezgIA4ATIfOuY+lzkf4A4Bv0seUXSlSSVmuwA3tl4FPOPeEZfAAAAAAAAAI5QDgAAAAAASkJ5LRafHyY4qcDqVqvijLOncbgk+8RNX7YNpuTpOHYeAAAAAAAAADuFBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAGJ1eQAAAAAAAAAAAAAAAAAAAAAAiBMAAAAAAABHKAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAELO4gUAAAAAQnoGAgcAAABCzuIFAAAAAA==",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2125 of 418049 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 71995 of 486038 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"
],
"preTokenBalances": [],
"postTokenBalances": [
{
"accountIndex": 9,
"mint": "7YD6ZHb39jGb33ki2iFd7kHK11yMkSFCc9kvjJscpump",
"uiTokenAmount": {
"uiAmount": 3520371.073923,
"decimals": 6,
"amount": "3520371073923",
"uiAmountString": "3520371.073923"
},
"owner": "5zsxd4pGNCQpwyKiBWZ95nCTPsEPoS62xEGnjpW6FRy7",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
},
{
"accountIndex": 15,
"mint": "7YD6ZHb39jGb33ki2iFd7kHK11yMkSFCc9kvjJscpump",
"uiTokenAmount": {
"uiAmount": 996479628.926077,
"decimals": 6,
"amount": "996479628926077",
"uiAmountString": "996479628.926077"
},
"owner": "9hgcsTpZP48Ttku3uhg5gZ388YFCfErayJ5rHSru9PF7",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
}
],
"rewards": null,
"loadedAddresses": {
"writable": [],
"readonly": []
},
"computeUnitsConsumed": 185957,
"costUnits": 195591
},
"version": 0
}
@@ -27,6 +27,36 @@ PUMP_PROGRAM_ID: Final[Pubkey] = Pubkey.from_string(
)
EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 6966180631402821399)
# Shortest account that still reaches quote_mint: 8 discriminator + 41 base fields
# + 32 creator + 1 mayhem + 1 cashback + 32 quote_mint.
_V5_MIN_LENGTH: Final[int] = 115
# Quote assets. `quote_mint` is all zeros on SOL-paired coins; the quote-side reserves
# are always in the quote mint's raw units (1e9 for SOL, 1e6 for USDC).
DEFAULT_QUOTE_MINT: Final[Pubkey] = Pubkey.from_bytes(bytes(32))
WSOL_MINT: Final[Pubkey] = Pubkey.from_string(
"So11111111111111111111111111111111111111112"
)
USDC_MINT: Final[Pubkey] = Pubkey.from_string(
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
)
QUOTE_DECIMALS: Final[dict[Pubkey, int]] = {WSOL_MINT: 9, USDC_MINT: 6}
QUOTE_SYMBOLS: Final[dict[Pubkey, str]] = {WSOL_MINT: "SOL", USDC_MINT: "USDC"}
def resolve_quote_asset(quote_mint: Pubkey) -> tuple[Pubkey, str, int]:
"""Resolve a curve's quote mint to its symbol and raw-unit scale.
Args:
quote_mint: The curve's raw quote_mint field
Returns:
(effective mint, display symbol, raw units per whole token)
"""
mint = WSOL_MINT if quote_mint == DEFAULT_QUOTE_MINT else quote_mint
decimals = QUOTE_DECIMALS.get(mint, 9)
return mint, QUOTE_SYMBOLS.get(mint, str(mint)), 10**decimals
class BondingCurveState:
"""
@@ -78,12 +108,29 @@ class BondingCurveState:
"is_cashback_coin" / Flag,
)
# V5: V4 + quote_mint. Live accounts are 151 bytes — this struct covers 107 of the
# 143 data bytes and the remaining 36 are reserved padding. The quote-side reserves
# are in the quote mint's raw units, so a non-SOL coin must not be scaled by 1e9.
_STRUCT_V5 = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag,
"creator" / Bytes(32),
"is_mayhem_mode" / Flag,
"is_cashback_coin" / Flag,
"quote_mint" / Bytes(32),
)
def __init__(self, data: bytes) -> None:
"""Parse bonding curve data."""
if data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
total_length = len(data)
self.quote_mint = DEFAULT_QUOTE_MINT
if total_length == 81: # V2: Creator only
parsed = self._STRUCT_V2.parse(data[8:])
@@ -98,11 +145,17 @@ class BondingCurveState:
self.creator = Pubkey.from_bytes(self.creator)
self.is_cashback_coin = False
elif total_length >= 83: # V4: Creator + mayhem + cashback
elif total_length < _V5_MIN_LENGTH: # V4: Creator + mayhem + cashback
parsed = self._STRUCT_V4.parse(data[8:])
self.__dict__.update(parsed)
self.creator = Pubkey.from_bytes(self.creator)
elif total_length >= _V5_MIN_LENGTH: # V5: + quote_mint
parsed = self._STRUCT_V5.parse(data[8:])
self.__dict__.update(parsed)
self.creator = Pubkey.from_bytes(self.creator)
self.quote_mint = Pubkey.from_bytes(self.quote_mint)
else:
raise ValueError(f"Unexpected bonding curve size: {total_length} bytes")
@@ -174,9 +227,14 @@ async def check_token_status(mint_address: str) -> None:
client, bonding_curve_address
)
quote_mint, quote_symbol, quote_unit = resolve_quote_asset(
curve_state.quote_mint
)
print("\nBonding curve status:")
print("-" * 50)
print(f"Creator: {curve_state.creator}")
print(f"Quote asset: {quote_symbol} ({quote_mint})")
print(
f"Mayhem Mode: {'✅ Enabled' if curve_state.is_mayhem_mode else '❌ Disabled'}"
)
@@ -190,11 +248,13 @@ async def check_token_status(mint_address: str) -> None:
print("\nBonding curve reserves:")
print(f"Virtual Token: {curve_state.virtual_token_reserves:,}")
print(
f"Virtual SOL: {curve_state.virtual_sol_reserves:,} lamports"
f"Virtual quote: {curve_state.virtual_sol_reserves:,} raw "
f"({curve_state.virtual_sol_reserves / quote_unit:,.6f} {quote_symbol})"
)
print(f"Real Token: {curve_state.real_token_reserves:,}")
print(
f"Real SOL: {curve_state.real_sol_reserves:,} lamports"
f"Real quote: {curve_state.real_sol_reserves:,} raw "
f"({curve_state.real_sol_reserves / quote_unit:,.6f} {quote_symbol})"
)
print(f"Total Supply: {curve_state.token_total_supply:,}")
@@ -1,11 +1,18 @@
"""
Module for tracking the progress of a bonding curve for a Pump.fun token.
It continuously polls the bonding curve state and prints updates at regular intervals.
"""Track a pump.fun bonding curve's progress toward graduation.
Usage:
uv run learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py <MINT>
Polls the curve every POLL_INTERVAL seconds. Progress is measured against
`Global.initial_real_token_reserves` read from chain rather than a hardcoded
constant, because a mayhem coin can be launched with different virtual params
(`set_mayhem_virtual_params`) and would otherwise show the wrong percentage.
"""
import asyncio
import os
import struct
import sys
from typing import Final
from dotenv import load_dotenv
@@ -16,18 +23,39 @@ load_dotenv()
# Constants
RPC_URL: Final[str] = os.getenv("SOLANA_NODE_RPC_ENDPOINT")
TOKEN_MINT: Final[str] = (
"5ZHx2GGGj87xpidVJpBqadMUutqBirhL2TqUR9T9taKc" # Replace with actual token mint address
)
PUMP_PROGRAM_ID: Final[Pubkey] = Pubkey.from_string(
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
)
LAMPORTS_PER_SOL: Final[int] = 1_000_000_000
PUMP_GLOBAL: Final[Pubkey] = Pubkey.from_string(
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"
)
TOKEN_DECIMALS: Final[int] = 6
EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack(
"<Q", 6966180631402821399
) # Pump.fun bonding curve discriminator
POLL_INTERVAL: Final[int] = 10 # Seconds between each status check
_MIN_ARGC: Final[int] = 2
# Quote assets. `quote_mint` is all zeros on SOL-paired coins, and the quote-side
# reserves are in that mint's raw units — 1e9 for SOL, 1e6 for USDC.
DEFAULT_QUOTE_MINT: Final[Pubkey] = Pubkey.from_bytes(bytes(32))
WSOL_MINT: Final[Pubkey] = Pubkey.from_string(
"So11111111111111111111111111111111111111112"
)
USDC_MINT: Final[Pubkey] = Pubkey.from_string(
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
)
QUOTE_DECIMALS: Final[dict[Pubkey, int]] = {WSOL_MINT: 9, USDC_MINT: 6}
QUOTE_SYMBOLS: Final[dict[Pubkey, str]] = {WSOL_MINT: "SOL", USDC_MINT: "USDC"}
# Data lengths excluding the 8-byte discriminator, per curve layout version.
_LEN_WITH_CREATOR: Final[int] = 73
_LEN_WITH_MAYHEM: Final[int] = 74
_LEN_WITH_CASHBACK: Final[int] = 75
_LEN_WITH_QUOTE_MINT: Final[int] = 107
# Only used if the Global account cannot be read: 1B supply less 206.9M reserved.
FALLBACK_INITIAL_REAL_TOKEN_RESERVES: Final[float] = 793_100_000.0
def get_bonding_curve_address(mint: Pubkey, program_id: Pubkey) -> Pubkey:
@@ -83,29 +111,42 @@ def parse_curve_state(data: bytes) -> dict:
# Parse common fields (present in all versions)
fields = struct.unpack_from("<QQQQQ?", data, 8)
data_length = len(data) - 8
# quote_mint decides the scale of the quote-side reserves, so read it before
# converting anything.
quote_mint = DEFAULT_QUOTE_MINT
if data_length >= _LEN_WITH_QUOTE_MINT: # Has quote_mint
quote_mint = Pubkey.from_bytes(data[83:115])
effective_quote_mint = WSOL_MINT if quote_mint == DEFAULT_QUOTE_MINT else quote_mint
quote_unit = 10 ** QUOTE_DECIMALS.get(effective_quote_mint, 9)
result = {
"virtual_token_reserves": fields[0] / 10**TOKEN_DECIMALS,
"virtual_sol_reserves": fields[1] / LAMPORTS_PER_SOL,
"virtual_quote_reserves": fields[1] / quote_unit,
"real_token_reserves": fields[2] / 10**TOKEN_DECIMALS,
"real_sol_reserves": fields[3] / LAMPORTS_PER_SOL,
"real_quote_reserves": fields[3] / quote_unit,
"token_total_supply": fields[4] / 10**TOKEN_DECIMALS,
"complete": fields[5],
"quote_mint": effective_quote_mint,
"quote_symbol": QUOTE_SYMBOLS.get(
effective_quote_mint, str(effective_quote_mint)
),
}
# Parse creator field if present
data_length = len(data) - 8
if data_length >= 73: # Has creator field
if data_length >= _LEN_WITH_CREATOR: # Has creator field
creator_bytes = data[49:81] # 8 (discriminator) + 41 (base fields) = 49
result["creator"] = Pubkey.from_bytes(creator_bytes)
# Parse is_mayhem_mode if present
if data_length >= 74: # Has mayhem mode field
if data_length >= _LEN_WITH_MAYHEM: # Has mayhem mode field
result["is_mayhem_mode"] = bool(data[81])
else:
result["is_mayhem_mode"] = False
# Parse is_cashback_coin if present (added in late-Feb 2026 cashback upgrade)
if data_length >= 75:
if data_length >= _LEN_WITH_CASHBACK:
result["is_cashback_coin"] = bool(data[82])
else:
result["is_cashback_coin"] = False
@@ -113,55 +154,87 @@ def parse_curve_state(data: bytes) -> dict:
return result
def print_curve_status(state: dict) -> None:
async def fetch_initial_real_token_reserves(client: AsyncClient) -> float:
"""Read the launch-time real token reserves from the Global account.
Global layout up to this field: discriminator(8) + initialized(1) +
authority(32) + fee_recipient(32) + initial_virtual_token_reserves(8) +
initial_virtual_sol_reserves(8), so initial_real_token_reserves sits at 89.
Args:
client: Connected RPC client
Returns:
Initial real token reserves in whole tokens, or the fallback constant
"""
try:
resp = await client.get_account_info(PUMP_GLOBAL, encoding="base64")
data = resp.value.data
raw = struct.unpack_from("<Q", data, 89)[0]
if raw:
return raw / 10**TOKEN_DECIMALS
except Exception as e: # noqa: BLE001 - fall back rather than abort the poller
print(f"⚠️ Could not read Global, using the fallback baseline: {e}")
return FALLBACK_INITIAL_REAL_TOKEN_RESERVES
def print_curve_status(state: dict, baseline: float) -> None:
"""
Print the current status of the bonding curve in a readable format.
Args:
state: The parsed bonding curve state dictionary
baseline: Launch-time real token reserves, used as the 0% mark
"""
progress = 0
progress = 0.0
if state["complete"]:
progress = 100.0
else:
# Pump.fun constants (already converted to human-readable format)
TOTAL_SUPPLY = 1_000_000_000 # 1B tokens
RESERVED_TOKENS = 206_900_000 # 206.9M tokens reserved for migration
initial_real_token_reserves = TOTAL_SUPPLY - RESERVED_TOKENS # 793.1M tokens
if initial_real_token_reserves > 0:
left_tokens = state["real_token_reserves"]
progress = 100 - (left_tokens * 100) / initial_real_token_reserves
elif baseline > 0:
left_tokens = state["real_token_reserves"]
progress = 100 - (left_tokens * 100) / baseline
# A coin can hold more real tokens than Global's baseline — verified on a live
# mayhem/USDC coin with 797.17M against Global's 793.10M — which would print a
# negative percentage. Its launch reserves are not recoverable from the curve
# account alone, so treat that case as "nothing sold yet" rather than guess.
progress = max(progress, 0.0)
print("=" * 30)
print(f"Complete: {'' if state['complete'] else ''}")
print(f"Progress: {progress:.2f}%")
print(f"Token reserves: {state['real_token_reserves']:.4f}")
print(f"SOL reserves: {state['real_sol_reserves']:.4f}")
print(f"{state['quote_symbol']} reserves: {state['real_quote_reserves']:.6f}")
print("=" * 30, "\n")
async def track_curve() -> None:
async def track_curve(token_mint: str) -> None:
"""
Continuously track and display the state of a bonding curve.
Args:
token_mint: The mint address of the coin to follow
"""
if not RPC_URL or not TOKEN_MINT:
print("❌ Set SOLANA_NODE_RPC_ENDPOINT and TOKEN_MINT in .env")
if not RPC_URL:
print("❌ Set SOLANA_NODE_RPC_ENDPOINT in .env")
return
mint_pubkey: Pubkey = Pubkey.from_string(TOKEN_MINT)
mint_pubkey: Pubkey = Pubkey.from_string(token_mint)
curve_pubkey: Pubkey = get_bonding_curve_address(mint_pubkey, PUMP_PROGRAM_ID)
print("Tracking bonding curve for:", mint_pubkey)
print("Curve address:", curve_pubkey, "\n")
async with AsyncClient(RPC_URL) as client:
baseline = await fetch_initial_real_token_reserves(client)
print(f"Graduation baseline: {baseline:,.0f} tokens (from Global)\n")
while True:
try:
data = await get_account_data(client, curve_pubkey)
state = parse_curve_state(data)
print_curve_status(state)
# Never let a coin that launched above Global's baseline read as
# negative progress; see the note in print_curve_status.
baseline = max(baseline, state["real_token_reserves"])
print_curve_status(state, baseline)
except Exception as e:
print(f"⚠️ Error: {e}")
@@ -169,4 +242,10 @@ async def track_curve() -> None:
if __name__ == "__main__":
asyncio.run(track_curve())
if len(sys.argv) < _MIN_ARGC:
print(
"Usage: uv run learning-examples/bonding-curve-progress/"
"poll_bonding_curve_progress.py <MINT>"
)
sys.exit(1)
asyncio.run(track_curve(sys.argv[1]))
@@ -1,11 +1,27 @@
"""Derive a coin's bonding curve and associated bonding curve, offline.
Usage:
uv run learning-examples/compute_associated_bonding_curve.py <MINT>
The associated bonding curve is an ordinary ATA, so its address depends on which
token program owns the mint. Coins created with `create_v2` are Token2022; older
`create` coins are SPL Token. Deriving against the wrong program returns a
valid-looking address that does not exist on chain, so both are printed here —
this script makes no RPC calls and cannot tell which one a given mint is.
"""
import sys
from solders.pubkey import Pubkey
# Global constants
PUMP_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
SYSTEM_TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
TOKEN_2022_PROGRAM = Pubkey.from_string("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb")
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = Pubkey.from_string(
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
)
MIN_ARGC = 2
def get_bonding_curve_address(mint: Pubkey, program_id: Pubkey) -> tuple[Pubkey, int]:
@@ -15,16 +31,25 @@ def get_bonding_curve_address(mint: Pubkey, program_id: Pubkey) -> tuple[Pubkey,
return Pubkey.find_program_address([b"bonding-curve", bytes(mint)], program_id)
def find_associated_bonding_curve(mint: Pubkey, bonding_curve: Pubkey) -> Pubkey:
def find_associated_bonding_curve(
mint: Pubkey, bonding_curve: Pubkey, token_program: Pubkey = TOKEN_2022_PROGRAM
) -> Pubkey:
"""
Find the associated bonding curve for a given mint and bonding curve.
This uses the standard ATA derivation.
"""
Args:
mint: The token mint address
bonding_curve: The bonding curve PDA
token_program: Token program owning the mint; Token2022 for create_v2 coins
Returns:
The derived associated bonding curve address
"""
derived_address, _ = Pubkey.find_program_address(
[
bytes(bonding_curve),
bytes(SYSTEM_TOKEN_PROGRAM),
bytes(token_program),
bytes(mint),
],
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM,
@@ -32,29 +57,34 @@ def find_associated_bonding_curve(mint: Pubkey, bonding_curve: Pubkey) -> Pubkey
return derived_address
def main():
mint_address = input("Enter the token mint address: ")
def main() -> None:
"""Print the curve PDAs for the mint given on the command line."""
if len(sys.argv) < MIN_ARGC:
print(
"Usage: uv run learning-examples/compute_associated_bonding_curve.py <MINT>"
)
return
try:
mint = Pubkey.from_string(mint_address)
bonding_curve_address, bump = get_bonding_curve_address(mint, PUMP_PROGRAM)
# Calculate the associated bonding curve
associated_bonding_curve = find_associated_bonding_curve(
mint, bonding_curve_address
)
print("\nResults:")
print("-" * 50)
print(f"Token Mint: {mint}")
print(f"Bonding Curve: {bonding_curve_address}")
print(f"Associated Bonding Curve: {associated_bonding_curve}")
print(f"Bonding Curve Bump: {bump}")
print("-" * 50)
mint = Pubkey.from_string(sys.argv[1])
except ValueError as e:
print(f"Error: Invalid address format - {e!s}")
return
bonding_curve_address, bump = get_bonding_curve_address(mint, PUMP_PROGRAM)
print("\nResults:")
print("-" * 62)
print(f"Token Mint: {mint}")
print(f"Bonding Curve: {bonding_curve_address}")
print(f"Bonding Curve Bump: {bump}")
for label, program in (
("Token2022 (create_v2 coins)", TOKEN_2022_PROGRAM),
("SPL Token (legacy create)", SYSTEM_TOKEN_PROGRAM),
):
derived = find_associated_bonding_curve(mint, bonding_curve_address, program)
print(f"Associated BC, {label:19s} {derived}")
print("-" * 62)
if __name__ == "__main__":
@@ -24,12 +24,36 @@ def decode_instruction(ix_data, ix_def):
Supports the primitive scalar types and the `OptionBool` defined type
(added in the late-Feb 2026 cashback upgrade `OptionBool` is a struct
wrapping a single bool, so it serializes as 1 byte on the wire).
Trailing args can be absent from the wire entirely: two real mainnet
`create_v2` instructions carry `0001` and `00` respectively after `creator`,
so `is_cashback_enabled` is there in one and omitted in the other. Anything
the data runs out for is reported as None rather than raising.
"""
args = {}
offset = 8 # Skip 8-byte discriminator
# Width each type needs before it can be read at all; strings carry their own
# 4-byte length prefix.
widths = {
"u64": 8,
"i64": 8,
"u32": 4,
"u16": 2,
"u8": 1,
"bool": 1,
"pubkey": 32,
"string": 4,
}
for arg in ix_def["args"]:
t = arg["type"]
needed = widths.get(t, 1) if isinstance(t, str) else 1
if offset + needed > len(ix_data):
# Truncated trailing arg: the sender omitted it.
args[arg["name"]] = None
continue
if t == "u64":
value = struct.unpack_from("<Q", ix_data, offset)[0]
offset += 8
@@ -116,9 +140,6 @@ def decode_transaction(tx_data, idl):
for idl_ix in idl["instructions"]:
idl_discriminator = calculate_discriminator(f"global:{idl_ix['name']}")
print(
f"Checking against IDL instruction: {idl_ix['name']} with discriminator {idl_discriminator:016x}"
)
if discriminator == idl_discriminator:
decoded_args = decode_instruction(ix_data, idl_ix)
@@ -168,7 +189,7 @@ def decode_transaction(tx_data, idl):
tx_file_path = ""
if len(sys.argv) != 2:
tx_file_path = "learning-examples/blockSubscribe-transactions/raw_create_tx_from_blockSubscribe.json"
tx_file_path = "learning-examples/blocksubscribe-transactions/raw_create_tx_from_blocksubscribe.json"
print(f"No path provided, using the path: {tx_file_path}")
else:
tx_file_path = sys.argv[1]
@@ -1,152 +0,0 @@
import json
import struct
import sys
import base58
tx_file_path = ""
if len(sys.argv) != 2:
tx_file_path = "learning-examples/raw_buy_tx_from_getTransaction.json"
print(f"No path provided, using the path: {tx_file_path}")
else:
tx_file_path = sys.argv[1]
# Load the IDL
with open("idl/pump_fun_idl.json") as f:
idl = json.load(f)
# Load the transaction log
with open(tx_file_path) as f:
tx_log = json.load(f)
# Extract the transaction data
tx_data = tx_log["result"]["transaction"]
print(json.dumps(tx_data, indent=2))
def decode_create_instruction(data):
"""Decode legacy Create instruction (Metaplex tokens).
IDL args (March 7, 2026 program upgrade): name, symbol, uri, creator (pubkey).
"""
offset = 8 # Skip the 8-byte discriminator
results = []
for _ in range(3):
length = struct.unpack_from("<I", data, offset)[0]
offset += 4
string_data = data[offset : offset + length].decode("utf-8")
results.append(string_data)
offset += length
creator = base58.b58encode(data[offset : offset + 32]).decode("utf-8") if offset + 32 <= len(data) else None
return {
"name": results[0],
"symbol": results[1],
"uri": results[2],
"creator": creator,
"token_standard": "legacy",
"is_mayhem_mode": False,
}
def decode_create_v2_instruction(data):
"""Decode CreateV2 instruction (Token2022 tokens).
IDL args: name, symbol, uri, creator (pubkey), is_mayhem_mode (bool),
is_cashback_enabled (OptionBool = 1 byte).
"""
offset = 8 # Skip the 8-byte discriminator
results = []
for _ in range(3):
length = struct.unpack_from("<I", data, offset)[0]
offset += 4
string_data = data[offset : offset + length].decode("utf-8")
results.append(string_data)
offset += length
creator = base58.b58encode(data[offset : offset + 32]).decode("utf-8") if offset + 32 <= len(data) else None
offset += 32
is_mayhem_mode = bool(data[offset]) if offset < len(data) else False
offset += 1
is_cashback_enabled = bool(data[offset]) if offset < len(data) else False
return {
"name": results[0],
"symbol": results[1],
"uri": results[2],
"creator": creator,
"token_standard": "token2022",
"is_mayhem_mode": is_mayhem_mode,
"is_cashback_enabled": is_cashback_enabled,
}
def decode_buy_instruction(data):
# Assuming the buy instruction has a u64 argument for amount
amount = struct.unpack_from("<Q", data, 8)[0]
return {"amount": amount}
def decode_instruction_data(instruction, accounts, data):
if instruction["name"] == "create":
return decode_create_instruction(data)
elif instruction["name"] == "create_v2":
return decode_create_v2_instruction(data)
elif instruction["name"] == "buy":
return decode_buy_instruction(data)
else:
return f"Unhandled instruction type: {instruction['name']}"
def find_matching_instruction(accounts, data):
if "instructions" not in idl:
print("Warning: No instructions found in IDL")
return None
for instruction in idl["instructions"]:
if len(instruction["accounts"]) == len(accounts):
return instruction
return None
# Parse the transaction
tx_message = tx_data["message"]
instructions = tx_message["instructions"]
for ix in instructions:
program_id = ix.get("programId")
accounts = ix.get("accounts", [])
data = ix.get("data", "")
if "parsed" in ix:
print(f"Parsed instruction: {ix['program']} - {ix['parsed']['type']}")
print(f"Info: {json.dumps(ix['parsed']['info'], indent=2)}")
elif (
program_id == "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
): # Pump Fun Program
matching_instruction = find_matching_instruction(accounts, data)
if matching_instruction:
decoded_data = decode_instruction_data(
matching_instruction, accounts, base58.b58decode(data)
)
print(f"Instruction: {matching_instruction['name']}")
print(f"Decoded data: {decoded_data}")
print("\nAccounts:")
for i, account in enumerate(accounts):
account_info = matching_instruction["accounts"][i]
print(f" {account_info['name']}: {account}")
else:
print(f"Unable to match instruction for program {program_id}")
else:
print(f"Instruction for program: {program_id}")
print(f"Data: {data}\n")
print("\nTransaction Information:")
print(f"Blockhash: {tx_message['recentBlockhash']}")
print(f"Fee payer: {tx_message['accountKeys'][0]['pubkey']}")
print(f"Signature: {tx_data['signatures'][0]}")
@@ -1,14 +1,22 @@
import base64
import json
import struct
import sys
from construct import Bytes, Flag, Int64ul, Struct
from solders.pubkey import Pubkey
LAMPORTS_PER_SOL = 1_000_000_000
TOKEN_DECIMALS = 6
EXPECTED_DISCRIMINATOR = struct.pack("<Q", 6966180631402821399)
# Quote assets. A curve's `quote_mint` is all zeros when the coin is SOL-paired, and
# the quote-side reserves are always raw units of that mint: 1e9 for SOL, 1e6 for USDC.
DEFAULT_QUOTE_MINT = Pubkey.from_bytes(bytes(32))
WSOL_MINT = Pubkey.from_string("So11111111111111111111111111111111111111112")
USDC_MINT = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
QUOTE_DECIMALS = {WSOL_MINT: 9, USDC_MINT: 6}
QUOTE_SYMBOLS = {WSOL_MINT: "SOL", USDC_MINT: "USDC"}
class BondingCurveState:
_STRUCT = Struct(
@@ -57,20 +65,43 @@ class BondingCurveState:
if len(data) > offset:
self.is_cashback_coin = bool(data[offset])
offset += 1
else:
self.is_cashback_coin = None
if len(data) >= offset + 32:
self.quote_mint = Pubkey.from_bytes(data[offset : offset + 32])
else:
self.quote_mint = DEFAULT_QUOTE_MINT
else:
self.creator = None
self.is_mayhem_mode = None
self.is_cashback_coin = None
self.quote_mint = DEFAULT_QUOTE_MINT
@property
def effective_quote_mint(self) -> Pubkey:
"""The quote mint to price against, resolving all-zeros to wrapped SOL."""
return WSOL_MINT if self.quote_mint == DEFAULT_QUOTE_MINT else self.quote_mint
@property
def quote_symbol(self) -> str:
"""Display symbol of the quote asset."""
mint = self.effective_quote_mint
return QUOTE_SYMBOLS.get(mint, str(mint))
@property
def quote_units(self) -> int:
"""Raw units per whole token of the quote asset."""
return 10 ** QUOTE_DECIMALS.get(self.effective_quote_mint, 9)
def calculate_bonding_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (
return (curve_state.virtual_sol_reserves / curve_state.quote_units) / (
curve_state.virtual_token_reserves / 10**TOKEN_DECIMALS
)
@@ -82,8 +113,13 @@ def decode_bonding_curve_data(raw_data: str) -> BondingCurveState:
return BondingCurveState(decoded_data)
# Load the JSON data
with open("learning-examples/raw_bondingCurve_from_getAccountInfo.json") as file:
# Load the JSON data: pass a getAccountInfo response as argv[1], or use the fixture
curve_file = (
sys.argv[1]
if len(sys.argv) > 1
else "learning-examples/raw_bonding_curve_from_getaccountinfo.json"
)
with open(curve_file) as file:
json_data = json.load(file)
# Extract the base64 encoded data
@@ -93,13 +129,19 @@ encoded_data = json_data["result"]["value"]["data"][0]
bonding_curve_state = decode_bonding_curve_data(encoded_data)
# Calculate and print the token price
token_price_sol = calculate_bonding_curve_price(bonding_curve_state)
token_price = calculate_bonding_curve_price(bonding_curve_state)
symbol = bonding_curve_state.quote_symbol
print("Bonding Curve State:")
print(f" Virtual Token Reserves: {bonding_curve_state.virtual_token_reserves}")
print(f" Virtual SOL Reserves: {bonding_curve_state.virtual_sol_reserves}")
print(
f" Virtual Quote Reserves: {bonding_curve_state.virtual_sol_reserves} raw {symbol}"
)
print(f" Real Token Reserves: {bonding_curve_state.real_token_reserves}")
print(f" Real SOL Reserves: {bonding_curve_state.real_sol_reserves}")
print(f" Real Quote Reserves: {bonding_curve_state.real_sol_reserves} raw {symbol}")
print(f" Token Total Supply: {bonding_curve_state.token_total_supply}")
print(f" Complete: {bonding_curve_state.complete}")
print(f"\nToken Price: {token_price_sol:.10f} SOL")
print(f" Mayhem Mode: {bonding_curve_state.is_mayhem_mode}")
print(f" Cashback Coin: {bonding_curve_state.is_cashback_coin}")
print(f" Quote Mint: {bonding_curve_state.effective_quote_mint}")
print(f"\nToken Price: {token_price:.10f} {symbol}")
@@ -0,0 +1,284 @@
"""Decode the pump.fun instructions in a getTransaction response.
Usage:
uv run learning-examples/decode_from_gettransaction.py [tx.json]
Two things this example exists to show, because both are easy to get wrong:
1. Identify an instruction by its **8-byte Anchor discriminator**, not by how many
accounts it carries. Several pump.fun instructions share an account count, so
matching on the count alone silently labels a `create_v2` as `claim_cashback`
and then prints every account under the wrong name.
2. Read `meta.innerInstructions` as well as `message.instructions`. Most pump.fun
trades reach the program as a CPI from an aggregator or router, so a decoder
that only walks the top level sees almost nothing — in a sample of 40 consecutive
pump.fun transactions there was 1 top-level pump instruction against 8 inner ones.
"""
import hashlib
import json
import struct
import sys
from collections.abc import Iterator
import base58
PUMP_PROGRAM = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
DEFAULT_TX = "learning-examples/raw_buy_tx_from_gettransaction.json"
IDL_PATH = "idl/pump_fun_idl.json"
# Anchor's event-CPI prefix. Every emitted event shows up as an inner instruction
# that calls the program itself with this discriminator, followed by the event's own
# 8-byte discriminator. Without recognising it, half the inner instructions in a
# trade look like unknown instructions.
ANCHOR_EVENT_CPI = bytes([0xE4, 0x45, 0xA5, 0x2E, 0x51, 0xCB, 0x9A, 0x1D])
DISCRIMINATOR_LEN = 8
# v2 trade args: discriminator + two u64, with no track_volume OptionBool.
TRADE_DATA_LEN = 24
EXPECTED_ARGC = 2
def anchor_discriminator(name: str) -> bytes:
"""Return the 8-byte Anchor discriminator for an instruction name.
Args:
name: snake_case instruction name as it appears in the IDL
Returns:
First 8 bytes of sha256("global:<name>")
"""
return hashlib.sha256(f"global:{name}".encode()).digest()[:8]
def build_instruction_index(idl: dict) -> dict[bytes, dict]:
"""Map every IDL instruction to its discriminator.
Args:
idl: Parsed Anchor IDL
Returns:
discriminator -> IDL instruction definition
"""
return {anchor_discriminator(ix["name"]): ix for ix in idl.get("instructions", [])}
def build_event_index(idl: dict) -> dict[bytes, str]:
"""Map every IDL event to its discriminator.
Args:
idl: Parsed Anchor IDL
Returns:
discriminator -> event name
"""
return {
hashlib.sha256(f"event:{event['name']}".encode()).digest()[:8]: event["name"]
for event in idl.get("events", [])
}
def decode_create_instruction(data: bytes) -> dict:
"""Decode a legacy `create` instruction (Metaplex tokens).
Args:
data: Raw instruction data including the discriminator
Returns:
Decoded args: name, symbol, uri, creator
"""
offset = 8 # Skip the 8-byte discriminator
results = []
for _ in range(3):
length = struct.unpack_from("<I", data, offset)[0]
offset += 4
results.append(data[offset : offset + length].decode("utf-8"))
offset += length
creator = (
base58.b58encode(data[offset : offset + 32]).decode("utf-8")
if offset + 32 <= len(data)
else None
)
return {
"name": results[0],
"symbol": results[1],
"uri": results[2],
"creator": creator,
"token_standard": "legacy",
"is_mayhem_mode": False,
}
def decode_create_v2_instruction(data: bytes) -> dict:
"""Decode a `create_v2` instruction (Token2022 tokens).
IDL args: name, symbol, uri, creator (pubkey), is_mayhem_mode (bool),
is_cashback_enabled (OptionBool = 1 byte).
Args:
data: Raw instruction data including the discriminator
Returns:
Decoded args including the mayhem and cashback flags
"""
offset = 8 # Skip the 8-byte discriminator
results = []
for _ in range(3):
length = struct.unpack_from("<I", data, offset)[0]
offset += 4
results.append(data[offset : offset + length].decode("utf-8"))
offset += length
creator = (
base58.b58encode(data[offset : offset + 32]).decode("utf-8")
if offset + 32 <= len(data)
else None
)
offset += 32
is_mayhem_mode = bool(data[offset]) if offset < len(data) else False
offset += 1
is_cashback_enabled = bool(data[offset]) if offset < len(data) else False
return {
"name": results[0],
"symbol": results[1],
"uri": results[2],
"creator": creator,
"token_standard": "token2022",
"is_mayhem_mode": is_mayhem_mode,
"is_cashback_enabled": is_cashback_enabled,
}
def decode_trade_instruction(data: bytes) -> dict:
"""Decode the two u64 args shared by buy/sell and their v2 forms.
v2 args carry no `track_volume` OptionBool: 24 bytes of data, being the
discriminator plus two u64. The quote-side limit is denominated in the quote
mint's raw units — lamports for SOL, 1e-6 for USDC.
Args:
data: Raw instruction data including the discriminator
Returns:
The token amount and the quote-side limit
"""
if len(data) < TRADE_DATA_LEN:
return {"error": f"expected >={TRADE_DATA_LEN} bytes of data, got {len(data)}"}
amount, quote_limit = struct.unpack_from("<QQ", data, 8)
return {"amount": amount, "quote_limit": quote_limit}
DECODERS = {
"create": decode_create_instruction,
"create_v2": decode_create_v2_instruction,
"buy": decode_trade_instruction,
"buy_v2": decode_trade_instruction,
"sell": decode_trade_instruction,
"sell_v2": decode_trade_instruction,
}
def iter_pump_instructions(result: dict) -> Iterator[tuple[str, dict]]:
"""Yield every pump.fun instruction in a getTransaction result.
Args:
result: The `result` object of a jsonParsed getTransaction response
Yields:
(location, instruction) where location is "top-level" or "inner (ix N)"
"""
for ix in result["transaction"]["message"].get("instructions", []):
if ix.get("programId") == PUMP_PROGRAM and ix.get("data"):
yield "top-level", ix
for group in result.get("meta", {}).get("innerInstructions") or []:
for ix in group.get("instructions", []):
if ix.get("programId") == PUMP_PROGRAM and ix.get("data"):
yield f"inner (ix {group['index']})", ix
def describe(
location: str, ix: dict, index: dict[bytes, dict], events: dict[bytes, str]
) -> None:
"""Print one pump.fun instruction, resolved against the IDL.
Args:
location: Where the instruction sits in the transaction
ix: The jsonParsed instruction
index: discriminator -> IDL instruction definition
events: discriminator -> IDL event name
"""
data = base58.b58decode(ix["data"])
accounts = ix.get("accounts", [])
if data[:8] == ANCHOR_EVENT_CPI:
event = events.get(data[8:16], "unknown event")
print(f"\n[{location}] anchor event emit -> {event}")
return
definition = index.get(data[:8])
if definition is None:
disc = (
struct.unpack("<Q", data[:DISCRIMINATOR_LEN])[0]
if len(data) >= DISCRIMINATOR_LEN
else None
)
print(f"\n[{location}] unknown pump.fun instruction (discriminator {disc})")
return
name = definition["name"]
print(f"\n[{location}] {name}")
decoder = DECODERS.get(name)
print(f" args: {decoder(data) if decoder else '(no decoder in this example)'}")
# The IDL under-reports the legacy instructions and omits create_v2's optional
# remaining accounts, so name what it covers and list the rest positionally.
idl_accounts = definition.get("accounts", [])
print(f" accounts: {len(accounts)} on chain, {len(idl_accounts)} named in the IDL")
for i, account in enumerate(accounts):
label = idl_accounts[i]["name"] if i < len(idl_accounts) else f"<extra {i}>"
print(f" {i:2d} {label}: {account}")
def main() -> None:
"""Decode the pump.fun instructions of one saved transaction."""
tx_file_path = sys.argv[1] if len(sys.argv) == EXPECTED_ARGC else DEFAULT_TX
if len(sys.argv) != EXPECTED_ARGC:
print(f"No path provided, using the path: {tx_file_path}")
with open(IDL_PATH) as f:
idl = json.load(f)
index = build_instruction_index(idl)
events = build_event_index(idl)
with open(tx_file_path) as f:
result = json.load(f)["result"]
found = 0
for location, ix in iter_pump_instructions(result):
describe(location, ix, index, events)
found += 1
if not found:
print(
"\nNo pump.fun instruction in this transaction. That is normal for a "
"router transaction whose pump.fun call was not captured in meta."
)
message = result["transaction"]["message"]
print("\nTransaction Information:")
print(f"Blockhash: {message['recentBlockhash']}")
print(f"Fee payer: {message['accountKeys'][0]['pubkey']}")
print(f"Signature: {result['transaction']['signatures'][0]}")
print(f"Slot: {result.get('slot')}")
if __name__ == "__main__":
main()
@@ -18,10 +18,32 @@ WSS_ENDPOINT = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
WEBSOCKET_MAX_MESSAGE_BYTES = 32 * 1024 * 1024
def extract_signature(tx: dict) -> str | None:
"""Pull the first signature out of a blockSubscribe transaction entry.
The encoding decides the shape: base64 gives `transaction` as a list whose
first element is the signature, jsonParsed gives a dict with `signatures`.
Args:
tx: One entry from `block["transactions"]`
Returns:
The signature string, or None if this entry carries no transaction
"""
if not isinstance(tx, dict):
return None
raw = tx.get("transaction")
if isinstance(raw, list) and raw:
return raw[0]
if isinstance(raw, dict) and raw.get("signatures"):
return raw["signatures"][0]
return None
async def save_transaction(tx_data, tx_signature):
os.makedirs("blockSubscribe-transactions", exist_ok=True)
os.makedirs("blocksubscribe-transactions", exist_ok=True)
hashed_signature = hashlib.sha256(tx_signature.encode()).hexdigest()
file_path = os.path.join("blockSubscribe-transactions", f"{hashed_signature}.json")
file_path = os.path.join("blocksubscribe-transactions", f"{hashed_signature}.json")
with open(file_path, "w") as f:
json.dump(tx_data, f, indent=2)
print(f"Saved transaction: {hashed_signature[:8]}...")
@@ -64,27 +86,30 @@ async def listen_for_transactions():
if "transactions" in block:
transactions = block["transactions"]
for tx in transactions:
if isinstance(tx, dict) and "transaction" in tx:
if (
isinstance(tx["transaction"], list)
and len(tx["transaction"]) > 0
):
tx_signature = tx["transaction"][0]
elif (
isinstance(tx["transaction"], dict)
and "signatures" in tx["transaction"]
):
tx_signature = tx["transaction"][
"signatures"
][0]
else:
continue
tx_signature = extract_signature(tx)
if tx_signature:
await save_transaction(tx, tx_signature)
elif "result" in data:
print("Subscription confirmed")
except websockets.ConnectionClosed:
# Leave the recv loop so main() can reconnect. Swallowing this here
# would make the next recv() raise immediately, spinning the loop.
print("WebSocket connection closed.")
break
except Exception as e:
print(f"An error occurred: {e!s}")
async def main() -> None:
"""Reconnect for as long as the script runs."""
while True:
try:
await listen_for_transactions()
except (websockets.WebSocketException, OSError) as e:
print(f"Connection error: {e!s}")
print("Reconnecting in 5 seconds...")
await asyncio.sleep(5)
if __name__ == "__main__":
asyncio.run(listen_for_transactions())
asyncio.run(main())
+149 -34
View File
@@ -1,3 +1,14 @@
"""Read one pump.fun bonding curve and print the token price in its quote asset.
Usage:
uv run learning-examples/fetch_price.py <BONDING_CURVE_ADDRESS>
pump.fun coins are not all SOL-paired. The curve carries a `quote_mint`, and the
quote-side reserves are denominated in that mint's raw units — 1e9 for SOL, 1e6 for
USDC. Dividing by a hardcoded 1e9 prints a USDC-paired coin's price 1000x too low.
`quote_mint` is `Pubkey::default()` (all zeros) on SOL-paired coins.
"""
import asyncio
import os
import struct
@@ -9,14 +20,27 @@ from dotenv import load_dotenv
from solana.rpc.async_api import AsyncClient
from solders.pubkey import Pubkey
LAMPORTS_PER_SOL: Final[int] = 1_000_000_000
TOKEN_DECIMALS: Final[int] = 6
# Bonding curve address: pass as argv[1], or hardcode here.
CURVE_ADDRESS: Final[str] = sys.argv[1] if len(sys.argv) > 1 else "..."
WSOL_MINT: Final[Pubkey] = Pubkey.from_string(
"So11111111111111111111111111111111111111112"
)
USDC_MINT: Final[Pubkey] = Pubkey.from_string(
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
)
# All-zero quote_mint means the coin is SOL-paired.
DEFAULT_QUOTE_MINT: Final[Pubkey] = Pubkey.from_bytes(bytes(32))
QUOTE_DECIMALS: Final[dict[Pubkey, int]] = {WSOL_MINT: 9, USDC_MINT: 6}
QUOTE_SYMBOLS: Final[dict[Pubkey, str]] = {WSOL_MINT: "SOL", USDC_MINT: "USDC"}
# Here and later all the discriminators are precalculated. See learning-examples/calculate_discriminator.py
EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 6966180631402821399)
# Data lengths, excluding the 8-byte discriminator: V2 stops after `creator`, V4
# runs through `quote_mint`. Live accounts are 151 bytes, so the tail is padding.
_V2_LENGTH: Final[int] = 73
_V4_LENGTH: Final[int] = 107
load_dotenv()
RPC_ENDPOINT = os.environ.get("SOLANA_NODE_RPC_ENDPOINT")
@@ -27,18 +51,18 @@ class BondingCurveState:
_STRUCT_V1 = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"virtual_quote_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"real_quote_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag,
)
_STRUCT_V2 = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"virtual_quote_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"real_quote_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag,
"creator" / Bytes(32),
@@ -46,40 +70,104 @@ class BondingCurveState:
_STRUCT_V3 = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"virtual_quote_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"real_quote_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag,
"creator" / Bytes(32),
"is_mayhem_mode" / Flag,
)
def __init__(self, data: bytes) -> None:
"""Parse bonding curve data - auto-detects version."""
data_length = len(data) - 8
# Current layout. The account is 151 bytes: this struct is 107 bytes after the
# 8-byte discriminator, and the remaining 36 are reserved padding.
_STRUCT_V4 = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_quote_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_quote_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag,
"creator" / Bytes(32),
"is_mayhem_mode" / Flag,
"is_cashback_coin" / Flag,
"quote_mint" / Bytes(32),
)
if data_length < 73: # V1: without creator and mayhem mode
parsed = self._STRUCT_V1.parse(data[8:])
self.__dict__.update(parsed)
self.creator = None
self.is_mayhem_mode = False
elif data_length == 73: # V2: with creator, without mayhem mode
parsed = self._STRUCT_V2.parse(data[8:])
self.__dict__.update(parsed)
if isinstance(self.creator, bytes):
self.creator = Pubkey.from_bytes(self.creator)
self.is_mayhem_mode = False
else: # V3: with creator and mayhem mode
parsed = self._STRUCT_V3.parse(data[8:])
self.__dict__.update(parsed)
if isinstance(self.creator, bytes):
self.creator = Pubkey.from_bytes(self.creator)
def __init__(self, data: bytes) -> None:
"""Parse bonding curve data - auto-detects version.
Args:
data: Raw account data including the 8-byte discriminator
"""
body = data[8:]
data_length = len(body)
self.creator = None
self.is_mayhem_mode = False
self.is_cashback_coin = False
self.quote_mint = DEFAULT_QUOTE_MINT
if data_length < _V2_LENGTH: # V1: without creator and mayhem mode
parsed = self._STRUCT_V1.parse(body)
elif data_length == _V2_LENGTH: # V2: with creator, without mayhem mode
parsed = self._STRUCT_V2.parse(body)
elif data_length < _V4_LENGTH: # V3: with creator and mayhem mode
parsed = self._STRUCT_V3.parse(body)
else: # V4: adds is_cashback_coin and quote_mint
parsed = self._STRUCT_V4.parse(body)
self.__dict__.update(parsed)
if isinstance(self.creator, bytes):
self.creator = Pubkey.from_bytes(self.creator)
if isinstance(self.quote_mint, bytes):
self.quote_mint = Pubkey.from_bytes(self.quote_mint)
# The SOL-named fields were renamed when non-SOL quote assets landed. Keep the
# old names working for anything that still reads them.
self.virtual_sol_reserves = self.virtual_quote_reserves
self.real_sol_reserves = self.real_quote_reserves
def normalize_quote_mint(quote_mint: Pubkey) -> Pubkey:
"""Resolve an all-zero quote mint to wrapped SOL.
Args:
quote_mint: The curve's raw quote_mint field
Returns:
The effective quote mint
"""
return WSOL_MINT if quote_mint == DEFAULT_QUOTE_MINT else quote_mint
def quote_units(quote_mint: Pubkey) -> int:
"""Return the raw units per whole token of the quote mint.
Args:
quote_mint: The effective quote mint
Returns:
1e9 for SOL, 1e6 for USDC, defaulting to 1e9 for an unknown mint
"""
return 10 ** QUOTE_DECIMALS.get(quote_mint, 9)
async def get_bonding_curve_state(
conn: AsyncClient, curve_address: Pubkey
) -> BondingCurveState:
"""Fetch and parse a bonding curve account.
Args:
conn: Connected RPC client
curve_address: The bonding curve PDA
Returns:
The parsed curve state
Raises:
ValueError: If the account is missing or is not a bonding curve
"""
response = await conn.get_account_info(curve_address, encoding="base64")
if not response.value or not response.value.data:
raise ValueError("Invalid curve state: No data")
@@ -92,23 +180,50 @@ async def get_bonding_curve_state(
def calculate_bonding_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
"""Price one token in the curve's quote asset.
Args:
curve_state: The parsed curve state
Returns:
Price per token, denominated in the quote mint
Raises:
ValueError: If either virtual reserve is non-positive
"""
if (
curve_state.virtual_token_reserves <= 0
or curve_state.virtual_quote_reserves <= 0
):
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (
quote_mint = normalize_quote_mint(curve_state.quote_mint)
return (curve_state.virtual_quote_reserves / quote_units(quote_mint)) / (
curve_state.virtual_token_reserves / 10**TOKEN_DECIMALS
)
async def main() -> None:
"""Print the price of the coin behind the bonding curve given on the CLI."""
if len(sys.argv) < 2:
print("Usage: uv run learning-examples/fetch_price.py <BONDING_CURVE_ADDRESS>")
return
try:
async with AsyncClient(RPC_ENDPOINT) as conn:
curve_address = Pubkey.from_string(CURVE_ADDRESS)
bonding_curve_state = await get_bonding_curve_state(conn, curve_address)
token_price_sol = calculate_bonding_curve_price(bonding_curve_state)
curve_address = Pubkey.from_string(sys.argv[1])
state = await get_bonding_curve_state(conn, curve_address)
price = calculate_bonding_curve_price(state)
quote_mint = normalize_quote_mint(state.quote_mint)
symbol = QUOTE_SYMBOLS.get(quote_mint, str(quote_mint))
print("Token price:")
print(f" {token_price_sol:.10f} SOL")
print(f" {price:.10f} {symbol}")
print(f"\nquote mint: {quote_mint}")
print(f"mayhem: {state.is_mayhem_mode}")
print(f"cashback: {state.is_cashback_coin}")
print(f"complete: {state.complete}")
except ValueError as e:
print(f"Error: {e}")
except Exception as e:
@@ -538,6 +538,14 @@ async def listen_for_migrations(wss_url, provider_name, tracker, known_events=No
except Exception as e:
print(f"[ERROR] Failed to decode Program data: {e}")
except websockets.ConnectionClosed:
# Break out so the outer loop reconnects. Swallowing the
# disconnect here makes every following recv() raise
# immediately, spinning the loop instead of retrying.
print(
f"[WARN] Migration listener for {provider_name}: connection closed"
)
break
except Exception as e:
print(f"[ERROR] Migration listener for {provider_name}: {e}")
@@ -651,6 +659,13 @@ async def listen_for_markets(wss_url, provider_name, tracker, known_markets):
except Exception as e:
print(f"[ERROR] Failed to decode account: {e}")
except websockets.ConnectionClosed:
# Same reason as the migration listener above: break so the
# outer loop can reconnect instead of spinning on recv().
print(
f"[WARN] Market listener for {provider_name}: connection closed"
)
break
except Exception as e:
print(f"[ERROR] Market listener for {provider_name}: {e}")
@@ -1,116 +0,0 @@
import asyncio
import json
import os
import websockets
from dotenv import load_dotenv
from solders.pubkey import Pubkey
load_dotenv()
WSS_ENDPOINT = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
# Solana's blockSubscribe (and a busy logsSubscribe) sends frames well past
# websockets' 1 MiB default, which kills the connection with a 1009 close
# instead of delivering the message. Same value the bot's own listeners use.
WEBSOCKET_MAX_MESSAGE_BYTES = 32 * 1024 * 1024
PUMP_MIGRATOR_ID = Pubkey.from_string("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg")
def process_initialize2_transaction(data):
"""Process and decode an initialize2 transaction"""
try:
signature = data["transaction"]["signatures"][0]
account_keys = data["transaction"]["message"]["accountKeys"]
# Check raydium_amm_idl.json for the account keys
# The token address is typically the 19th account (index 18)
# The liquidity pool address is typically the 3rd account (index 2)
if len(account_keys) > 18:
token_address = account_keys[18]
liquidity_address = account_keys[2]
print(f"\nSignature: {signature}")
print(f"Token Address: {token_address}")
print(f"Liquidity Address: {liquidity_address}")
print("=" * 50)
else:
print(f"\nError: Not enough account keys (found {len(account_keys)})")
except Exception as e:
print(f"\nError: {e!s}")
async def listen_for_events():
while True:
try:
async with websockets.connect(
WSS_ENDPOINT, max_size=WEBSOCKET_MAX_MESSAGE_BYTES
) as websocket:
subscription_message = json.dumps(
{
"jsonrpc": "2.0",
"id": 1,
"method": "blockSubscribe",
"params": [
{"mentionsAccountOrProgram": str(PUMP_MIGRATOR_ID)},
{
"commitment": "confirmed",
"encoding": "json",
"showRewards": False,
"transactionDetails": "full",
"maxSupportedTransactionVersion": 0,
},
],
}
)
await websocket.send(subscription_message)
response = await websocket.recv()
print(f"Subscription response: {response}")
print("\nListening for Raydium pool initialization events...")
while True:
try:
response = await asyncio.wait_for(websocket.recv(), timeout=30)
data = json.loads(response)
if "method" in data and data["method"] == "blockNotification":
if "params" in data and "result" in data["params"]:
block_data = data["params"]["result"]
if (
"value" in block_data
and "block" in block_data["value"]
):
block = block_data["value"]["block"]
if "transactions" in block:
for tx in block["transactions"]:
logs = tx.get("meta", {}).get(
"logMessages", []
)
# Check for initialize2 instruction
for log in logs:
if (
"Program log: initialize2: InitializeInstruction2"
in log
):
print(
"Found initialize2 instruction!"
)
process_initialize2_transaction(tx)
break
except TimeoutError:
print("\nChecking connection...")
print("Connection alive")
continue
except Exception as e:
print(f"\nConnection error: {e!s}")
print("Retrying in 5 seconds...")
await asyncio.sleep(5)
if __name__ == "__main__":
asyncio.run(listen_for_events())
@@ -38,7 +38,9 @@ import base64
import json
import os
import struct
import sys
import time
from pathlib import Path
import base58
import grpc
@@ -47,6 +49,9 @@ from dotenv import load_dotenv
from solders.pubkey import Pubkey
from solders.transaction import VersionedTransaction
# Reach the shared geyser stubs in src/geyser/generated (imported lazily below).
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
load_dotenv(override=True)
# Solana's blockSubscribe (and a busy logsSubscribe) sends frames well past
@@ -617,6 +622,15 @@ async def listen_block_subscription(wss_url, provider_name, tracker, known_token
except Exception as e:
print(f"[ERROR] Failed to process transaction: {e}")
except websockets.ConnectionClosed:
# Break out so the outer loop reconnects. Without this the
# broad handler below swallows the disconnect and recv()
# raises again immediately, spinning at millions of
# iterations per minute.
print(
f"[WARN] Block listener for {provider_name}: connection closed"
)
break
except Exception as e:
print(f"[ERROR] Block listener for {provider_name}: {e}")
@@ -743,11 +757,12 @@ async def listen_geyser_grpc(
Listen for new tokens via Geyser gRPC API
"""
try:
# Import the generated protobuf modules
from generated import geyser_pb2, geyser_pb2_grpc
# Generated once into src/geyser/generated; see CLAUDE.md for regenerating them.
from src.geyser.generated import geyser_pb2, geyser_pb2_grpc
except ImportError:
print(
"[ERROR] Could not import geyser_pb2 or geyser_pb2_grpc. Make sure to generate from .proto files"
"[ERROR] Could not import geyser_pb2 or geyser_pb2_grpc. "
"Regenerate them into src/geyser/generated from src/geyser/proto"
)
return
File diff suppressed because one or more lines are too long
@@ -1,791 +0,0 @@
import solana_storage_pb2 as _solana_storage_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import (
ClassVar as _ClassVar,
Iterable as _Iterable,
Mapping as _Mapping,
Optional as _Optional,
Union as _Union,
)
from solana_storage_pb2 import ConfirmedBlock as ConfirmedBlock
from solana_storage_pb2 import ConfirmedTransaction as ConfirmedTransaction
from solana_storage_pb2 import Transaction as Transaction
from solana_storage_pb2 import Message as Message
from solana_storage_pb2 import MessageHeader as MessageHeader
from solana_storage_pb2 import MessageAddressTableLookup as MessageAddressTableLookup
from solana_storage_pb2 import TransactionStatusMeta as TransactionStatusMeta
from solana_storage_pb2 import TransactionError as TransactionError
from solana_storage_pb2 import InnerInstructions as InnerInstructions
from solana_storage_pb2 import InnerInstruction as InnerInstruction
from solana_storage_pb2 import CompiledInstruction as CompiledInstruction
from solana_storage_pb2 import TokenBalance as TokenBalance
from solana_storage_pb2 import UiTokenAmount as UiTokenAmount
from solana_storage_pb2 import ReturnData as ReturnData
from solana_storage_pb2 import Reward as Reward
from solana_storage_pb2 import Rewards as Rewards
from solana_storage_pb2 import UnixTimestamp as UnixTimestamp
from solana_storage_pb2 import BlockHeight as BlockHeight
from solana_storage_pb2 import NumPartitions as NumPartitions
from solana_storage_pb2 import RewardType as RewardType
DESCRIPTOR: _descriptor.FileDescriptor
Unspecified: _solana_storage_pb2.RewardType
Fee: _solana_storage_pb2.RewardType
Rent: _solana_storage_pb2.RewardType
Staking: _solana_storage_pb2.RewardType
Voting: _solana_storage_pb2.RewardType
class CommitmentLevel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
PROCESSED: _ClassVar[CommitmentLevel]
CONFIRMED: _ClassVar[CommitmentLevel]
FINALIZED: _ClassVar[CommitmentLevel]
FIRST_SHRED_RECEIVED: _ClassVar[CommitmentLevel]
COMPLETED: _ClassVar[CommitmentLevel]
CREATED_BANK: _ClassVar[CommitmentLevel]
DEAD: _ClassVar[CommitmentLevel]
PROCESSED: CommitmentLevel
CONFIRMED: CommitmentLevel
FINALIZED: CommitmentLevel
FIRST_SHRED_RECEIVED: CommitmentLevel
COMPLETED: CommitmentLevel
CREATED_BANK: CommitmentLevel
DEAD: CommitmentLevel
class SubscribeRequest(_message.Message):
__slots__ = (
"accounts",
"slots",
"transactions",
"transactions_status",
"blocks",
"blocks_meta",
"entry",
"commitment",
"accounts_data_slice",
"ping",
)
class AccountsEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: SubscribeRequestFilterAccounts
def __init__(
self,
key: _Optional[str] = ...,
value: _Optional[_Union[SubscribeRequestFilterAccounts, _Mapping]] = ...,
) -> None: ...
class SlotsEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: SubscribeRequestFilterSlots
def __init__(
self,
key: _Optional[str] = ...,
value: _Optional[_Union[SubscribeRequestFilterSlots, _Mapping]] = ...,
) -> None: ...
class TransactionsEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: SubscribeRequestFilterTransactions
def __init__(
self,
key: _Optional[str] = ...,
value: _Optional[
_Union[SubscribeRequestFilterTransactions, _Mapping]
] = ...,
) -> None: ...
class TransactionsStatusEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: SubscribeRequestFilterTransactions
def __init__(
self,
key: _Optional[str] = ...,
value: _Optional[
_Union[SubscribeRequestFilterTransactions, _Mapping]
] = ...,
) -> None: ...
class BlocksEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: SubscribeRequestFilterBlocks
def __init__(
self,
key: _Optional[str] = ...,
value: _Optional[_Union[SubscribeRequestFilterBlocks, _Mapping]] = ...,
) -> None: ...
class BlocksMetaEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: SubscribeRequestFilterBlocksMeta
def __init__(
self,
key: _Optional[str] = ...,
value: _Optional[_Union[SubscribeRequestFilterBlocksMeta, _Mapping]] = ...,
) -> None: ...
class EntryEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: SubscribeRequestFilterEntry
def __init__(
self,
key: _Optional[str] = ...,
value: _Optional[_Union[SubscribeRequestFilterEntry, _Mapping]] = ...,
) -> None: ...
ACCOUNTS_FIELD_NUMBER: _ClassVar[int]
SLOTS_FIELD_NUMBER: _ClassVar[int]
TRANSACTIONS_FIELD_NUMBER: _ClassVar[int]
TRANSACTIONS_STATUS_FIELD_NUMBER: _ClassVar[int]
BLOCKS_FIELD_NUMBER: _ClassVar[int]
BLOCKS_META_FIELD_NUMBER: _ClassVar[int]
ENTRY_FIELD_NUMBER: _ClassVar[int]
COMMITMENT_FIELD_NUMBER: _ClassVar[int]
ACCOUNTS_DATA_SLICE_FIELD_NUMBER: _ClassVar[int]
PING_FIELD_NUMBER: _ClassVar[int]
accounts: _containers.MessageMap[str, SubscribeRequestFilterAccounts]
slots: _containers.MessageMap[str, SubscribeRequestFilterSlots]
transactions: _containers.MessageMap[str, SubscribeRequestFilterTransactions]
transactions_status: _containers.MessageMap[str, SubscribeRequestFilterTransactions]
blocks: _containers.MessageMap[str, SubscribeRequestFilterBlocks]
blocks_meta: _containers.MessageMap[str, SubscribeRequestFilterBlocksMeta]
entry: _containers.MessageMap[str, SubscribeRequestFilterEntry]
commitment: CommitmentLevel
accounts_data_slice: _containers.RepeatedCompositeFieldContainer[
SubscribeRequestAccountsDataSlice
]
ping: SubscribeRequestPing
def __init__(
self,
accounts: _Optional[_Mapping[str, SubscribeRequestFilterAccounts]] = ...,
slots: _Optional[_Mapping[str, SubscribeRequestFilterSlots]] = ...,
transactions: _Optional[
_Mapping[str, SubscribeRequestFilterTransactions]
] = ...,
transactions_status: _Optional[
_Mapping[str, SubscribeRequestFilterTransactions]
] = ...,
blocks: _Optional[_Mapping[str, SubscribeRequestFilterBlocks]] = ...,
blocks_meta: _Optional[_Mapping[str, SubscribeRequestFilterBlocksMeta]] = ...,
entry: _Optional[_Mapping[str, SubscribeRequestFilterEntry]] = ...,
commitment: _Optional[_Union[CommitmentLevel, str]] = ...,
accounts_data_slice: _Optional[
_Iterable[_Union[SubscribeRequestAccountsDataSlice, _Mapping]]
] = ...,
ping: _Optional[_Union[SubscribeRequestPing, _Mapping]] = ...,
) -> None: ...
class SubscribeRequestFilterAccounts(_message.Message):
__slots__ = ("account", "owner", "filters", "nonempty_txn_signature")
ACCOUNT_FIELD_NUMBER: _ClassVar[int]
OWNER_FIELD_NUMBER: _ClassVar[int]
FILTERS_FIELD_NUMBER: _ClassVar[int]
NONEMPTY_TXN_SIGNATURE_FIELD_NUMBER: _ClassVar[int]
account: _containers.RepeatedScalarFieldContainer[str]
owner: _containers.RepeatedScalarFieldContainer[str]
filters: _containers.RepeatedCompositeFieldContainer[
SubscribeRequestFilterAccountsFilter
]
nonempty_txn_signature: bool
def __init__(
self,
account: _Optional[_Iterable[str]] = ...,
owner: _Optional[_Iterable[str]] = ...,
filters: _Optional[
_Iterable[_Union[SubscribeRequestFilterAccountsFilter, _Mapping]]
] = ...,
nonempty_txn_signature: bool = ...,
) -> None: ...
class SubscribeRequestFilterAccountsFilter(_message.Message):
__slots__ = ("memcmp", "datasize", "token_account_state", "lamports")
MEMCMP_FIELD_NUMBER: _ClassVar[int]
DATASIZE_FIELD_NUMBER: _ClassVar[int]
TOKEN_ACCOUNT_STATE_FIELD_NUMBER: _ClassVar[int]
LAMPORTS_FIELD_NUMBER: _ClassVar[int]
memcmp: SubscribeRequestFilterAccountsFilterMemcmp
datasize: int
token_account_state: bool
lamports: SubscribeRequestFilterAccountsFilterLamports
def __init__(
self,
memcmp: _Optional[
_Union[SubscribeRequestFilterAccountsFilterMemcmp, _Mapping]
] = ...,
datasize: _Optional[int] = ...,
token_account_state: bool = ...,
lamports: _Optional[
_Union[SubscribeRequestFilterAccountsFilterLamports, _Mapping]
] = ...,
) -> None: ...
class SubscribeRequestFilterAccountsFilterMemcmp(_message.Message):
__slots__ = ("offset", "bytes", "base58", "base64")
OFFSET_FIELD_NUMBER: _ClassVar[int]
BYTES_FIELD_NUMBER: _ClassVar[int]
BASE58_FIELD_NUMBER: _ClassVar[int]
BASE64_FIELD_NUMBER: _ClassVar[int]
offset: int
bytes: bytes
base58: str
base64: str
def __init__(
self,
offset: _Optional[int] = ...,
bytes: _Optional[bytes] = ...,
base58: _Optional[str] = ...,
base64: _Optional[str] = ...,
) -> None: ...
class SubscribeRequestFilterAccountsFilterLamports(_message.Message):
__slots__ = ("eq", "ne", "lt", "gt")
EQ_FIELD_NUMBER: _ClassVar[int]
NE_FIELD_NUMBER: _ClassVar[int]
LT_FIELD_NUMBER: _ClassVar[int]
GT_FIELD_NUMBER: _ClassVar[int]
eq: int
ne: int
lt: int
gt: int
def __init__(
self,
eq: _Optional[int] = ...,
ne: _Optional[int] = ...,
lt: _Optional[int] = ...,
gt: _Optional[int] = ...,
) -> None: ...
class SubscribeRequestFilterSlots(_message.Message):
__slots__ = ("filter_by_commitment",)
FILTER_BY_COMMITMENT_FIELD_NUMBER: _ClassVar[int]
filter_by_commitment: bool
def __init__(self, filter_by_commitment: bool = ...) -> None: ...
class SubscribeRequestFilterTransactions(_message.Message):
__slots__ = (
"vote",
"failed",
"signature",
"account_include",
"account_exclude",
"account_required",
)
VOTE_FIELD_NUMBER: _ClassVar[int]
FAILED_FIELD_NUMBER: _ClassVar[int]
SIGNATURE_FIELD_NUMBER: _ClassVar[int]
ACCOUNT_INCLUDE_FIELD_NUMBER: _ClassVar[int]
ACCOUNT_EXCLUDE_FIELD_NUMBER: _ClassVar[int]
ACCOUNT_REQUIRED_FIELD_NUMBER: _ClassVar[int]
vote: bool
failed: bool
signature: str
account_include: _containers.RepeatedScalarFieldContainer[str]
account_exclude: _containers.RepeatedScalarFieldContainer[str]
account_required: _containers.RepeatedScalarFieldContainer[str]
def __init__(
self,
vote: bool = ...,
failed: bool = ...,
signature: _Optional[str] = ...,
account_include: _Optional[_Iterable[str]] = ...,
account_exclude: _Optional[_Iterable[str]] = ...,
account_required: _Optional[_Iterable[str]] = ...,
) -> None: ...
class SubscribeRequestFilterBlocks(_message.Message):
__slots__ = (
"account_include",
"include_transactions",
"include_accounts",
"include_entries",
)
ACCOUNT_INCLUDE_FIELD_NUMBER: _ClassVar[int]
INCLUDE_TRANSACTIONS_FIELD_NUMBER: _ClassVar[int]
INCLUDE_ACCOUNTS_FIELD_NUMBER: _ClassVar[int]
INCLUDE_ENTRIES_FIELD_NUMBER: _ClassVar[int]
account_include: _containers.RepeatedScalarFieldContainer[str]
include_transactions: bool
include_accounts: bool
include_entries: bool
def __init__(
self,
account_include: _Optional[_Iterable[str]] = ...,
include_transactions: bool = ...,
include_accounts: bool = ...,
include_entries: bool = ...,
) -> None: ...
class SubscribeRequestFilterBlocksMeta(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class SubscribeRequestFilterEntry(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class SubscribeRequestAccountsDataSlice(_message.Message):
__slots__ = ("offset", "length")
OFFSET_FIELD_NUMBER: _ClassVar[int]
LENGTH_FIELD_NUMBER: _ClassVar[int]
offset: int
length: int
def __init__(
self, offset: _Optional[int] = ..., length: _Optional[int] = ...
) -> None: ...
class SubscribeRequestPing(_message.Message):
__slots__ = ("id",)
ID_FIELD_NUMBER: _ClassVar[int]
id: int
def __init__(self, id: _Optional[int] = ...) -> None: ...
class SubscribeUpdate(_message.Message):
__slots__ = (
"filters",
"account",
"slot",
"transaction",
"transaction_status",
"block",
"ping",
"pong",
"block_meta",
"entry",
)
FILTERS_FIELD_NUMBER: _ClassVar[int]
ACCOUNT_FIELD_NUMBER: _ClassVar[int]
SLOT_FIELD_NUMBER: _ClassVar[int]
TRANSACTION_FIELD_NUMBER: _ClassVar[int]
TRANSACTION_STATUS_FIELD_NUMBER: _ClassVar[int]
BLOCK_FIELD_NUMBER: _ClassVar[int]
PING_FIELD_NUMBER: _ClassVar[int]
PONG_FIELD_NUMBER: _ClassVar[int]
BLOCK_META_FIELD_NUMBER: _ClassVar[int]
ENTRY_FIELD_NUMBER: _ClassVar[int]
filters: _containers.RepeatedScalarFieldContainer[str]
account: SubscribeUpdateAccount
slot: SubscribeUpdateSlot
transaction: SubscribeUpdateTransaction
transaction_status: SubscribeUpdateTransactionStatus
block: SubscribeUpdateBlock
ping: SubscribeUpdatePing
pong: SubscribeUpdatePong
block_meta: SubscribeUpdateBlockMeta
entry: SubscribeUpdateEntry
def __init__(
self,
filters: _Optional[_Iterable[str]] = ...,
account: _Optional[_Union[SubscribeUpdateAccount, _Mapping]] = ...,
slot: _Optional[_Union[SubscribeUpdateSlot, _Mapping]] = ...,
transaction: _Optional[_Union[SubscribeUpdateTransaction, _Mapping]] = ...,
transaction_status: _Optional[
_Union[SubscribeUpdateTransactionStatus, _Mapping]
] = ...,
block: _Optional[_Union[SubscribeUpdateBlock, _Mapping]] = ...,
ping: _Optional[_Union[SubscribeUpdatePing, _Mapping]] = ...,
pong: _Optional[_Union[SubscribeUpdatePong, _Mapping]] = ...,
block_meta: _Optional[_Union[SubscribeUpdateBlockMeta, _Mapping]] = ...,
entry: _Optional[_Union[SubscribeUpdateEntry, _Mapping]] = ...,
) -> None: ...
class SubscribeUpdateAccount(_message.Message):
__slots__ = ("account", "slot", "is_startup")
ACCOUNT_FIELD_NUMBER: _ClassVar[int]
SLOT_FIELD_NUMBER: _ClassVar[int]
IS_STARTUP_FIELD_NUMBER: _ClassVar[int]
account: SubscribeUpdateAccountInfo
slot: int
is_startup: bool
def __init__(
self,
account: _Optional[_Union[SubscribeUpdateAccountInfo, _Mapping]] = ...,
slot: _Optional[int] = ...,
is_startup: bool = ...,
) -> None: ...
class SubscribeUpdateAccountInfo(_message.Message):
__slots__ = (
"pubkey",
"lamports",
"owner",
"executable",
"rent_epoch",
"data",
"write_version",
"txn_signature",
)
PUBKEY_FIELD_NUMBER: _ClassVar[int]
LAMPORTS_FIELD_NUMBER: _ClassVar[int]
OWNER_FIELD_NUMBER: _ClassVar[int]
EXECUTABLE_FIELD_NUMBER: _ClassVar[int]
RENT_EPOCH_FIELD_NUMBER: _ClassVar[int]
DATA_FIELD_NUMBER: _ClassVar[int]
WRITE_VERSION_FIELD_NUMBER: _ClassVar[int]
TXN_SIGNATURE_FIELD_NUMBER: _ClassVar[int]
pubkey: bytes
lamports: int
owner: bytes
executable: bool
rent_epoch: int
data: bytes
write_version: int
txn_signature: bytes
def __init__(
self,
pubkey: _Optional[bytes] = ...,
lamports: _Optional[int] = ...,
owner: _Optional[bytes] = ...,
executable: bool = ...,
rent_epoch: _Optional[int] = ...,
data: _Optional[bytes] = ...,
write_version: _Optional[int] = ...,
txn_signature: _Optional[bytes] = ...,
) -> None: ...
class SubscribeUpdateSlot(_message.Message):
__slots__ = ("slot", "parent", "status", "dead_error")
SLOT_FIELD_NUMBER: _ClassVar[int]
PARENT_FIELD_NUMBER: _ClassVar[int]
STATUS_FIELD_NUMBER: _ClassVar[int]
DEAD_ERROR_FIELD_NUMBER: _ClassVar[int]
slot: int
parent: int
status: CommitmentLevel
dead_error: str
def __init__(
self,
slot: _Optional[int] = ...,
parent: _Optional[int] = ...,
status: _Optional[_Union[CommitmentLevel, str]] = ...,
dead_error: _Optional[str] = ...,
) -> None: ...
class SubscribeUpdateTransaction(_message.Message):
__slots__ = ("transaction", "slot")
TRANSACTION_FIELD_NUMBER: _ClassVar[int]
SLOT_FIELD_NUMBER: _ClassVar[int]
transaction: SubscribeUpdateTransactionInfo
slot: int
def __init__(
self,
transaction: _Optional[_Union[SubscribeUpdateTransactionInfo, _Mapping]] = ...,
slot: _Optional[int] = ...,
) -> None: ...
class SubscribeUpdateTransactionInfo(_message.Message):
__slots__ = ("signature", "is_vote", "transaction", "meta", "index")
SIGNATURE_FIELD_NUMBER: _ClassVar[int]
IS_VOTE_FIELD_NUMBER: _ClassVar[int]
TRANSACTION_FIELD_NUMBER: _ClassVar[int]
META_FIELD_NUMBER: _ClassVar[int]
INDEX_FIELD_NUMBER: _ClassVar[int]
signature: bytes
is_vote: bool
transaction: _solana_storage_pb2.Transaction
meta: _solana_storage_pb2.TransactionStatusMeta
index: int
def __init__(
self,
signature: _Optional[bytes] = ...,
is_vote: bool = ...,
transaction: _Optional[_Union[_solana_storage_pb2.Transaction, _Mapping]] = ...,
meta: _Optional[
_Union[_solana_storage_pb2.TransactionStatusMeta, _Mapping]
] = ...,
index: _Optional[int] = ...,
) -> None: ...
class SubscribeUpdateTransactionStatus(_message.Message):
__slots__ = ("slot", "signature", "is_vote", "index", "err")
SLOT_FIELD_NUMBER: _ClassVar[int]
SIGNATURE_FIELD_NUMBER: _ClassVar[int]
IS_VOTE_FIELD_NUMBER: _ClassVar[int]
INDEX_FIELD_NUMBER: _ClassVar[int]
ERR_FIELD_NUMBER: _ClassVar[int]
slot: int
signature: bytes
is_vote: bool
index: int
err: _solana_storage_pb2.TransactionError
def __init__(
self,
slot: _Optional[int] = ...,
signature: _Optional[bytes] = ...,
is_vote: bool = ...,
index: _Optional[int] = ...,
err: _Optional[_Union[_solana_storage_pb2.TransactionError, _Mapping]] = ...,
) -> None: ...
class SubscribeUpdateBlock(_message.Message):
__slots__ = (
"slot",
"blockhash",
"rewards",
"block_time",
"block_height",
"parent_slot",
"parent_blockhash",
"executed_transaction_count",
"transactions",
"updated_account_count",
"accounts",
"entries_count",
"entries",
)
SLOT_FIELD_NUMBER: _ClassVar[int]
BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
REWARDS_FIELD_NUMBER: _ClassVar[int]
BLOCK_TIME_FIELD_NUMBER: _ClassVar[int]
BLOCK_HEIGHT_FIELD_NUMBER: _ClassVar[int]
PARENT_SLOT_FIELD_NUMBER: _ClassVar[int]
PARENT_BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
EXECUTED_TRANSACTION_COUNT_FIELD_NUMBER: _ClassVar[int]
TRANSACTIONS_FIELD_NUMBER: _ClassVar[int]
UPDATED_ACCOUNT_COUNT_FIELD_NUMBER: _ClassVar[int]
ACCOUNTS_FIELD_NUMBER: _ClassVar[int]
ENTRIES_COUNT_FIELD_NUMBER: _ClassVar[int]
ENTRIES_FIELD_NUMBER: _ClassVar[int]
slot: int
blockhash: str
rewards: _solana_storage_pb2.Rewards
block_time: _solana_storage_pb2.UnixTimestamp
block_height: _solana_storage_pb2.BlockHeight
parent_slot: int
parent_blockhash: str
executed_transaction_count: int
transactions: _containers.RepeatedCompositeFieldContainer[
SubscribeUpdateTransactionInfo
]
updated_account_count: int
accounts: _containers.RepeatedCompositeFieldContainer[SubscribeUpdateAccountInfo]
entries_count: int
entries: _containers.RepeatedCompositeFieldContainer[SubscribeUpdateEntry]
def __init__(
self,
slot: _Optional[int] = ...,
blockhash: _Optional[str] = ...,
rewards: _Optional[_Union[_solana_storage_pb2.Rewards, _Mapping]] = ...,
block_time: _Optional[
_Union[_solana_storage_pb2.UnixTimestamp, _Mapping]
] = ...,
block_height: _Optional[
_Union[_solana_storage_pb2.BlockHeight, _Mapping]
] = ...,
parent_slot: _Optional[int] = ...,
parent_blockhash: _Optional[str] = ...,
executed_transaction_count: _Optional[int] = ...,
transactions: _Optional[
_Iterable[_Union[SubscribeUpdateTransactionInfo, _Mapping]]
] = ...,
updated_account_count: _Optional[int] = ...,
accounts: _Optional[
_Iterable[_Union[SubscribeUpdateAccountInfo, _Mapping]]
] = ...,
entries_count: _Optional[int] = ...,
entries: _Optional[_Iterable[_Union[SubscribeUpdateEntry, _Mapping]]] = ...,
) -> None: ...
class SubscribeUpdateBlockMeta(_message.Message):
__slots__ = (
"slot",
"blockhash",
"rewards",
"block_time",
"block_height",
"parent_slot",
"parent_blockhash",
"executed_transaction_count",
"entries_count",
)
SLOT_FIELD_NUMBER: _ClassVar[int]
BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
REWARDS_FIELD_NUMBER: _ClassVar[int]
BLOCK_TIME_FIELD_NUMBER: _ClassVar[int]
BLOCK_HEIGHT_FIELD_NUMBER: _ClassVar[int]
PARENT_SLOT_FIELD_NUMBER: _ClassVar[int]
PARENT_BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
EXECUTED_TRANSACTION_COUNT_FIELD_NUMBER: _ClassVar[int]
ENTRIES_COUNT_FIELD_NUMBER: _ClassVar[int]
slot: int
blockhash: str
rewards: _solana_storage_pb2.Rewards
block_time: _solana_storage_pb2.UnixTimestamp
block_height: _solana_storage_pb2.BlockHeight
parent_slot: int
parent_blockhash: str
executed_transaction_count: int
entries_count: int
def __init__(
self,
slot: _Optional[int] = ...,
blockhash: _Optional[str] = ...,
rewards: _Optional[_Union[_solana_storage_pb2.Rewards, _Mapping]] = ...,
block_time: _Optional[
_Union[_solana_storage_pb2.UnixTimestamp, _Mapping]
] = ...,
block_height: _Optional[
_Union[_solana_storage_pb2.BlockHeight, _Mapping]
] = ...,
parent_slot: _Optional[int] = ...,
parent_blockhash: _Optional[str] = ...,
executed_transaction_count: _Optional[int] = ...,
entries_count: _Optional[int] = ...,
) -> None: ...
class SubscribeUpdateEntry(_message.Message):
__slots__ = (
"slot",
"index",
"num_hashes",
"hash",
"executed_transaction_count",
"starting_transaction_index",
)
SLOT_FIELD_NUMBER: _ClassVar[int]
INDEX_FIELD_NUMBER: _ClassVar[int]
NUM_HASHES_FIELD_NUMBER: _ClassVar[int]
HASH_FIELD_NUMBER: _ClassVar[int]
EXECUTED_TRANSACTION_COUNT_FIELD_NUMBER: _ClassVar[int]
STARTING_TRANSACTION_INDEX_FIELD_NUMBER: _ClassVar[int]
slot: int
index: int
num_hashes: int
hash: bytes
executed_transaction_count: int
starting_transaction_index: int
def __init__(
self,
slot: _Optional[int] = ...,
index: _Optional[int] = ...,
num_hashes: _Optional[int] = ...,
hash: _Optional[bytes] = ...,
executed_transaction_count: _Optional[int] = ...,
starting_transaction_index: _Optional[int] = ...,
) -> None: ...
class SubscribeUpdatePing(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class SubscribeUpdatePong(_message.Message):
__slots__ = ("id",)
ID_FIELD_NUMBER: _ClassVar[int]
id: int
def __init__(self, id: _Optional[int] = ...) -> None: ...
class PingRequest(_message.Message):
__slots__ = ("count",)
COUNT_FIELD_NUMBER: _ClassVar[int]
count: int
def __init__(self, count: _Optional[int] = ...) -> None: ...
class PongResponse(_message.Message):
__slots__ = ("count",)
COUNT_FIELD_NUMBER: _ClassVar[int]
count: int
def __init__(self, count: _Optional[int] = ...) -> None: ...
class GetLatestBlockhashRequest(_message.Message):
__slots__ = ("commitment",)
COMMITMENT_FIELD_NUMBER: _ClassVar[int]
commitment: CommitmentLevel
def __init__(
self, commitment: _Optional[_Union[CommitmentLevel, str]] = ...
) -> None: ...
class GetLatestBlockhashResponse(_message.Message):
__slots__ = ("slot", "blockhash", "last_valid_block_height")
SLOT_FIELD_NUMBER: _ClassVar[int]
BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
LAST_VALID_BLOCK_HEIGHT_FIELD_NUMBER: _ClassVar[int]
slot: int
blockhash: str
last_valid_block_height: int
def __init__(
self,
slot: _Optional[int] = ...,
blockhash: _Optional[str] = ...,
last_valid_block_height: _Optional[int] = ...,
) -> None: ...
class GetBlockHeightRequest(_message.Message):
__slots__ = ("commitment",)
COMMITMENT_FIELD_NUMBER: _ClassVar[int]
commitment: CommitmentLevel
def __init__(
self, commitment: _Optional[_Union[CommitmentLevel, str]] = ...
) -> None: ...
class GetBlockHeightResponse(_message.Message):
__slots__ = ("block_height",)
BLOCK_HEIGHT_FIELD_NUMBER: _ClassVar[int]
block_height: int
def __init__(self, block_height: _Optional[int] = ...) -> None: ...
class GetSlotRequest(_message.Message):
__slots__ = ("commitment",)
COMMITMENT_FIELD_NUMBER: _ClassVar[int]
commitment: CommitmentLevel
def __init__(
self, commitment: _Optional[_Union[CommitmentLevel, str]] = ...
) -> None: ...
class GetSlotResponse(_message.Message):
__slots__ = ("slot",)
SLOT_FIELD_NUMBER: _ClassVar[int]
slot: int
def __init__(self, slot: _Optional[int] = ...) -> None: ...
class GetVersionRequest(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class GetVersionResponse(_message.Message):
__slots__ = ("version",)
VERSION_FIELD_NUMBER: _ClassVar[int]
version: str
def __init__(self, version: _Optional[str] = ...) -> None: ...
class IsBlockhashValidRequest(_message.Message):
__slots__ = ("blockhash", "commitment")
BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
COMMITMENT_FIELD_NUMBER: _ClassVar[int]
blockhash: str
commitment: CommitmentLevel
def __init__(
self,
blockhash: _Optional[str] = ...,
commitment: _Optional[_Union[CommitmentLevel, str]] = ...,
) -> None: ...
class IsBlockhashValidResponse(_message.Message):
__slots__ = ("slot", "valid")
SLOT_FIELD_NUMBER: _ClassVar[int]
VALID_FIELD_NUMBER: _ClassVar[int]
slot: int
valid: bool
def __init__(self, slot: _Optional[int] = ..., valid: bool = ...) -> None: ...
@@ -1,387 +0,0 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import generated.geyser_pb2 as geyser__pb2
GRPC_GENERATED_VERSION = "1.71.0"
GRPC_VERSION = grpc.__version__
_version_not_supported = False
try:
from grpc._utilities import first_version_is_lower
_version_not_supported = first_version_is_lower(
GRPC_VERSION, GRPC_GENERATED_VERSION
)
except ImportError:
_version_not_supported = True
if _version_not_supported:
raise RuntimeError(
f"The grpc package installed is at version {GRPC_VERSION},"
+ " but the generated code in geyser_pb2_grpc.py depends on"
+ f" grpcio>={GRPC_GENERATED_VERSION}."
+ f" Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}"
+ f" or downgrade your generated code using grpcio-tools<={GRPC_VERSION}."
)
class GeyserStub:
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Subscribe = channel.stream_stream(
"/geyser.Geyser/Subscribe",
request_serializer=geyser__pb2.SubscribeRequest.SerializeToString,
response_deserializer=geyser__pb2.SubscribeUpdate.FromString,
_registered_method=True,
)
self.Ping = channel.unary_unary(
"/geyser.Geyser/Ping",
request_serializer=geyser__pb2.PingRequest.SerializeToString,
response_deserializer=geyser__pb2.PongResponse.FromString,
_registered_method=True,
)
self.GetLatestBlockhash = channel.unary_unary(
"/geyser.Geyser/GetLatestBlockhash",
request_serializer=geyser__pb2.GetLatestBlockhashRequest.SerializeToString,
response_deserializer=geyser__pb2.GetLatestBlockhashResponse.FromString,
_registered_method=True,
)
self.GetBlockHeight = channel.unary_unary(
"/geyser.Geyser/GetBlockHeight",
request_serializer=geyser__pb2.GetBlockHeightRequest.SerializeToString,
response_deserializer=geyser__pb2.GetBlockHeightResponse.FromString,
_registered_method=True,
)
self.GetSlot = channel.unary_unary(
"/geyser.Geyser/GetSlot",
request_serializer=geyser__pb2.GetSlotRequest.SerializeToString,
response_deserializer=geyser__pb2.GetSlotResponse.FromString,
_registered_method=True,
)
self.IsBlockhashValid = channel.unary_unary(
"/geyser.Geyser/IsBlockhashValid",
request_serializer=geyser__pb2.IsBlockhashValidRequest.SerializeToString,
response_deserializer=geyser__pb2.IsBlockhashValidResponse.FromString,
_registered_method=True,
)
self.GetVersion = channel.unary_unary(
"/geyser.Geyser/GetVersion",
request_serializer=geyser__pb2.GetVersionRequest.SerializeToString,
response_deserializer=geyser__pb2.GetVersionResponse.FromString,
_registered_method=True,
)
class GeyserServicer:
"""Missing associated documentation comment in .proto file."""
def Subscribe(self, request_iterator, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details("Method not implemented!")
raise NotImplementedError("Method not implemented!")
def Ping(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details("Method not implemented!")
raise NotImplementedError("Method not implemented!")
def GetLatestBlockhash(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details("Method not implemented!")
raise NotImplementedError("Method not implemented!")
def GetBlockHeight(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details("Method not implemented!")
raise NotImplementedError("Method not implemented!")
def GetSlot(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details("Method not implemented!")
raise NotImplementedError("Method not implemented!")
def IsBlockhashValid(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details("Method not implemented!")
raise NotImplementedError("Method not implemented!")
def GetVersion(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details("Method not implemented!")
raise NotImplementedError("Method not implemented!")
def add_GeyserServicer_to_server(servicer, server):
rpc_method_handlers = {
"Subscribe": grpc.stream_stream_rpc_method_handler(
servicer.Subscribe,
request_deserializer=geyser__pb2.SubscribeRequest.FromString,
response_serializer=geyser__pb2.SubscribeUpdate.SerializeToString,
),
"Ping": grpc.unary_unary_rpc_method_handler(
servicer.Ping,
request_deserializer=geyser__pb2.PingRequest.FromString,
response_serializer=geyser__pb2.PongResponse.SerializeToString,
),
"GetLatestBlockhash": grpc.unary_unary_rpc_method_handler(
servicer.GetLatestBlockhash,
request_deserializer=geyser__pb2.GetLatestBlockhashRequest.FromString,
response_serializer=geyser__pb2.GetLatestBlockhashResponse.SerializeToString,
),
"GetBlockHeight": grpc.unary_unary_rpc_method_handler(
servicer.GetBlockHeight,
request_deserializer=geyser__pb2.GetBlockHeightRequest.FromString,
response_serializer=geyser__pb2.GetBlockHeightResponse.SerializeToString,
),
"GetSlot": grpc.unary_unary_rpc_method_handler(
servicer.GetSlot,
request_deserializer=geyser__pb2.GetSlotRequest.FromString,
response_serializer=geyser__pb2.GetSlotResponse.SerializeToString,
),
"IsBlockhashValid": grpc.unary_unary_rpc_method_handler(
servicer.IsBlockhashValid,
request_deserializer=geyser__pb2.IsBlockhashValidRequest.FromString,
response_serializer=geyser__pb2.IsBlockhashValidResponse.SerializeToString,
),
"GetVersion": grpc.unary_unary_rpc_method_handler(
servicer.GetVersion,
request_deserializer=geyser__pb2.GetVersionRequest.FromString,
response_serializer=geyser__pb2.GetVersionResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
"geyser.Geyser", rpc_method_handlers
)
server.add_generic_rpc_handlers((generic_handler,))
server.add_registered_method_handlers("geyser.Geyser", rpc_method_handlers)
# This class is part of an EXPERIMENTAL API.
class Geyser:
"""Missing associated documentation comment in .proto file."""
@staticmethod
def Subscribe(
request_iterator,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None,
):
return grpc.experimental.stream_stream(
request_iterator,
target,
"/geyser.Geyser/Subscribe",
geyser__pb2.SubscribeRequest.SerializeToString,
geyser__pb2.SubscribeUpdate.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True,
)
@staticmethod
def Ping(
request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None,
):
return grpc.experimental.unary_unary(
request,
target,
"/geyser.Geyser/Ping",
geyser__pb2.PingRequest.SerializeToString,
geyser__pb2.PongResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True,
)
@staticmethod
def GetLatestBlockhash(
request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None,
):
return grpc.experimental.unary_unary(
request,
target,
"/geyser.Geyser/GetLatestBlockhash",
geyser__pb2.GetLatestBlockhashRequest.SerializeToString,
geyser__pb2.GetLatestBlockhashResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True,
)
@staticmethod
def GetBlockHeight(
request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None,
):
return grpc.experimental.unary_unary(
request,
target,
"/geyser.Geyser/GetBlockHeight",
geyser__pb2.GetBlockHeightRequest.SerializeToString,
geyser__pb2.GetBlockHeightResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True,
)
@staticmethod
def GetSlot(
request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None,
):
return grpc.experimental.unary_unary(
request,
target,
"/geyser.Geyser/GetSlot",
geyser__pb2.GetSlotRequest.SerializeToString,
geyser__pb2.GetSlotResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True,
)
@staticmethod
def IsBlockhashValid(
request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None,
):
return grpc.experimental.unary_unary(
request,
target,
"/geyser.Geyser/IsBlockhashValid",
geyser__pb2.IsBlockhashValidRequest.SerializeToString,
geyser__pb2.IsBlockhashValidResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True,
)
@staticmethod
def GetVersion(
request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None,
):
return grpc.experimental.unary_unary(
request,
target,
"/geyser.Geyser/GetVersion",
geyser__pb2.GetVersionRequest.SerializeToString,
geyser__pb2.GetVersionResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True,
)
File diff suppressed because one or more lines are too long
@@ -1,385 +0,0 @@
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import (
ClassVar as _ClassVar,
Iterable as _Iterable,
Mapping as _Mapping,
Optional as _Optional,
Union as _Union,
)
DESCRIPTOR: _descriptor.FileDescriptor
class RewardType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
Unspecified: _ClassVar[RewardType]
Fee: _ClassVar[RewardType]
Rent: _ClassVar[RewardType]
Staking: _ClassVar[RewardType]
Voting: _ClassVar[RewardType]
Unspecified: RewardType
Fee: RewardType
Rent: RewardType
Staking: RewardType
Voting: RewardType
class ConfirmedBlock(_message.Message):
__slots__ = (
"previous_blockhash",
"blockhash",
"parent_slot",
"transactions",
"rewards",
"block_time",
"block_height",
"num_partitions",
)
PREVIOUS_BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
PARENT_SLOT_FIELD_NUMBER: _ClassVar[int]
TRANSACTIONS_FIELD_NUMBER: _ClassVar[int]
REWARDS_FIELD_NUMBER: _ClassVar[int]
BLOCK_TIME_FIELD_NUMBER: _ClassVar[int]
BLOCK_HEIGHT_FIELD_NUMBER: _ClassVar[int]
NUM_PARTITIONS_FIELD_NUMBER: _ClassVar[int]
previous_blockhash: str
blockhash: str
parent_slot: int
transactions: _containers.RepeatedCompositeFieldContainer[ConfirmedTransaction]
rewards: _containers.RepeatedCompositeFieldContainer[Reward]
block_time: UnixTimestamp
block_height: BlockHeight
num_partitions: NumPartitions
def __init__(
self,
previous_blockhash: _Optional[str] = ...,
blockhash: _Optional[str] = ...,
parent_slot: _Optional[int] = ...,
transactions: _Optional[
_Iterable[_Union[ConfirmedTransaction, _Mapping]]
] = ...,
rewards: _Optional[_Iterable[_Union[Reward, _Mapping]]] = ...,
block_time: _Optional[_Union[UnixTimestamp, _Mapping]] = ...,
block_height: _Optional[_Union[BlockHeight, _Mapping]] = ...,
num_partitions: _Optional[_Union[NumPartitions, _Mapping]] = ...,
) -> None: ...
class ConfirmedTransaction(_message.Message):
__slots__ = ("transaction", "meta")
TRANSACTION_FIELD_NUMBER: _ClassVar[int]
META_FIELD_NUMBER: _ClassVar[int]
transaction: Transaction
meta: TransactionStatusMeta
def __init__(
self,
transaction: _Optional[_Union[Transaction, _Mapping]] = ...,
meta: _Optional[_Union[TransactionStatusMeta, _Mapping]] = ...,
) -> None: ...
class Transaction(_message.Message):
__slots__ = ("signatures", "message")
SIGNATURES_FIELD_NUMBER: _ClassVar[int]
MESSAGE_FIELD_NUMBER: _ClassVar[int]
signatures: _containers.RepeatedScalarFieldContainer[bytes]
message: Message
def __init__(
self,
signatures: _Optional[_Iterable[bytes]] = ...,
message: _Optional[_Union[Message, _Mapping]] = ...,
) -> None: ...
class Message(_message.Message):
__slots__ = (
"header",
"account_keys",
"recent_blockhash",
"instructions",
"versioned",
"address_table_lookups",
)
HEADER_FIELD_NUMBER: _ClassVar[int]
ACCOUNT_KEYS_FIELD_NUMBER: _ClassVar[int]
RECENT_BLOCKHASH_FIELD_NUMBER: _ClassVar[int]
INSTRUCTIONS_FIELD_NUMBER: _ClassVar[int]
VERSIONED_FIELD_NUMBER: _ClassVar[int]
ADDRESS_TABLE_LOOKUPS_FIELD_NUMBER: _ClassVar[int]
header: MessageHeader
account_keys: _containers.RepeatedScalarFieldContainer[bytes]
recent_blockhash: bytes
instructions: _containers.RepeatedCompositeFieldContainer[CompiledInstruction]
versioned: bool
address_table_lookups: _containers.RepeatedCompositeFieldContainer[
MessageAddressTableLookup
]
def __init__(
self,
header: _Optional[_Union[MessageHeader, _Mapping]] = ...,
account_keys: _Optional[_Iterable[bytes]] = ...,
recent_blockhash: _Optional[bytes] = ...,
instructions: _Optional[_Iterable[_Union[CompiledInstruction, _Mapping]]] = ...,
versioned: bool = ...,
address_table_lookups: _Optional[
_Iterable[_Union[MessageAddressTableLookup, _Mapping]]
] = ...,
) -> None: ...
class MessageHeader(_message.Message):
__slots__ = (
"num_required_signatures",
"num_readonly_signed_accounts",
"num_readonly_unsigned_accounts",
)
NUM_REQUIRED_SIGNATURES_FIELD_NUMBER: _ClassVar[int]
NUM_READONLY_SIGNED_ACCOUNTS_FIELD_NUMBER: _ClassVar[int]
NUM_READONLY_UNSIGNED_ACCOUNTS_FIELD_NUMBER: _ClassVar[int]
num_required_signatures: int
num_readonly_signed_accounts: int
num_readonly_unsigned_accounts: int
def __init__(
self,
num_required_signatures: _Optional[int] = ...,
num_readonly_signed_accounts: _Optional[int] = ...,
num_readonly_unsigned_accounts: _Optional[int] = ...,
) -> None: ...
class MessageAddressTableLookup(_message.Message):
__slots__ = ("account_key", "writable_indexes", "readonly_indexes")
ACCOUNT_KEY_FIELD_NUMBER: _ClassVar[int]
WRITABLE_INDEXES_FIELD_NUMBER: _ClassVar[int]
READONLY_INDEXES_FIELD_NUMBER: _ClassVar[int]
account_key: bytes
writable_indexes: bytes
readonly_indexes: bytes
def __init__(
self,
account_key: _Optional[bytes] = ...,
writable_indexes: _Optional[bytes] = ...,
readonly_indexes: _Optional[bytes] = ...,
) -> None: ...
class TransactionStatusMeta(_message.Message):
__slots__ = (
"err",
"fee",
"pre_balances",
"post_balances",
"inner_instructions",
"inner_instructions_none",
"log_messages",
"log_messages_none",
"pre_token_balances",
"post_token_balances",
"rewards",
"loaded_writable_addresses",
"loaded_readonly_addresses",
"return_data",
"return_data_none",
"compute_units_consumed",
)
ERR_FIELD_NUMBER: _ClassVar[int]
FEE_FIELD_NUMBER: _ClassVar[int]
PRE_BALANCES_FIELD_NUMBER: _ClassVar[int]
POST_BALANCES_FIELD_NUMBER: _ClassVar[int]
INNER_INSTRUCTIONS_FIELD_NUMBER: _ClassVar[int]
INNER_INSTRUCTIONS_NONE_FIELD_NUMBER: _ClassVar[int]
LOG_MESSAGES_FIELD_NUMBER: _ClassVar[int]
LOG_MESSAGES_NONE_FIELD_NUMBER: _ClassVar[int]
PRE_TOKEN_BALANCES_FIELD_NUMBER: _ClassVar[int]
POST_TOKEN_BALANCES_FIELD_NUMBER: _ClassVar[int]
REWARDS_FIELD_NUMBER: _ClassVar[int]
LOADED_WRITABLE_ADDRESSES_FIELD_NUMBER: _ClassVar[int]
LOADED_READONLY_ADDRESSES_FIELD_NUMBER: _ClassVar[int]
RETURN_DATA_FIELD_NUMBER: _ClassVar[int]
RETURN_DATA_NONE_FIELD_NUMBER: _ClassVar[int]
COMPUTE_UNITS_CONSUMED_FIELD_NUMBER: _ClassVar[int]
err: TransactionError
fee: int
pre_balances: _containers.RepeatedScalarFieldContainer[int]
post_balances: _containers.RepeatedScalarFieldContainer[int]
inner_instructions: _containers.RepeatedCompositeFieldContainer[InnerInstructions]
inner_instructions_none: bool
log_messages: _containers.RepeatedScalarFieldContainer[str]
log_messages_none: bool
pre_token_balances: _containers.RepeatedCompositeFieldContainer[TokenBalance]
post_token_balances: _containers.RepeatedCompositeFieldContainer[TokenBalance]
rewards: _containers.RepeatedCompositeFieldContainer[Reward]
loaded_writable_addresses: _containers.RepeatedScalarFieldContainer[bytes]
loaded_readonly_addresses: _containers.RepeatedScalarFieldContainer[bytes]
return_data: ReturnData
return_data_none: bool
compute_units_consumed: int
def __init__(
self,
err: _Optional[_Union[TransactionError, _Mapping]] = ...,
fee: _Optional[int] = ...,
pre_balances: _Optional[_Iterable[int]] = ...,
post_balances: _Optional[_Iterable[int]] = ...,
inner_instructions: _Optional[
_Iterable[_Union[InnerInstructions, _Mapping]]
] = ...,
inner_instructions_none: bool = ...,
log_messages: _Optional[_Iterable[str]] = ...,
log_messages_none: bool = ...,
pre_token_balances: _Optional[_Iterable[_Union[TokenBalance, _Mapping]]] = ...,
post_token_balances: _Optional[_Iterable[_Union[TokenBalance, _Mapping]]] = ...,
rewards: _Optional[_Iterable[_Union[Reward, _Mapping]]] = ...,
loaded_writable_addresses: _Optional[_Iterable[bytes]] = ...,
loaded_readonly_addresses: _Optional[_Iterable[bytes]] = ...,
return_data: _Optional[_Union[ReturnData, _Mapping]] = ...,
return_data_none: bool = ...,
compute_units_consumed: _Optional[int] = ...,
) -> None: ...
class TransactionError(_message.Message):
__slots__ = ("err",)
ERR_FIELD_NUMBER: _ClassVar[int]
err: bytes
def __init__(self, err: _Optional[bytes] = ...) -> None: ...
class InnerInstructions(_message.Message):
__slots__ = ("index", "instructions")
INDEX_FIELD_NUMBER: _ClassVar[int]
INSTRUCTIONS_FIELD_NUMBER: _ClassVar[int]
index: int
instructions: _containers.RepeatedCompositeFieldContainer[InnerInstruction]
def __init__(
self,
index: _Optional[int] = ...,
instructions: _Optional[_Iterable[_Union[InnerInstruction, _Mapping]]] = ...,
) -> None: ...
class InnerInstruction(_message.Message):
__slots__ = ("program_id_index", "accounts", "data", "stack_height")
PROGRAM_ID_INDEX_FIELD_NUMBER: _ClassVar[int]
ACCOUNTS_FIELD_NUMBER: _ClassVar[int]
DATA_FIELD_NUMBER: _ClassVar[int]
STACK_HEIGHT_FIELD_NUMBER: _ClassVar[int]
program_id_index: int
accounts: bytes
data: bytes
stack_height: int
def __init__(
self,
program_id_index: _Optional[int] = ...,
accounts: _Optional[bytes] = ...,
data: _Optional[bytes] = ...,
stack_height: _Optional[int] = ...,
) -> None: ...
class CompiledInstruction(_message.Message):
__slots__ = ("program_id_index", "accounts", "data")
PROGRAM_ID_INDEX_FIELD_NUMBER: _ClassVar[int]
ACCOUNTS_FIELD_NUMBER: _ClassVar[int]
DATA_FIELD_NUMBER: _ClassVar[int]
program_id_index: int
accounts: bytes
data: bytes
def __init__(
self,
program_id_index: _Optional[int] = ...,
accounts: _Optional[bytes] = ...,
data: _Optional[bytes] = ...,
) -> None: ...
class TokenBalance(_message.Message):
__slots__ = ("account_index", "mint", "ui_token_amount", "owner", "program_id")
ACCOUNT_INDEX_FIELD_NUMBER: _ClassVar[int]
MINT_FIELD_NUMBER: _ClassVar[int]
UI_TOKEN_AMOUNT_FIELD_NUMBER: _ClassVar[int]
OWNER_FIELD_NUMBER: _ClassVar[int]
PROGRAM_ID_FIELD_NUMBER: _ClassVar[int]
account_index: int
mint: str
ui_token_amount: UiTokenAmount
owner: str
program_id: str
def __init__(
self,
account_index: _Optional[int] = ...,
mint: _Optional[str] = ...,
ui_token_amount: _Optional[_Union[UiTokenAmount, _Mapping]] = ...,
owner: _Optional[str] = ...,
program_id: _Optional[str] = ...,
) -> None: ...
class UiTokenAmount(_message.Message):
__slots__ = ("ui_amount", "decimals", "amount", "ui_amount_string")
UI_AMOUNT_FIELD_NUMBER: _ClassVar[int]
DECIMALS_FIELD_NUMBER: _ClassVar[int]
AMOUNT_FIELD_NUMBER: _ClassVar[int]
UI_AMOUNT_STRING_FIELD_NUMBER: _ClassVar[int]
ui_amount: float
decimals: int
amount: str
ui_amount_string: str
def __init__(
self,
ui_amount: _Optional[float] = ...,
decimals: _Optional[int] = ...,
amount: _Optional[str] = ...,
ui_amount_string: _Optional[str] = ...,
) -> None: ...
class ReturnData(_message.Message):
__slots__ = ("program_id", "data")
PROGRAM_ID_FIELD_NUMBER: _ClassVar[int]
DATA_FIELD_NUMBER: _ClassVar[int]
program_id: bytes
data: bytes
def __init__(
self, program_id: _Optional[bytes] = ..., data: _Optional[bytes] = ...
) -> None: ...
class Reward(_message.Message):
__slots__ = ("pubkey", "lamports", "post_balance", "reward_type", "commission")
PUBKEY_FIELD_NUMBER: _ClassVar[int]
LAMPORTS_FIELD_NUMBER: _ClassVar[int]
POST_BALANCE_FIELD_NUMBER: _ClassVar[int]
REWARD_TYPE_FIELD_NUMBER: _ClassVar[int]
COMMISSION_FIELD_NUMBER: _ClassVar[int]
pubkey: str
lamports: int
post_balance: int
reward_type: RewardType
commission: str
def __init__(
self,
pubkey: _Optional[str] = ...,
lamports: _Optional[int] = ...,
post_balance: _Optional[int] = ...,
reward_type: _Optional[_Union[RewardType, str]] = ...,
commission: _Optional[str] = ...,
) -> None: ...
class Rewards(_message.Message):
__slots__ = ("rewards", "num_partitions")
REWARDS_FIELD_NUMBER: _ClassVar[int]
NUM_PARTITIONS_FIELD_NUMBER: _ClassVar[int]
rewards: _containers.RepeatedCompositeFieldContainer[Reward]
num_partitions: NumPartitions
def __init__(
self,
rewards: _Optional[_Iterable[_Union[Reward, _Mapping]]] = ...,
num_partitions: _Optional[_Union[NumPartitions, _Mapping]] = ...,
) -> None: ...
class UnixTimestamp(_message.Message):
__slots__ = ("timestamp",)
TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
timestamp: int
def __init__(self, timestamp: _Optional[int] = ...) -> None: ...
class BlockHeight(_message.Message):
__slots__ = ("block_height",)
BLOCK_HEIGHT_FIELD_NUMBER: _ClassVar[int]
block_height: int
def __init__(self, block_height: _Optional[int] = ...) -> None: ...
class NumPartitions(_message.Message):
__slots__ = ("num_partitions",)
NUM_PARTITIONS_FIELD_NUMBER: _ClassVar[int]
num_partitions: int
def __init__(self, num_partitions: _Optional[int] = ...) -> None: ...
@@ -1,28 +0,0 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import warnings
GRPC_GENERATED_VERSION = "1.71.0"
GRPC_VERSION = grpc.__version__
_version_not_supported = False
try:
from grpc._utilities import first_version_is_lower
_version_not_supported = first_version_is_lower(
GRPC_VERSION, GRPC_GENERATED_VERSION
)
except ImportError:
_version_not_supported = True
if _version_not_supported:
raise RuntimeError(
f"The grpc package installed is at version {GRPC_VERSION},"
+ f" but the generated code in solana_storage_pb2_grpc.py depends on"
+ f" grpcio>={GRPC_GENERATED_VERSION}."
+ f" Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}"
+ f" or downgrade your generated code using grpcio-tools<={GRPC_VERSION}."
)
@@ -382,6 +382,11 @@ async def listen_and_decode_create():
print(
f"Received unexpected message type: {data.get('method', 'Unknown')}"
)
except websockets.ConnectionClosed:
# Leave the recv loop so main() can reconnect. Swallowing this here
# would make the next recv() raise immediately, spinning the loop.
print("WebSocket connection closed.")
break
except Exception as e:
print(f"An error occurred: {e!s}")
print(f"Error details: {type(e).__name__}")
@@ -389,8 +394,17 @@ async def listen_and_decode_create():
traceback.print_exc()
print("WebSocket connection closed.")
async def main() -> None:
"""Reconnect for as long as the script runs."""
while True:
try:
await listen_and_decode_create()
except (websockets.WebSocketException, OSError) as e:
print(f"Connection error: {e!s}")
print("Reconnecting in 5 seconds...")
await asyncio.sleep(5)
if __name__ == "__main__":
asyncio.run(listen_and_decode_create())
asyncio.run(main())
@@ -18,13 +18,19 @@ Configure via GEYSER_ENDPOINT, GEYSER_API_TOKEN, and AUTH_TYPE variables.
import asyncio
import os
import struct
import sys
from pathlib import Path
import base58
import grpc
from dotenv import load_dotenv
from generated import geyser_pb2, geyser_pb2_grpc
from solders.pubkey import Pubkey
# The geyser stubs are generated once, into src/geyser/generated. Reuse them rather
# than keeping a second copy here that drifts out of sync with proto/.
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from src.geyser.generated import geyser_pb2, geyser_pb2_grpc
load_dotenv()
@@ -106,6 +112,31 @@ def create_subscription_request():
return request
def resolve_account_keys(
tx: geyser_pb2.SubscribeUpdateTransactionInfo,
) -> list[bytes]:
"""Build the full account-key table for one transaction.
A v0 transaction indexes accounts past the end of `message.account_keys` when it
uses an address lookup table; geyser reports those in the transaction meta, in
this exact order: static keys, then writable loaded, then read-only loaded.
Coins minted through a router (most of them) arrive this way, so a listener that
only reads `message.account_keys` mislabels or drops them.
Args:
tx: A geyser `SubscribeUpdateTransactionInfo`
Returns:
Account keys as raw 32-byte values, indexable by an instruction's account list
"""
keys = list(tx.transaction.message.account_keys)
meta = getattr(tx, "meta", None)
if meta is not None:
keys.extend(meta.loaded_writable_addresses)
keys.extend(meta.loaded_readonly_addresses)
return keys
def decode_create_instruction(ix_data: bytes, keys, accounts) -> dict:
"""Decode a legacy create instruction (Metaplex) from transaction data."""
# Skip past the 8-byte discriminator prefix
@@ -116,6 +147,12 @@ def decode_create_instruction(ix_data: bytes, keys, accounts) -> dict:
if index >= len(accounts):
return "N/A"
account_index = accounts[index]
# A v0 transaction can index accounts that live in an address lookup table,
# which geyser reports under meta.loaded_*_addresses rather than
# message.account_keys. Without this guard those coins raise IndexError and
# kill the listener.
if account_index >= len(keys):
return "N/A"
return base58.b58encode(keys[account_index]).decode()
# Read string fields (prefixed with length)
@@ -170,6 +207,12 @@ def decode_create_v2_instruction(ix_data: bytes, keys, accounts) -> dict:
if index >= len(accounts):
return "N/A"
account_index = accounts[index]
# A v0 transaction can index accounts that live in an address lookup table,
# which geyser reports under meta.loaded_*_addresses rather than
# message.account_keys. Without this guard those coins raise IndexError and
# kill the listener.
if account_index >= len(keys):
return "N/A"
return base58.b58encode(keys[account_index]).decode()
# Read string fields (prefixed with length)
@@ -238,6 +281,8 @@ async def monitor_pump():
if msg is None:
continue
keys = resolve_account_keys(update.transaction.transaction)
# Check each instruction in the transaction
for ix in msg.instructions:
# Check for both Create and CreateV2 instructions
@@ -249,11 +294,9 @@ async def monitor_pump():
# Decode based on instruction type
if is_create_v2:
info = decode_create_v2_instruction(
ix.data, msg.account_keys, ix.accounts
)
info = decode_create_v2_instruction(ix.data, keys, ix.accounts)
else:
info = decode_create_instruction(ix.data, msg.account_keys, ix.accounts)
info = decode_create_instruction(ix.data, keys, ix.accounts)
# Extract transaction signature
signature = base58.b58encode(
@@ -6,13 +6,17 @@ Performance: Usually faster than blockSubscribe, but slower than Geyser.
This script uses logsSubscribe which receives program logs containing event data.
Event logs include all token fields directly, making parsing simpler and faster than
decoding full transactions.
decoding full transactions. It also derives each coin's associated bonding curve,
which is the token account the curve holds its supply in.
WebSocket API Reference:
https://solana.com/docs/rpc/websocket/logssubscribe
Program Logs and Events:
https://solana.com/docs/programs/debugging#logging
Program Derived Addresses:
https://solana.com/docs/core/pda
"""
import asyncio
@@ -36,19 +40,32 @@ WSS_ENDPOINT = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
WEBSOCKET_MAX_MESSAGE_BYTES = 32 * 1024 * 1024
PUMP_PROGRAM_ID = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
# Coins created with `create_v2` are Token2022; legacy `create` coins are SPL Token.
# The associated bonding curve is an ATA, and an ATA's address depends on which token
# program owns the mint — deriving a Token2022 coin's ATA against the legacy program
# yields a valid-looking address that does not exist on chain.
TOKEN_PROGRAM_ID = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
TOKEN_2022_PROGRAM_ID = Pubkey.from_string("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb")
ASSOCIATED_TOKEN_PROGRAM_ID = Pubkey.from_string(
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
)
# Event discriminator for CreateEvent (8-byte identifier)
# This is emitted by both Create and CreateV2 instructions
# Calculated using the first 8 bytes of sha256("event:CreateEvent")
CREATE_EVENT_DISCRIMINATOR = bytes([27, 114, 169, 77, 222, 235, 99, 118])
def print_token_info(token_data, signature=None):
def print_token_info(
token_data, signature=None, associated_bonding_curve: str | None = None
):
"""
Print token information in a consistent, user-friendly format.
Args:
token_data: Dictionary containing token fields
signature: Optional transaction signature
associated_bonding_curve: Optional derived associated bonding curve address
"""
print("\n" + "=" * 80)
print("🎯 NEW TOKEN DETECTED")
@@ -59,6 +76,8 @@ def print_token_info(token_data, signature=None):
if "bondingCurve" in token_data:
print(f"Bonding Curve: {token_data['bondingCurve']}")
if associated_bonding_curve:
print(f"Associated BC: {associated_bonding_curve}")
if "user" in token_data:
print(f"User: {token_data['user']}")
if "creator" in token_data:
@@ -76,6 +95,36 @@ def print_token_info(token_data, signature=None):
def find_associated_bonding_curve(
mint: Pubkey, bonding_curve: Pubkey, token_standard: str
) -> Pubkey:
"""
Derive the associated token account the bonding curve holds its supply in.
ATA derivation: find_program_address(
[bonding_curve, token_program_id, mint], associated_token_program_id
)
Args:
mint: The token mint pubkey
bonding_curve: The bonding curve pubkey
token_standard: "token2022" for create_v2 coins, anything else for legacy
Returns:
The derived associated bonding curve address
"""
token_program = (
TOKEN_2022_PROGRAM_ID
if token_standard == "token2022" # noqa: S105 - a token standard, not a secret
else TOKEN_PROGRAM_ID
)
derived_address, _ = Pubkey.find_program_address(
[bytes(bonding_curve), bytes(token_program), bytes(mint)],
ASSOCIATED_TOKEN_PROGRAM_ID,
)
return derived_address
def parse_create_instruction(data):
"""
Parse CreateEvent data from legacy Create instruction (Metaplex tokens).
@@ -236,22 +285,30 @@ async def listen_for_new_tokens():
# Both create and create_v2 emit the same CreateEvent
# The difference is in the optional is_mayhem_mode field
if is_create_v2:
print("📝 Instruction: CreateV2 (Token2022)")
parsed_data = parse_create_v2_instruction(
decoded_data
)
else:
print("📝 Instruction: Create (Legacy/Metaplex)")
parsed_data = parse_create_instruction(
decoded_data
)
if parsed_data and "name" in parsed_data:
associated_curve = find_associated_bonding_curve(
Pubkey.from_string(parsed_data["mint"]),
Pubkey.from_string(parsed_data["bondingCurve"]),
parsed_data.get("token_standard", ""),
)
# Print token information in consistent format
print_token_info(
parsed_data,
signature=log_data.get("signature")
signature=log_data.get("signature"),
associated_bonding_curve=str(associated_curve),
)
else:
print(f"⚠️ Parsing failed for CreateEvent")
print("⚠️ Parsing failed for CreateEvent")
except Exception as e:
print(f"❌ Error processing log: {e!s}")
@@ -1,303 +0,0 @@
"""
Listens for new Pump.fun token creations via Solana WebSocket.
Monitors logs for 'Create' instructions, decodes and prints token details (name, symbol, mint, etc.).
Additionally, calculates the associated bonding curve address for each token using PDA derivation.
Performance: Usually faster than blockSubscribe, but slower than Geyser.
This script demonstrates Program Derived Address (PDA) calculation for the associated
bonding curve, which is the token account owned by the bonding curve that holds
the minted tokens.
WebSocket API Reference:
https://solana.com/docs/rpc/websocket/logssubscribe
Program Derived Addresses:
https://solana.com/docs/core/pda
"""
import asyncio
import base64
import json
import os
import struct
import base58
import websockets
from dotenv import load_dotenv
from solders.pubkey import Pubkey
load_dotenv()
WSS_ENDPOINT = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
# Solana's blockSubscribe (and a busy logsSubscribe) sends frames well past
# websockets' 1 MiB default, which kills the connection with a 1009 close
# instead of delivering the message. Same value the bot's own listeners use.
WEBSOCKET_MAX_MESSAGE_BYTES = 32 * 1024 * 1024
PUMP_PROGRAM_ID = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
TOKEN_PROGRAM_ID = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
ASSOCIATED_TOKEN_PROGRAM_ID = Pubkey.from_string(
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
)
# Event discriminator for CreateEvent (8-byte identifier)
# This is emitted by both Create and CreateV2 instructions
# Calculated using the first 8 bytes of sha256("event:CreateEvent")
CREATE_EVENT_DISCRIMINATOR = bytes([27, 114, 169, 77, 222, 235, 99, 118])
def print_token_info(token_data, signature=None, associated_bonding_curve=None):
"""
Print token information in a consistent, user-friendly format.
Args:
token_data: Dictionary containing token fields
signature: Optional transaction signature
associated_bonding_curve: Optional associated bonding curve address
"""
print("\n" + "=" * 80)
print("🎯 NEW TOKEN DETECTED")
print("=" * 80)
print(f"Name: {token_data.get('name', 'N/A')}")
print(f"Symbol: {token_data.get('symbol', 'N/A')}")
print(f"Mint: {token_data.get('mint', 'N/A')}")
if "bondingCurve" in token_data:
print(f"Bonding Curve: {token_data['bondingCurve']}")
if associated_bonding_curve:
print(f"Associated BC: {associated_bonding_curve}")
if "user" in token_data:
print(f"User: {token_data['user']}")
if "creator" in token_data:
print(f"Creator: {token_data['creator']}")
print(f"Token Standard: {token_data.get('token_standard', 'N/A')}")
print(f"Mayhem Mode: {token_data.get('is_mayhem_mode', False)}")
if "uri" in token_data:
print(f"URI: {token_data['uri']}")
if signature:
print(f"Signature: {signature}")
print("=" * 80 + "\n")
def find_associated_bonding_curve(mint: Pubkey, bonding_curve: Pubkey) -> Pubkey:
"""
Calculate the associated token account (ATA) address for the bonding curve.
The associated bonding curve is a Program Derived Address (PDA) that holds
the token supply controlled by the bonding curve. It's derived using the
standard Associated Token Account (ATA) derivation.
ATA Derivation: find_program_address(
[bonding_curve_pubkey, token_program_id, mint_pubkey],
associated_token_program_id
)
Args:
mint: The token mint pubkey
bonding_curve: The bonding curve pubkey
Returns:
The derived associated bonding curve address
"""
derived_address, _ = Pubkey.find_program_address(
[
bytes(bonding_curve),
bytes(TOKEN_PROGRAM_ID),
bytes(mint),
],
ASSOCIATED_TOKEN_PROGRAM_ID,
)
return derived_address
_CREATE_EVENT_FIELDS = [
("name", "string"),
("symbol", "string"),
("uri", "string"),
("mint", "publicKey"),
("bondingCurve", "publicKey"),
("user", "publicKey"),
("creator", "publicKey"),
("timestamp", "i64"),
("virtual_token_reserves", "u64"),
("virtual_sol_reserves", "u64"),
("real_token_reserves", "u64"),
("token_total_supply", "u64"),
("token_program", "publicKey"),
("is_mayhem_mode", "bool"),
("is_cashback_enabled", "bool"),
]
def _parse_create_event(data, token_standard_hint):
"""Parse a CreateEvent payload (same on-chain layout for both create and create_v2)."""
if len(data) < 8:
print(f"⚠️ Data too short for Create event: {len(data)} bytes")
return None
offset = 8
parsed_data = {}
try:
for field_name, field_type in _CREATE_EVENT_FIELDS:
if field_type == "string":
if offset + 4 > len(data):
raise ValueError(f"Not enough data for {field_name} length at offset {offset}")
length = struct.unpack("<I", data[offset : offset + 4])[0]
offset += 4
if offset + length > len(data):
raise ValueError(f"Not enough data for {field_name} value (length={length}) at offset {offset}")
value = data[offset : offset + length].decode("utf-8")
offset += length
elif field_type == "publicKey":
if offset + 32 > len(data):
raise ValueError(f"Not enough data for {field_name} at offset {offset}")
value = base58.b58encode(data[offset : offset + 32]).decode("utf-8")
offset += 32
elif field_type == "u64":
value = struct.unpack("<Q", data[offset : offset + 8])[0]
offset += 8
elif field_type == "i64":
value = struct.unpack("<q", data[offset : offset + 8])[0]
offset += 8
elif field_type == "bool":
value = bool(data[offset]) if offset < len(data) else False
offset += 1
parsed_data[field_name] = value
parsed_data["token_standard"] = token_standard_hint
return parsed_data
except Exception as e:
print(f"❌ Parse Create event error: {e}")
print(f" Data length: {len(data)} bytes, offset: {offset}")
return None
def parse_create_instruction(data):
"""Parse CreateEvent emitted by legacy Create instruction (Metaplex tokens)."""
return _parse_create_event(data, token_standard_hint="legacy")
def parse_create_v2_instruction(data):
"""Parse CreateEvent emitted by CreateV2 instruction (Token2022 tokens)."""
return _parse_create_event(data, token_standard_hint="token2022")
async def listen_for_new_tokens():
while True:
try:
async with websockets.connect(
WSS_ENDPOINT, max_size=WEBSOCKET_MAX_MESSAGE_BYTES
) as websocket:
subscription_message = json.dumps(
{
"jsonrpc": "2.0",
"id": 1,
"method": "logsSubscribe",
"params": [
{"mentions": [str(PUMP_PROGRAM_ID)]},
{"commitment": "processed"},
],
}
)
await websocket.send(subscription_message)
print(
f"Listening for new token creations from program: {PUMP_PROGRAM_ID}"
)
# Wait for subscription confirmation
response = await websocket.recv()
print(f"Subscription response: {response}")
while True:
try:
response = await websocket.recv()
data = json.loads(response)
if "method" in data and data["method"] == "logsNotification":
log_data = data["params"]["result"]["value"]
logs = log_data.get("logs", [])
# Detect both Create and CreateV2 instructions
is_create = any(
"Program log: Instruction: Create" in log
for log in logs
)
is_create_v2 = any(
"Program log: Instruction: CreateV2" in log
for log in logs
)
if is_create or is_create_v2:
for log in logs:
if "Program data:" in log:
try:
encoded_data = log.split(": ")[1]
decoded_data = base64.b64decode(
encoded_data
)
# Check if this is a CreateEvent by validating discriminator
if len(decoded_data) < 8:
continue
event_discriminator = decoded_data[:8]
if event_discriminator != CREATE_EVENT_DISCRIMINATOR:
# Skip non-CreateEvent logs (e.g., TradeEvent, ExtendAccountEvent)
continue
print(f"\n🔍 Found CreateEvent, length: {len(decoded_data)} bytes")
print(f" Signature: {log_data.get('signature')}")
# Both create and create_v2 emit the same CreateEvent
# The difference is in the optional is_mayhem_mode field
if is_create_v2:
print("📝 Instruction: CreateV2 (Token2022)")
parsed_data = (
parse_create_v2_instruction(
decoded_data
)
)
else:
print("📝 Instruction: Create (Legacy/Metaplex)")
parsed_data = parse_create_instruction(
decoded_data
)
if parsed_data and "name" in parsed_data:
# Calculate associated bonding curve using PDA derivation
mint = Pubkey.from_string(
parsed_data["mint"]
)
bonding_curve = Pubkey.from_string(
parsed_data["bondingCurve"]
)
associated_curve = find_associated_bonding_curve(
mint, bonding_curve
)
# Print token information in consistent format
print_token_info(
parsed_data,
signature=log_data.get("signature"),
associated_bonding_curve=str(associated_curve)
)
else:
print(f"⚠️ Parsing failed for CreateEvent")
except Exception as e:
print(f"❌ Error processing log: {e!s}")
except Exception as e:
print(f"An error occurred while processing message: {e}")
break
except Exception as e:
print(f"Connection error: {e}")
print("Reconnecting in 5 seconds...")
await asyncio.sleep(5)
if __name__ == "__main__":
asyncio.run(listen_for_new_tokens())
@@ -1,262 +0,0 @@
syntax = "proto3";
import public "solana-storage.proto";
option go_package = "github.com/rpcpool/yellowstone-grpc/examples/golang/proto";
package geyser;
service Geyser {
rpc Subscribe(stream SubscribeRequest) returns (stream SubscribeUpdate) {}
rpc Ping(PingRequest) returns (PongResponse) {}
rpc GetLatestBlockhash(GetLatestBlockhashRequest) returns (GetLatestBlockhashResponse) {}
rpc GetBlockHeight(GetBlockHeightRequest) returns (GetBlockHeightResponse) {}
rpc GetSlot(GetSlotRequest) returns (GetSlotResponse) {}
rpc IsBlockhashValid(IsBlockhashValidRequest) returns (IsBlockhashValidResponse) {}
rpc GetVersion(GetVersionRequest) returns (GetVersionResponse) {}
}
enum CommitmentLevel {
PROCESSED = 0;
CONFIRMED = 1;
FINALIZED = 2;
FIRST_SHRED_RECEIVED = 3;
COMPLETED = 4;
CREATED_BANK = 5;
DEAD = 6;
}
message SubscribeRequest {
map<string, SubscribeRequestFilterAccounts> accounts = 1;
map<string, SubscribeRequestFilterSlots> slots = 2;
map<string, SubscribeRequestFilterTransactions> transactions = 3;
map<string, SubscribeRequestFilterTransactions> transactions_status = 10;
map<string, SubscribeRequestFilterBlocks> blocks = 4;
map<string, SubscribeRequestFilterBlocksMeta> blocks_meta = 5;
map<string, SubscribeRequestFilterEntry> entry = 8;
optional CommitmentLevel commitment = 6;
repeated SubscribeRequestAccountsDataSlice accounts_data_slice = 7;
optional SubscribeRequestPing ping = 9;
}
message SubscribeRequestFilterAccounts {
repeated string account = 2;
repeated string owner = 3;
repeated SubscribeRequestFilterAccountsFilter filters = 4;
optional bool nonempty_txn_signature = 5;
}
message SubscribeRequestFilterAccountsFilter {
oneof filter {
SubscribeRequestFilterAccountsFilterMemcmp memcmp = 1;
uint64 datasize = 2;
bool token_account_state = 3;
SubscribeRequestFilterAccountsFilterLamports lamports = 4;
}
}
message SubscribeRequestFilterAccountsFilterMemcmp {
uint64 offset = 1;
oneof data {
bytes bytes = 2;
string base58 = 3;
string base64 = 4;
}
}
message SubscribeRequestFilterAccountsFilterLamports {
oneof cmp {
uint64 eq = 1;
uint64 ne = 2;
uint64 lt = 3;
uint64 gt = 4;
}
}
message SubscribeRequestFilterSlots {
optional bool filter_by_commitment = 1;
}
message SubscribeRequestFilterTransactions {
optional bool vote = 1;
optional bool failed = 2;
optional string signature = 5;
repeated string account_include = 3;
repeated string account_exclude = 4;
repeated string account_required = 6;
}
message SubscribeRequestFilterBlocks {
repeated string account_include = 1;
optional bool include_transactions = 2;
optional bool include_accounts = 3;
optional bool include_entries = 4;
}
message SubscribeRequestFilterBlocksMeta {}
message SubscribeRequestFilterEntry {}
message SubscribeRequestAccountsDataSlice {
uint64 offset = 1;
uint64 length = 2;
}
message SubscribeRequestPing {
int32 id = 1;
}
message SubscribeUpdate {
repeated string filters = 1;
oneof update_oneof {
SubscribeUpdateAccount account = 2;
SubscribeUpdateSlot slot = 3;
SubscribeUpdateTransaction transaction = 4;
SubscribeUpdateTransactionStatus transaction_status = 10;
SubscribeUpdateBlock block = 5;
SubscribeUpdatePing ping = 6;
SubscribeUpdatePong pong = 9;
SubscribeUpdateBlockMeta block_meta = 7;
SubscribeUpdateEntry entry = 8;
}
}
message SubscribeUpdateAccount {
SubscribeUpdateAccountInfo account = 1;
uint64 slot = 2;
bool is_startup = 3;
}
message SubscribeUpdateAccountInfo {
bytes pubkey = 1;
uint64 lamports = 2;
bytes owner = 3;
bool executable = 4;
uint64 rent_epoch = 5;
bytes data = 6;
uint64 write_version = 7;
optional bytes txn_signature = 8;
}
message SubscribeUpdateSlot {
uint64 slot = 1;
optional uint64 parent = 2;
CommitmentLevel status = 3;
optional string dead_error = 4;
}
message SubscribeUpdateTransaction {
SubscribeUpdateTransactionInfo transaction = 1;
uint64 slot = 2;
}
message SubscribeUpdateTransactionInfo {
bytes signature = 1;
bool is_vote = 2;
solana.storage.ConfirmedBlock.Transaction transaction = 3;
solana.storage.ConfirmedBlock.TransactionStatusMeta meta = 4;
uint64 index = 5;
}
message SubscribeUpdateTransactionStatus {
uint64 slot = 1;
bytes signature = 2;
bool is_vote = 3;
uint64 index = 4;
solana.storage.ConfirmedBlock.TransactionError err = 5;
}
message SubscribeUpdateBlock {
uint64 slot = 1;
string blockhash = 2;
solana.storage.ConfirmedBlock.Rewards rewards = 3;
solana.storage.ConfirmedBlock.UnixTimestamp block_time = 4;
solana.storage.ConfirmedBlock.BlockHeight block_height = 5;
uint64 parent_slot = 7;
string parent_blockhash = 8;
uint64 executed_transaction_count = 9;
repeated SubscribeUpdateTransactionInfo transactions = 6;
uint64 updated_account_count = 10;
repeated SubscribeUpdateAccountInfo accounts = 11;
uint64 entries_count = 12;
repeated SubscribeUpdateEntry entries = 13;
}
message SubscribeUpdateBlockMeta {
uint64 slot = 1;
string blockhash = 2;
solana.storage.ConfirmedBlock.Rewards rewards = 3;
solana.storage.ConfirmedBlock.UnixTimestamp block_time = 4;
solana.storage.ConfirmedBlock.BlockHeight block_height = 5;
uint64 parent_slot = 6;
string parent_blockhash = 7;
uint64 executed_transaction_count = 8;
uint64 entries_count = 9;
}
message SubscribeUpdateEntry {
uint64 slot = 1;
uint64 index = 2;
uint64 num_hashes = 3;
bytes hash = 4;
uint64 executed_transaction_count = 5;
uint64 starting_transaction_index = 6; // added in v1.18, for solana 1.17 value is always 0
}
message SubscribeUpdatePing {}
message SubscribeUpdatePong {
int32 id = 1;
}
// non-streaming methods
message PingRequest {
int32 count = 1;
}
message PongResponse {
int32 count = 1;
}
message GetLatestBlockhashRequest {
optional CommitmentLevel commitment = 1;
}
message GetLatestBlockhashResponse {
uint64 slot = 1;
string blockhash = 2;
uint64 last_valid_block_height = 3;
}
message GetBlockHeightRequest {
optional CommitmentLevel commitment = 1;
}
message GetBlockHeightResponse {
uint64 block_height = 1;
}
message GetSlotRequest {
optional CommitmentLevel commitment = 1;
}
message GetSlotResponse {
uint64 slot = 1;
}
message GetVersionRequest {}
message GetVersionResponse {
string version = 1;
}
message IsBlockhashValidRequest {
string blockhash = 1;
optional CommitmentLevel commitment = 2;
}
message IsBlockhashValidResponse {
uint64 slot = 1;
bool valid = 2;
}
@@ -1,149 +0,0 @@
syntax = "proto3";
package solana.storage.ConfirmedBlock;
option go_package = "github.com/rpcpool/yellowstone-grpc/examples/golang/proto";
message ConfirmedBlock {
string previous_blockhash = 1;
string blockhash = 2;
uint64 parent_slot = 3;
repeated ConfirmedTransaction transactions = 4;
repeated Reward rewards = 5;
UnixTimestamp block_time = 6;
BlockHeight block_height = 7;
NumPartitions num_partitions = 8;
}
message ConfirmedTransaction {
Transaction transaction = 1;
TransactionStatusMeta meta = 2;
}
message Transaction {
repeated bytes signatures = 1;
Message message = 2;
}
message Message {
MessageHeader header = 1;
repeated bytes account_keys = 2;
bytes recent_blockhash = 3;
repeated CompiledInstruction instructions = 4;
bool versioned = 5;
repeated MessageAddressTableLookup address_table_lookups = 6;
}
message MessageHeader {
uint32 num_required_signatures = 1;
uint32 num_readonly_signed_accounts = 2;
uint32 num_readonly_unsigned_accounts = 3;
}
message MessageAddressTableLookup {
bytes account_key = 1;
bytes writable_indexes = 2;
bytes readonly_indexes = 3;
}
message TransactionStatusMeta {
TransactionError err = 1;
uint64 fee = 2;
repeated uint64 pre_balances = 3;
repeated uint64 post_balances = 4;
repeated InnerInstructions inner_instructions = 5;
bool inner_instructions_none = 10;
repeated string log_messages = 6;
bool log_messages_none = 11;
repeated TokenBalance pre_token_balances = 7;
repeated TokenBalance post_token_balances = 8;
repeated Reward rewards = 9;
repeated bytes loaded_writable_addresses = 12;
repeated bytes loaded_readonly_addresses = 13;
ReturnData return_data = 14;
bool return_data_none = 15;
// Sum of compute units consumed by all instructions.
// Available since Solana v1.10.35 / v1.11.6.
// Set to `None` for txs executed on earlier versions.
optional uint64 compute_units_consumed = 16;
}
message TransactionError {
bytes err = 1;
}
message InnerInstructions {
uint32 index = 1;
repeated InnerInstruction instructions = 2;
}
message InnerInstruction {
uint32 program_id_index = 1;
bytes accounts = 2;
bytes data = 3;
// Invocation stack height of an inner instruction.
// Available since Solana v1.14.6
// Set to `None` for txs executed on earlier versions.
optional uint32 stack_height = 4;
}
message CompiledInstruction {
uint32 program_id_index = 1;
bytes accounts = 2;
bytes data = 3;
}
message TokenBalance {
uint32 account_index = 1;
string mint = 2;
UiTokenAmount ui_token_amount = 3;
string owner = 4;
string program_id = 5;
}
message UiTokenAmount {
double ui_amount = 1;
uint32 decimals = 2;
string amount = 3;
string ui_amount_string = 4;
}
message ReturnData {
bytes program_id = 1;
bytes data = 2;
}
enum RewardType {
Unspecified = 0;
Fee = 1;
Rent = 2;
Staking = 3;
Voting = 4;
}
message Reward {
string pubkey = 1;
int64 lamports = 2;
uint64 post_balance = 3;
RewardType reward_type = 4;
string commission = 5;
}
message Rewards {
repeated Reward rewards = 1;
NumPartitions num_partitions = 2;
}
message UnixTimestamp {
int64 timestamp = 1;
}
message BlockHeight {
uint64 block_height = 1;
}
message NumPartitions {
uint64 num_partitions = 1;
}
+60 -3
View File
@@ -1,9 +1,31 @@
"""Buy the next pump.fun coin to be created, using buy_v2.
WARNING: this submits a real transaction and spends real funds.
Usage:
uv run learning-examples/manual_buy.py
uv run learning-examples/manual_buy.py --cu-optimized
`--cu-optimized` adds a SetLoadedAccountsDataSizeLimit instruction. A transaction
may load up to 64 MB of account data by default, which is billed at 16k CU toward
the fee and priority calculation. Declaring a smaller ceiling lowers that share.
The saving does not show up in a transaction's reported `unitsConsumed`, which
only covers execution, so it is hard to measure directly from a receipt.
Do not lower the limit too far: 16 MB is still 4x smaller than the default and
leaves room for Token-2022 mints with extensions, while 512 KB is rejected with
MaxLoadedAccountsDataSizeExceeded on exactly those coins.
Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
"""
import asyncio
import base64
import hashlib
import json
import os
import struct
import sys
import base58
import pump_v2
@@ -14,6 +36,7 @@ from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Confirmed
from solana.rpc.types import TxOpts
from solders.compute_budget import set_compute_unit_price
from solders.instruction import Instruction
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
@@ -26,6 +49,13 @@ from spl.token.instructions import (
EXPECTED_DISCRIMINATOR = pump_v2.BONDING_CURVE_DISCRIMINATOR
TOKEN_DECIMALS = 6
COMPUTE_BUDGET_PROGRAM = Pubkey.from_string(
"ComputeBudget111111111111111111111111111111"
)
# 16 MB. Enough for Token-2022 mints carrying extensions, and still 4x below the
# 64 MB default; 4-8 MB is rejected with MaxLoadedAccountsDataSizeExceeded.
LOADED_ACCOUNTS_DATA_SIZE_LIMIT = 16_384_000
# Global constants
PUMP_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
PUMP_GLOBAL = Pubkey.from_string("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf")
@@ -100,6 +130,22 @@ def calculate_pump_curve_price(curve_state: pump_v2.BondingCurveState) -> float:
return price
def set_loaded_accounts_data_size_limit(bytes_limit: int) -> Instruction:
"""Build a SetLoadedAccountsDataSizeLimit compute-budget instruction.
solders does not ship a helper for this one, so encode it by hand: the
compute-budget program takes a 1-byte discriminator (4) and a u32 limit.
Args:
bytes_limit: Max account data the transaction may load, in bytes
Returns:
The compute-budget instruction
"""
data = struct.pack("<BI", 4, bytes_limit)
return Instruction(COMPUTE_BUDGET_PROGRAM, data, [])
async def buy_token(
mint: Pubkey,
bonding_curve: Pubkey,
@@ -109,6 +155,8 @@ async def buy_token(
amount: float,
slippage: float = 0.25,
max_retries=5,
*,
cu_optimized: bool = False,
):
private_key = base58.b58decode(os.environ.get("SOLANA_PRIVATE_KEY"))
payer = Keypair.from_bytes(private_key)
@@ -142,7 +190,13 @@ async def buy_token(
is_mayhem_mode=curve_state.is_mayhem_mode,
)
instructions = [
instructions = []
if cu_optimized:
# Must come first, before the instructions it applies to.
instructions.append(
set_loaded_accounts_data_size_limit(LOADED_ACCOUNTS_DATA_SIZE_LIMIT)
)
instructions += [
set_compute_unit_price(1_000),
create_idempotent_associated_token_account(
payer.pubkey(), payer.pubkey(), mint, token_program_id=token_program
@@ -350,7 +404,9 @@ async def listen_for_create_transaction():
return decoded_args
async def main():
async def main(*, cu_optimized: bool = False):
if cu_optimized:
print("Compute-unit optimization enabled (SetLoadedAccountsDataSizeLimit)")
print("Waiting for a new token creation...")
token_data = await listen_for_create_transaction()
print("New token created:")
@@ -393,8 +449,9 @@ async def main():
token_program,
amount,
slippage,
cu_optimized=cu_optimized,
)
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main(cu_optimized="--cu-optimized" in sys.argv))
@@ -1,521 +0,0 @@
"""
Pump.fun Token Buy Script with Compute Unit Optimization
This script is identical to manual_buy.py but adds SetLoadedAccountsDataSizeLimit
instruction. By default, Solana transactions can load up to 64MB of account data
(costing 16k CU). By setting a lower limit (512KB), we reduce CU consumption and
improve transaction priority.
Key difference from manual_buy.py:
- Adds set_loaded_accounts_data_size_limit(512_000) before other instructions
NOTE: The CU savings from this optimization are NOT visible in transaction "consumed CU"
metrics, which only show execution CU. The 16k CU loaded accounts overhead is counted
separately for transaction priority/cost calculation. This makes the real impact hard
to measure directly, but it improves priority.
Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
"""
import asyncio
import base64
import hashlib
import json
import os
import struct
import base58
import pump_v2
import tx_status
import websockets
from dotenv import load_dotenv
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Confirmed
from solana.rpc.types import TxOpts
from solders.compute_budget import set_compute_unit_price
from solders.instruction import Instruction
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.transaction import Transaction, VersionedTransaction
from spl.token.instructions import (
create_idempotent_associated_token_account,
)
# Discriminators
EXPECTED_DISCRIMINATOR = pump_v2.BONDING_CURVE_DISCRIMINATOR
TOKEN_DECIMALS = 6
# Global constants
PUMP_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
PUMP_GLOBAL = Pubkey.from_string("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf")
PUMP_EVENT_AUTHORITY = Pubkey.from_string(
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
)
PUMP_FEE = Pubkey.from_string("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM")
PUMP_FEE_PROGRAM = Pubkey.from_string("pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ")
# 8 breaking-upgrade fee recipients (pump.fun program upgrade 2026-04-28).
# One must be appended (mutable) AFTER bonding-curve-v2 on every buy/sell.
# Doc: github.com/pump-fun/pump-public-docs/blob/main/docs/BREAKING_FEE_RECIPIENT.md
BREAKING_FEE_RECIPIENTS = [
Pubkey.from_string("5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD"),
Pubkey.from_string("9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7"),
Pubkey.from_string("GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL"),
Pubkey.from_string("3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR"),
Pubkey.from_string("5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6"),
Pubkey.from_string("EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL"),
Pubkey.from_string("5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD"),
Pubkey.from_string("A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"),
]
SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111")
SYSTEM_TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
TOKEN_2022_PROGRAM = Pubkey.from_string("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb")
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = Pubkey.from_string(
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
)
SOL = Pubkey.from_string("So11111111111111111111111111111111111111112")
LAMPORTS_PER_SOL = 1_000_000_000
COMPUTE_BUDGET_PROGRAM = Pubkey.from_string(
"ComputeBudget111111111111111111111111111111"
)
load_dotenv()
RPC_ENDPOINT = os.environ.get("SOLANA_NODE_RPC_ENDPOINT")
RPC_WEBSOCKET = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
# logsSubscribe frames exceed the websockets library's 1 MiB default, which
# closes the connection with 1009 ("message too big").
WEBSOCKET_MAX_MESSAGE_BYTES = 32 * 1024 * 1024
BondingCurveState = pump_v2.BondingCurveState
async def get_pump_curve_state(
conn: AsyncClient, curve_address: Pubkey
) -> BondingCurveState:
response = await conn.get_account_info(curve_address, encoding="base64")
if not response.value or not response.value.data:
raise ValueError("Invalid curve state: No data")
data = response.value.data
if data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
return pump_v2.BondingCurveState(data)
def calculate_pump_curve_price(curve_state: pump_v2.BondingCurveState) -> float:
"""Price of one whole token in whole units of the curve's quote asset.
Args:
curve_state: Parsed curve state
Returns:
Price in the quote asset
Raises:
ValueError: If reserves are empty
"""
price = curve_state.price_per_token()
if price <= 0:
raise ValueError("Invalid reserve state")
return price
def _find_creator_vault(creator: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"creator-vault", bytes(creator)],
PUMP_PROGRAM,
)
return derived_address
def _find_global_volume_accumulator() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"global_volume_accumulator"],
PUMP_PROGRAM,
)
return derived_address
def _find_user_volume_accumulator(user: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"user_volume_accumulator", bytes(user)],
PUMP_PROGRAM,
)
return derived_address
def _find_fee_config() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"fee_config", bytes(PUMP_PROGRAM)],
PUMP_FEE_PROGRAM,
)
return derived_address
def _find_bonding_curve_v2(mint: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"bonding-curve-v2", bytes(mint)],
PUMP_PROGRAM,
)
return derived_address
async def get_fee_recipient(
client: AsyncClient, curve_state: BondingCurveState
) -> Pubkey:
"""Determine the correct fee recipient based on mayhem mode.
Mayhem mode tokens use a different fee recipient (reserved_fee_recipient from Global account)
instead of the standard fee recipient. This function checks the bonding curve state
and returns the appropriate fee recipient.
Args:
client: Solana RPC client to fetch Global account data
curve_state: Parsed bonding curve state containing is_mayhem_mode flag
Returns:
Appropriate fee recipient pubkey (mayhem or standard)
"""
if not curve_state.is_mayhem_mode:
return PUMP_FEE
# Fetch Global account to get reserved_fee_recipient for mayhem mode tokens
response = await client.get_account_info(PUMP_GLOBAL, encoding="base64")
if not response.value or not response.value.data:
# Fallback to standard fee if Global account cannot be fetched
return PUMP_FEE
data = response.value.data
# Parse reserved_fee_recipient from Global account
# Offset calculation based on pump_fun_idl.json Global struct:
# discriminator(8) + initialized(1) + authority(32) + fee_recipient(32) +
# initial_virtual_token_reserves(8) + initial_virtual_sol_reserves(8) +
# initial_real_token_reserves(8) + token_total_supply(8) + fee_basis_points(8) +
# withdraw_authority(32) + enable_migrate(1) + pool_migration_fee(8) +
# creator_fee_basis_points(8) + fee_recipients[7](224) + set_creator_authority(32) +
# admin_set_creator_authority(32) + create_v2_enabled(1) + whitelist_pda(32) = 483
RESERVED_FEE_RECIPIENT_OFFSET = 483
if len(data) < RESERVED_FEE_RECIPIENT_OFFSET + 32:
# Fallback if account data is too short
return PUMP_FEE
reserved_fee_recipient_bytes = data[
RESERVED_FEE_RECIPIENT_OFFSET : RESERVED_FEE_RECIPIENT_OFFSET + 32
]
return Pubkey.from_bytes(reserved_fee_recipient_bytes)
def set_loaded_accounts_data_size_limit(bytes_limit: int) -> Instruction:
"""
Create SetLoadedAccountsDataSizeLimit instruction to reduce CU consumption.
Solana defaults to 64MB loaded data limit (16k CU cost: 8 CU per 32KB).
By setting a lower limit, you reduce CU consumption and improve tx priority.
Args:
bytes_limit: Max account data size in bytes (e.g., 512_000 = 512KB)
Returns:
Compute Budget instruction (discriminator 4)
"""
data = struct.pack("<BI", 4, bytes_limit)
return Instruction(COMPUTE_BUDGET_PROGRAM, data, [])
async def buy_token(
mint: Pubkey,
bonding_curve: Pubkey,
associated_bonding_curve: Pubkey,
creator_vault: Pubkey,
token_program: Pubkey,
amount: float,
slippage: float = 0.25,
max_retries=5,
):
private_key = base58.b58decode(os.environ.get("SOLANA_PRIVATE_KEY"))
payer = Keypair.from_bytes(private_key)
async with AsyncClient(RPC_ENDPOINT) as client:
# Fetch bonding curve state to calculate price and determine fee recipient
curve_state = await get_pump_curve_state(client, bonding_curve)
token_price_sol = calculate_pump_curve_price(curve_state)
token_amount = amount / token_price_sol
# Determine fee recipient based on whether token uses mayhem mode
# buy_v2 takes 27 mandatory accounts in a fixed order for every coin.
quote_mint = pump_v2.normalize_quote_mint(
getattr(curve_state, "quote_mint", None)
)
quote_unit = pump_v2.quote_units(quote_mint)
print(f"Quote asset: {quote_mint}")
buy_ix = pump_v2.build_buy_v2_instruction(
base_mint=mint,
creator=curve_state.creator,
user=payer.pubkey(),
token_amount_raw=int(token_amount * 10**TOKEN_DECIMALS),
max_quote_cost_raw=int(amount * quote_unit * (1 + slippage)),
quote_mint=quote_mint,
base_token_program=token_program,
is_mayhem_mode=curve_state.is_mayhem_mode,
)
idempotent_ata_ix = create_idempotent_associated_token_account(
payer.pubkey(), payer.pubkey(), mint, token_program_id=token_program
)
# CU OPTIMIZATION: Limit account data to 512KB (down from 64MB default)
# This reduces CU cost from 16k to ~128 CU and improves tx priority.
# Must be placed FIRST in the instruction list.
# 16MB limit: works for cashback-coin Token-2022 buys on mainnet.
# Smaller values (48MB) trigger MaxLoadedAccountsDataSizeExceeded for
# Token-2022 mints with extensions. Still 4× smaller than the 64MB default.
cu_limit_ix = set_loaded_accounts_data_size_limit(16_384_000)
msg = Message(
[cu_limit_ix, set_compute_unit_price(1_000), idempotent_ata_ix, buy_ix],
payer.pubkey(),
)
recent_blockhash = await client.get_latest_blockhash()
opts = TxOpts(skip_preflight=True, preflight_commitment=Confirmed)
for attempt in range(max_retries):
try:
tx_buy = await client.send_transaction(
Transaction(
[payer],
msg,
recent_blockhash.value.blockhash,
),
opts=opts,
)
tx_hash = tx_buy.value
print(f"Transaction sent: https://explorer.solana.com/tx/{tx_hash}")
await tx_status.confirm_and_assert(client, tx_hash)
print("Transaction confirmed")
return # Success, exit the function
except tx_status.TransactionRevertedError as e:
# The signature is already on chain and reverted. The message and
# blockhash below are fixed, so a retry would resubmit identical
# bytes and revert identically — stop instead of burning attempts.
print(f"Transaction reverted on-chain, not retrying: {e}")
return
except Exception as e:
print(f"Attempt {attempt + 1} failed: {str(e)[:50]}")
if attempt < max_retries - 1:
wait_time = 2**attempt
print(f"Retrying in {wait_time} seconds...")
await asyncio.sleep(wait_time)
else:
print("Max retries reached. Unable to complete the transaction.")
def load_idl(file_path):
with open(file_path) as f:
return json.load(f)
def calculate_discriminator(instruction_name):
sha = hashlib.sha256()
sha.update(instruction_name.encode("utf-8"))
return struct.unpack("<Q", sha.digest()[:8])[0]
def decode_create_instruction(ix_data, ix_def, accounts):
"""Decode create instruction from transaction data."""
args = {}
offset = 8
for arg in ix_def["args"]:
t = arg["type"]
if t == "string":
length = struct.unpack_from("<I", ix_data, offset)[0]
offset += 4
value = ix_data[offset : offset + length].decode("utf-8")
offset += length
elif t == "pubkey":
value = base58.b58encode(ix_data[offset : offset + 32]).decode("utf-8")
offset += 32
elif t == "bool" or (isinstance(t, dict) and "defined" in t):
# `bool` and `OptionBool` (struct {bool}) both serialize as 1 byte
value = bool(ix_data[offset])
offset += 1
else:
raise ValueError(f"Unsupported type: {t}")
args[arg["name"]] = value
args["mint"] = str(accounts[0])
args["bondingCurve"] = str(accounts[2])
args["associatedBondingCurve"] = str(accounts[3])
args["user"] = str(accounts[7])
return args
async def listen_for_create_transaction():
"""Listen for new token creation on pump.fun."""
idl_path = os.path.join(os.path.dirname(__file__), "..", "idl", "pump_fun_idl.json")
idl = load_idl(idl_path)
create_discriminator = calculate_discriminator("global:create")
create_v2_discriminator = calculate_discriminator("global:create_v2")
async with websockets.connect(
RPC_WEBSOCKET, max_size=WEBSOCKET_MAX_MESSAGE_BYTES
) as websocket:
subscription_message = json.dumps(
{
"jsonrpc": "2.0",
"id": 1,
"method": "blockSubscribe",
"params": [
{"mentionsAccountOrProgram": str(PUMP_PROGRAM)},
{
"commitment": "confirmed",
"encoding": "base64",
"showRewards": False,
"transactionDetails": "full",
"maxSupportedTransactionVersion": 0,
},
],
}
)
await websocket.send(subscription_message)
print(f"Subscribed to blocks mentioning program: {PUMP_PROGRAM}")
while True:
response = await websocket.recv()
data = json.loads(response)
if "method" in data and data["method"] == "blockNotification":
if "params" in data and "result" in data["params"]:
block_data = data["params"]["result"]
if "value" in block_data and "block" in block_data["value"]:
block = block_data["value"]["block"]
if "transactions" in block:
for tx in block["transactions"]:
if isinstance(tx, dict) and "transaction" in tx:
tx_data_decoded = base64.b64decode(
tx["transaction"][0]
)
transaction = VersionedTransaction.from_bytes(
tx_data_decoded
)
for ix in transaction.message.instructions:
if str(
transaction.message.account_keys[
ix.program_id_index
]
) == str(PUMP_PROGRAM):
ix_data = bytes(ix.data)
discriminator = struct.unpack(
"<Q", ix_data[:8]
)[0]
# Check which create instruction was used
instruction_name = None
token_program = None
if discriminator == create_discriminator:
instruction_name = "create"
token_program = SYSTEM_TOKEN_PROGRAM
elif (
discriminator == create_v2_discriminator
):
instruction_name = "create_v2"
token_program = TOKEN_2022_PROGRAM
if instruction_name:
create_ix = next(
instr
for instr in idl["instructions"]
if instr["name"] == instruction_name
)
# Skip txs that use Address Lookup Tables — their
# instruction account indices reference ALT-loaded keys
# not present in transaction.message.account_keys.
static_keys = (
transaction.message.account_keys
)
if any(
idx >= len(static_keys)
for idx in ix.accounts
):
continue
account_keys = [
str(
transaction.message.account_keys[
index
]
)
for index in ix.accounts
]
decoded_args = (
decode_create_instruction(
ix_data, create_ix, account_keys
)
)
# Add token program info to decoded args
decoded_args["token_program"] = str(
token_program
)
decoded_args["is_token_2022"] = (
token_program == TOKEN_2022_PROGRAM
)
return decoded_args
async def main():
print("Waiting for a new token creation...")
token_data = await listen_for_create_transaction()
print("New token created:")
print(json.dumps(token_data, indent=2))
print("\nWaiting 15 seconds for things to stabilize...")
await asyncio.sleep(15)
mint = Pubkey.from_string(token_data["mint"])
bonding_curve = Pubkey.from_string(token_data["bondingCurve"])
associated_bonding_curve = Pubkey.from_string(token_data["associatedBondingCurve"])
creator_vault = pump_v2.find_creator_vault(
Pubkey.from_string(token_data["creator"])
)
token_program = Pubkey.from_string(token_data["token_program"])
# Fetch the token price
async with AsyncClient(RPC_ENDPOINT) as client:
curve_state = await get_pump_curve_state(client, bonding_curve)
token_price_sol = calculate_pump_curve_price(curve_state)
# Amount of SOL to spend (adjust as needed)
amount = 0.000_001 # 0.00001 SOL
slippage = 0.3 # 30% slippage tolerance
print(f"Bonding curve address: {bonding_curve}")
print(
f"Token Program: {token_program} ({'Token2022' if token_data['is_token_2022'] else 'Standard Token'})"
)
print(f"Token price: {token_price_sol:.10f} SOL")
print(
f"Buying {amount:.6f} SOL worth of the new token with {slippage * 100:.1f}% slippage tolerance..."
)
print("CU Optimization: Enabled (16MB account data limit)")
await buy_token(
mint,
bonding_curve,
associated_bonding_curve,
creator_vault,
token_program,
amount,
slippage,
)
if __name__ == "__main__":
asyncio.run(main())
-100
View File
@@ -40,19 +40,6 @@ PUMP_EVENT_AUTHORITY = Pubkey.from_string(
PUMP_FEE = Pubkey.from_string("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM")
PUMP_FEE_PROGRAM = Pubkey.from_string("pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ")
# 8 breaking-upgrade fee recipients (pump.fun program upgrade 2026-04-28).
# One must be appended (mutable) AFTER bonding-curve-v2 on every buy/sell.
# Doc: github.com/pump-fun/pump-public-docs/blob/main/docs/BREAKING_FEE_RECIPIENT.md
BREAKING_FEE_RECIPIENTS = [
Pubkey.from_string("5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD"),
Pubkey.from_string("9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7"),
Pubkey.from_string("GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL"),
Pubkey.from_string("3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR"),
Pubkey.from_string("5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6"),
Pubkey.from_string("EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL"),
Pubkey.from_string("5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD"),
Pubkey.from_string("A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"),
]
SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111")
SYSTEM_TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
SYSTEM_TOKEN_2022_PROGRAM = Pubkey.from_string(
@@ -112,93 +99,6 @@ def calculate_pump_curve_price(curve_state: pump_v2.BondingCurveState) -> float:
return price
def _find_creator_vault(creator: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"creator-vault", bytes(creator)],
PUMP_PROGRAM,
)
return derived_address
def _find_global_volume_accumulator() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"global_volume_accumulator"],
PUMP_PROGRAM,
)
return derived_address
def _find_user_volume_accumulator(user: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"user_volume_accumulator", bytes(user)],
PUMP_PROGRAM,
)
return derived_address
def _find_fee_config() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"fee_config", bytes(PUMP_PROGRAM)],
PUMP_FEE_PROGRAM,
)
return derived_address
def _find_bonding_curve_v2(mint: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"bonding-curve-v2", bytes(mint)],
PUMP_PROGRAM,
)
return derived_address
async def get_fee_recipient(
client: AsyncClient, curve_state: BondingCurveState
) -> Pubkey:
"""Determine the correct fee recipient based on mayhem mode.
Mayhem mode tokens use a different fee recipient (reserved_fee_recipient from Global account)
instead of the standard fee recipient. This function checks the bonding curve state
and returns the appropriate fee recipient.
Args:
client: Solana RPC client to fetch Global account data
curve_state: Parsed bonding curve state containing is_mayhem_mode flag
Returns:
Appropriate fee recipient pubkey (mayhem or standard)
"""
if not curve_state.is_mayhem_mode:
return PUMP_FEE
# Fetch Global account to get reserved_fee_recipient for mayhem mode tokens
response = await client.get_account_info(PUMP_GLOBAL, encoding="base64")
if not response.value or not response.value.data:
# Fallback to standard fee if Global account cannot be fetched
return PUMP_FEE
data = response.value.data
# Parse reserved_fee_recipient from Global account
# Offset calculation based on pump_fun_idl.json Global struct:
# discriminator(8) + initialized(1) + authority(32) + fee_recipient(32) +
# initial_virtual_token_reserves(8) + initial_virtual_sol_reserves(8) +
# initial_real_token_reserves(8) + token_total_supply(8) + fee_basis_points(8) +
# withdraw_authority(32) + enable_migrate(1) + pool_migration_fee(8) +
# creator_fee_basis_points(8) + fee_recipients[7](224) + set_creator_authority(32) +
# admin_set_creator_authority(32) + create_v2_enabled(1) + whitelist_pda(32) = 483
RESERVED_FEE_RECIPIENT_OFFSET = 483
if len(data) < RESERVED_FEE_RECIPIENT_OFFSET + 32:
# Fallback if account data is too short
return PUMP_FEE
reserved_fee_recipient_bytes = data[
RESERVED_FEE_RECIPIENT_OFFSET : RESERVED_FEE_RECIPIENT_OFFSET + 32
]
return Pubkey.from_bytes(reserved_fee_recipient_bytes)
async def create_geyser_connection():
"""Establish a secure connection to the Geyser endpoint using the configured auth type."""
if AUTH_TYPE == "x-token":
-46
View File
@@ -49,19 +49,6 @@ PUMP_FEE_PROGRAM: Final[Pubkey] = Pubkey.from_string(
"pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ"
)
# 8 breaking-upgrade fee recipients (pump.fun program upgrade 2026-04-28).
# One must be appended (mutable) AFTER bonding-curve-v2 on every buy/sell.
# Doc: github.com/pump-fun/pump-public-docs/blob/main/docs/BREAKING_FEE_RECIPIENT.md
BREAKING_FEE_RECIPIENTS: Final[list[Pubkey]] = [
Pubkey.from_string("5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD"),
Pubkey.from_string("9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7"),
Pubkey.from_string("GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL"),
Pubkey.from_string("3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR"),
Pubkey.from_string("5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6"),
Pubkey.from_string("EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL"),
Pubkey.from_string("5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD"),
Pubkey.from_string("A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"),
]
PUMP_MINT_AUTHORITY: Final[Pubkey] = Pubkey.from_string(
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
)
@@ -85,7 +72,6 @@ TOKEN_DECIMALS: Final[int] = 6
# Discriminators
CREATE_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 8576854823835016728)
BUY_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 16927863322537952870)
EXTEND_ACCOUNT_DISCRIMINATOR: Final[bytes] = bytes(
[234, 102, 194, 203, 150, 72, 62, 229]
)
@@ -135,38 +121,6 @@ def find_creator_vault(creator: Pubkey) -> Pubkey:
return derived_address
def _find_global_volume_accumulator() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"global_volume_accumulator"],
PUMP_PROGRAM,
)
return derived_address
def _find_user_volume_accumulator(user: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"user_volume_accumulator", bytes(user)],
PUMP_PROGRAM,
)
return derived_address
def _find_fee_config() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"fee_config", bytes(PUMP_PROGRAM)],
PUMP_FEE_PROGRAM,
)
return derived_address
def _find_bonding_curve_v2(mint: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"bonding-curve-v2", bytes(mint)],
PUMP_PROGRAM,
)
return derived_address
def create_pump_create_instruction(
mint: Pubkey,
mint_authority: Pubkey,
-46
View File
@@ -50,19 +50,6 @@ PUMP_FEE_PROGRAM: Final[Pubkey] = Pubkey.from_string(
"pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ"
)
# 8 breaking-upgrade fee recipients (pump.fun program upgrade 2026-04-28).
# One must be appended (mutable) AFTER bonding-curve-v2 on every buy/sell.
# Doc: github.com/pump-fun/pump-public-docs/blob/main/docs/BREAKING_FEE_RECIPIENT.md
BREAKING_FEE_RECIPIENTS: Final[list[Pubkey]] = [
Pubkey.from_string("5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD"),
Pubkey.from_string("9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7"),
Pubkey.from_string("GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL"),
Pubkey.from_string("3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR"),
Pubkey.from_string("5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6"),
Pubkey.from_string("EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL"),
Pubkey.from_string("5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD"),
Pubkey.from_string("A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"),
]
PUMP_MINT_AUTHORITY: Final[Pubkey] = Pubkey.from_string(
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
)
@@ -91,7 +78,6 @@ TOKEN_DECIMALS: Final[int] = 6
# Discriminators
CREATE_V2_DISCRIMINATOR: Final[bytes] = bytes([214, 144, 76, 236, 95, 139, 49, 180])
BUY_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 16927863322537952870)
EXTEND_ACCOUNT_DISCRIMINATOR: Final[bytes] = bytes(
[234, 102, 194, 203, 150, 72, 62, 229]
)
@@ -151,38 +137,6 @@ def find_mayhem_token_vault(mint: Pubkey) -> Pubkey:
return get_associated_token_address(SOL_VAULT, mint, TOKEN_2022_PROGRAM)
def _find_global_volume_accumulator() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"global_volume_accumulator"],
PUMP_PROGRAM,
)
return derived_address
def _find_user_volume_accumulator(user: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"user_volume_accumulator", bytes(user)],
PUMP_PROGRAM,
)
return derived_address
def _find_fee_config() -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"fee_config", bytes(PUMP_PROGRAM)],
PUMP_FEE_PROGRAM,
)
return derived_address
def _find_bonding_curve_v2(mint: Pubkey) -> Pubkey:
derived_address, _ = Pubkey.find_program_address(
[b"bonding-curve-v2", bytes(mint)],
PUMP_PROGRAM,
)
return derived_address
def create_pump_create_v2_instruction(
mint: Pubkey,
mint_authority: Pubkey,
@@ -53,6 +53,9 @@ async def get_market_data(market_address: Pubkey):
parsed_data = {}
offset = 8
# Fields end at 261; live pool accounts are 301 bytes with trailing padding.
# virtual_quote_reserves is an i128, not a u64 — reading only 8 bytes happens
# to work while the high half is zero, and silently breaks when it isn't.
fields = [
("pool_bump", "u8"),
("index", "u16"),
@@ -64,6 +67,9 @@ async def get_market_data(market_address: Pubkey):
("pool_quote_token_account", "pubkey"),
("lp_supply", "u64"),
("coin_creator", "pubkey"),
("is_mayhem_mode", "bool"),
("is_cashback_coin", "bool"),
("virtual_quote_reserves", "i128"),
]
for field_name, field_type in fields:
@@ -79,6 +85,14 @@ async def get_market_data(market_address: Pubkey):
)
parsed_data[field_name] = value
offset += 8
elif field_type == "i128":
if len(data) < offset + 16:
parsed_data[field_name] = 0
continue
parsed_data[field_name] = int.from_bytes(
data[offset : offset + 16], "little", signed=True
)
offset += 16
elif field_type == "u16":
value = struct.unpack("<H", data[offset : offset + 2])[0]
parsed_data[field_name] = value
@@ -87,6 +101,11 @@ async def get_market_data(market_address: Pubkey):
value = data[offset]
parsed_data[field_name] = value
offset += 1
elif field_type == "bool":
parsed_data[field_name] = (
bool(data[offset]) if len(data) > offset else False
)
offset += 1
return parsed_data
@@ -98,7 +117,19 @@ async def main():
print(market_address)
market_data = await get_market_data(market_address)
print(market_data)
for key, value in market_data.items():
print(f" {key}: {value}")
# Quote against effective reserves. Upstream's release note says
# virtual_quote_reserves is 0 on all pools; that is out of date — pools carry
# 17.5845 SOL of virtual reserves, so quoting off the raw vault balance
# under-prices by anywhere from a few percent to over 20%.
virtual = market_data.get("virtual_quote_reserves", 0)
if virtual:
print(
f"\nNote: this pool carries {virtual / 1e9:.9f} SOL of virtual quote "
"reserves. Add them to pool_quote_token_account.amount before quoting."
)
if __name__ == "__main__":
@@ -1 +0,0 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"1.18.22","slot":285247740},"value":{"data":["F7f4N2DYrGD99rN6is0DALwvcwAHAAAA/V6hLvnOAgC8g08EAAAAAACAxqR+jQMAAA==","base64"],"executable":false,"lamports":73551852,"owner":"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P","rentEpoch":18446744073709551615,"space":49}},"id":1}
@@ -0,0 +1,21 @@
{
"jsonrpc": "2.0",
"result": {
"context": {
"slot": 435946373,
"apiVersion": "4.3.0-alpha.2"
},
"value": {
"lamports": 790949926,
"data": [
"F7f4N2DYrGCHbmgi4bYDANb6KisHAAAAh9ZV1k+4AgDWTgcvAAAAAACAxqR+jQMAAEXn9ErjbXNmON16LY9gtDVntkXAv94W3SK1C3OqM6zeAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"base64"
],
"owner": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"executable": false,
"rentEpoch": 18446744073709551615,
"space": 151
}
},
"id": 1
}
@@ -1,388 +0,0 @@
{
"jsonrpc": "2.0",
"result": {
"blockTime": 1724126293,
"meta": {
"computeUnitsConsumed": 68322,
"err": null,
"fee": 32000,
"innerInstructions": [
{
"index": 2,
"instructions": [
{
"parsed": {
"info": {
"amount": "605426095720",
"authority": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"destination": "DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"source": "9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd"
},
"type": "transfer"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"lamports": 24080282,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"lamports": 240802,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "2K7nL28PxCW8ejnyCeuMpbYBaHNNxSWmhNFbMDYBXdWw7nSYrc7woNd4ENfAZMMQjP9TLFxfRvA69i3wPHorNMpqcfCFFFFeAmfcVqdtaPqq3JE1erMrE8gHpGJ8NXA1633JV4iabs9saqZ8Pa7xQrjkoYX8pgbAjh3CnePG1Lq18E9fsPv89nKqmgvb",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
},
{
"index": 3,
"instructions": [
{
"parsed": {
"info": {
"amount": "605426095720",
"authority": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"destination": "9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"source": "DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S"
},
"type": "transfer"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "2K7nL28PxCW8ejnyCeuMpbYBaHNNxSWmhNFbMDYBXdWw7nSYrc7woNd4ENfAZMMQjP9RGosGgCYezUhV4mEBVCtoTrbAXXkFVvp72dtBLa7fuvzRsmCgMkydN6Ez8H17gRiXkmmNHUCXcUmfhMG2cGeaukQWu1YD7mkmTzg7QGUF69ArSTS3RHHM6zXh",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Buy",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 129562 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 117474 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: vdt/007mYe73itfzw580Z6SEg9q3HfHO2n0qXIpNVTcl7oo9jo+CP5pvbwEAAAAAaBY19owAAAABHKbz9pJ3+YMsz+xMr0BHBMU3VB0RDjRv3ae0eInXRhRVFMRmAAAAAFjTeFUIAAAAbRsnNO0xAwBYJ1VZAQAAAG2DFOhbMwIA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 35954 of 149700 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Sell",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 93687 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 85557 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: vdt/007mYe73itfzw580Z6SEg9q3HfHO2n0qXIpNVTcl7oo9jo+CP5lvbwEAAAAAaBY19owAAAAAHKbz9pJ3+YMsz+xMr0BHBMU3VB0RDjRv3ae0eInXRhRVFMRmAAAAAL9jCVQIAAAA1TFcKnoyAwC/t+VXAQAAANWZSd7oMwIA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 31918 of 113746 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success"
],
"postBalances": [
706655008,
5770871791,
2039280,
279629252504426,
2039280,
97135324113,
1,
1141440,
1,
1009200,
934087680,
2500000,
731913600,
0,
1461600
],
"postTokenBalances": [
{
"accountIndex": 2,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "826925208216021",
"decimals": 6,
"uiAmount": 826925208.216021,
"uiAmountString": "826925208.216021"
}
},
{
"accountIndex": 4,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "0",
"decimals": 6,
"uiAmount": null,
"uiAmountString": "0"
}
}
],
"preBalances": [
708131176,
5770871790,
2039280,
279629252022822,
2039280,
97134361550,
1,
1141440,
1,
1009200,
934087680,
2500000,
731913600,
0,
1461600
],
"preTokenBalances": [
{
"accountIndex": 2,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "826925208216021",
"decimals": 6,
"uiAmount": 826925208.216021,
"uiAmountString": "826925208.216021"
}
},
{
"accountIndex": 4,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "0",
"decimals": 6,
"uiAmount": null,
"uiAmountString": "0"
}
}
],
"rewards": [],
"status": {
"Ok": null
}
},
"slot": 284677332,
"transaction": {
"message": {
"accountKeys": [
{
"pubkey": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "JBfdxsh3DEXfpeTUrQe94hpKQ8yxBqVRqRiSRvemUA4i",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ComputeBudget111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "SysvarRent111111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"signer": false,
"source": "transaction",
"writable": false
}
],
"addressTableLookups": [],
"instructions": [
{
"accounts": [],
"data": "3JwEwun4YUPH",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [],
"data": "LEJDE7",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "AJTQ2h9DXrBqzdpEhcLVYocNoqujioBxb",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"11111111111111111111111111111111",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "5jRcjdixRUDSvSh4QXANSHU9rk2He2WMm",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"parsed": {
"info": {
"destination": "JBfdxsh3DEXfpeTUrQe94hpKQ8yxBqVRqRiSRvemUA4i",
"lamports": 962563,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": null
}
],
"recentBlockhash": "cqZ8vtKbuAVtwCRHrATJn7X3kohsJH2Qn9zdhEr8sE5"
},
"signatures": [
"33LHUzKfhBvU68kYib22oFx2XdQKQZ2sfvTmmdCFEr6YidyP8S3WwAurjz6Suewvr2WUByV79K3stNCZDe7wq3De"
]
},
"version": 0
},
"id": 1
}
@@ -0,0 +1,698 @@
{
"jsonrpc": "2.0",
"result": {
"slot": 435948490,
"transaction": {
"signatures": [
"2m5nWLnDSbM5SEGCnRxuftg5PFFZR6kziuNQbmrmqtEhbH81PyKVeEsipiXaFQxnerN8zQYB2XRwozrjoZheFDuG"
],
"message": {
"accountKeys": [
{
"pubkey": "Gygj9QQby4j2jryqyqBHvLP7ctv2SaANgh4sCb69BUpA",
"writable": true,
"signer": true,
"source": "transaction"
},
{
"pubkey": "6w1RMBHu8G269Z1SSp6p7SZyVj3ugGupWhKkeSbs7Vm6",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "9LdJrtQkdqioAWiiyTpd1Vx4utffxHxvssEYhPhuucMv",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "2Y3wfpoDxGWYsuqDhSZKWeVh5Mgg42edV9bd5CFYA679",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "AShUETU4ABeHiBAwLfG56X3mv9CGUZRQ5ZK5RPzte4Th",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "2HA4cjd1kL3d4BbWRAd9tp2XMw29skQeL3HZ1XU2BBB3",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "Ezz2ojEpLcYs3A7uMFW6pgnxtwbhHkJHRAU27zTfiYJU",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "8i6hiPsdTZ7RqMTKb6mnS4qPvHdA2eA9dxkv3wpnESNV",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "FGFrX2q1iAjyAojjeyFDxXqdmvegjPpSWsrPmrJjeQ2f",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "2hcbDhq9CacWu2FZa7n1YbftAgo8FfKRDkVahRo7TwST",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "ComputeBudget111111111111111111111111111111",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "ELya7rmiRHfKyDkE9j5yQZtjD9fABkifmsFw3XSPDfEh",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "13ec7XdrjF3h3YcqBTFDSReRcUFwbCnJaAQspM4j6DDJ",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "41xY1DU1zzo893bEg2HzTFxPVVM84UvDCNsQm6aKRq8Z",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "6oCkp6gpyjxVTeL6ahMYcekN2x2pzt1KY8g2LqemaTNE",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "11111111111111111111111111111111",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "Hq2wp8uJ9jCPsYgNHex8RtqdvMPfVGoYwjvF1ATiwn2Y",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "8Wf5TiAheLUqBrKXeYg2JtAFFMWtKdG2BSFgqUcPVwTt",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "8FoNgzmjuSmiy86EPCWxvv1q7oJSu2WGA7wPymwki2LJ",
"writable": false,
"signer": false,
"source": "lookupTable"
}
],
"recentBlockhash": "2aMGsi77kV4cQXNLcKmkSn9ZzfK2Q6WC4yPTyPk5PLG6",
"instructions": [
{
"programId": "ComputeBudget111111111111111111111111111111",
"accounts": [],
"data": "HMypLP",
"stackHeight": 1
},
{
"programId": "ComputeBudget111111111111111111111111111111",
"accounts": [],
"data": "3KSRLvB8X9SP",
"stackHeight": 1
},
{
"programId": "MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e",
"accounts": [
"Gygj9QQby4j2jryqyqBHvLP7ctv2SaANgh4sCb69BUpA",
"13ec7XdrjF3h3YcqBTFDSReRcUFwbCnJaAQspM4j6DDJ",
"6w1RMBHu8G269Z1SSp6p7SZyVj3ugGupWhKkeSbs7Vm6",
"4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"9LdJrtQkdqioAWiiyTpd1Vx4utffxHxvssEYhPhuucMv",
"2Y3wfpoDxGWYsuqDhSZKWeVh5Mgg42edV9bd5CFYA679",
"BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"11111111111111111111111111111111",
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"AShUETU4ABeHiBAwLfG56X3mv9CGUZRQ5ZK5RPzte4Th",
"GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS",
"41xY1DU1zzo893bEg2HzTFxPVVM84UvDCNsQm6aKRq8Z",
"2HA4cjd1kL3d4BbWRAd9tp2XMw29skQeL3HZ1XU2BBB3",
"Ezz2ojEpLcYs3A7uMFW6pgnxtwbhHkJHRAU27zTfiYJU",
"8i6hiPsdTZ7RqMTKb6mnS4qPvHdA2eA9dxkv3wpnESNV",
"ELya7rmiRHfKyDkE9j5yQZtjD9fABkifmsFw3XSPDfEh",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"Hq2wp8uJ9jCPsYgNHex8RtqdvMPfVGoYwjvF1ATiwn2Y",
"FGFrX2q1iAjyAojjeyFDxXqdmvegjPpSWsrPmrJjeQ2f",
"2hcbDhq9CacWu2FZa7n1YbftAgo8FfKRDkVahRo7TwST",
"8Wf5TiAheLUqBrKXeYg2JtAFFMWtKdG2BSFgqUcPVwTt",
"pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
"8FoNgzmjuSmiy86EPCWxvv1q7oJSu2WGA7wPymwki2LJ",
"MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e",
"5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
"6oCkp6gpyjxVTeL6ahMYcekN2x2pzt1KY8g2LqemaTNE"
],
"data": "2tpZiHBNBWa1UWDSRdfDd9rxSjLbuHp5xpxmwmZ",
"stackHeight": 1
}
],
"addressTableLookups": [
{
"accountKey": "Hyif6eWb8x88RVrvjPfabsgRYnwkVnyByEXTVTXbUcyP",
"writableIndexes": [
18,
19,
37,
95,
29,
71
],
"readonlyIndexes": [
125,
13,
10,
11,
12,
1,
3,
0,
4,
14,
15,
20
]
}
]
}
},
"meta": {
"err": null,
"status": {
"Ok": null
},
"fee": 24778,
"preBalances": [
812758564779,
1628640,
2074080,
2039280,
1691280,
2039280,
2074080,
5633394,
2039280,
1854400,
2039280,
1,
11149834,
3681840,
0,
3104160,
46718205325026,
89916349345,
2039280,
951841917,
2039280,
517251819632,
3388605256,
1,
70128637,
58238313,
4089612038,
168261371,
8502112342,
17016138,
37290293,
6046720,
0
],
"postBalances": [
812758540001,
1628640,
2074080,
2039280,
1691280,
2039280,
2074080,
5633394,
2039280,
1854400,
2039280,
1,
11149834,
3681840,
0,
3104160,
46718205325026,
89916349345,
2039280,
951841917,
2039280,
517251819632,
3388605256,
1,
70128637,
58238313,
4089612038,
168261371,
8502112342,
17016138,
37290293,
6046720,
0
],
"innerInstructions": [
{
"index": 2,
"instructions": [
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS",
"41xY1DU1zzo893bEg2HzTFxPVVM84UvDCNsQm6aKRq8Z",
"5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
"6oCkp6gpyjxVTeL6ahMYcekN2x2pzt1KY8g2LqemaTNE",
"HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"2HA4cjd1kL3d4BbWRAd9tp2XMw29skQeL3HZ1XU2BBB3",
"AShUETU4ABeHiBAwLfG56X3mv9CGUZRQ5ZK5RPzte4Th",
"BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"9LdJrtQkdqioAWiiyTpd1Vx4utffxHxvssEYhPhuucMv",
"2Y3wfpoDxGWYsuqDhSZKWeVh5Mgg42edV9bd5CFYA679",
"Ezz2ojEpLcYs3A7uMFW6pgnxtwbhHkJHRAU27zTfiYJU",
"8i6hiPsdTZ7RqMTKb6mnS4qPvHdA2eA9dxkv3wpnESNV",
"ELya7rmiRHfKyDkE9j5yQZtjD9fABkifmsFw3XSPDfEh",
"Hq2wp8uJ9jCPsYgNHex8RtqdvMPfVGoYwjvF1ATiwn2Y",
"FGFrX2q1iAjyAojjeyFDxXqdmvegjPpSWsrPmrJjeQ2f",
"2hcbDhq9CacWu2FZa7n1YbftAgo8FfKRDkVahRo7TwST",
"8Wf5TiAheLUqBrKXeYg2JtAFFMWtKdG2BSFgqUcPVwTt",
"pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
"11111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "HnQ14hy6fxGQxczSWyBXHka96z13LiDXm",
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"authority": "HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"destination": "9LdJrtQkdqioAWiiyTpd1Vx4utffxHxvssEYhPhuucMv",
"mint": "4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"source": "2HA4cjd1kL3d4BbWRAd9tp2XMw29skQeL3HZ1XU2BBB3",
"tokenAmount": {
"amount": "445377137871",
"decimals": 6,
"uiAmount": 445377.137871,
"uiAmountString": "445377.137871"
}
},
"type": "transferChecked"
},
"stackHeight": 3
},
{
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"parsed": {
"info": {
"authority": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"destination": "AShUETU4ABeHiBAwLfG56X3mv9CGUZRQ5ZK5RPzte4Th",
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"source": "2Y3wfpoDxGWYsuqDhSZKWeVh5Mgg42edV9bd5CFYA679",
"tokenAmount": {
"amount": "3517192",
"decimals": 6,
"uiAmount": 3.517192,
"uiAmountString": "3.517192"
}
},
"type": "transferChecked"
},
"stackHeight": 3
},
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "T2jLjveMmM4gJ1fdXs3mfxMtZLtJew2gANfsjyRwyyjrfKAURDb9USbZcayqSDHN6b9A2nwWgy4hLExiNxyJNqAwddH69Zhd98G2dMD2c1S9dN4wLwUbXgUSJ8PyhmADh7AD52U1wrr2YpFTDS8pvP9Hbq11RmbC3C3JYPMg9WEvYZMU7npACaGnkETZjSQKUZTbMCcQriEUgcXtzj1ZhnB8bqUfVfYrSWftc3v1YQj8mjRR9rJkVzio6o8GtEuDg2sFoc9iMSyjNvU5BvZZGwQzUPzRx53xpVZ1h55gFVViQoTwrMyNfGQGA8XBoJcuRjWE8Fk8WjoUqmVDamCqNoyNwTm276eCPwwz3iGeJFGeBiDSa722Fsm25w1Y8hRw9Rb4A82jQz9dsuuPFGuM2bdKCazk4W4yVsmgEyVBAi26kMha4bDGvXLHF618cxx7GZjpjKKQ4sAApDXY4dHYAqh4WGxTKtx4Ab6cuxJBCJh5ehb58WkP",
"stackHeight": 3
},
{
"programId": "MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e",
"accounts": [
"8FoNgzmjuSmiy86EPCWxvv1q7oJSu2WGA7wPymwki2LJ"
],
"data": "HaAvdxyruSvtMDoMtGvePmYV4dda7tWKCLFHadQoSjYsbWWixs1eN1wCF27wUxZao1NgZS9bvKCk9fBzvFqDnPg6QsN9zSkzT9e6xqQywHnLc2LokFDuFWdGqvRU9zoNbt4nY2UuSY4y5ESyEMbB1Jz1U4ibP6pvCw13tDLfnUHMG7yySVJmA2B4Z1AFKZ2WzWtiyisinm6nqWjFuvwGeG8y472DtjpjZDwreJAWNUZHj9M7FkiRmz6Tj4NFidjj7Evwp6f7bKVP75Grxv9stZCiDdPQVWVUuVUkdbTpohhvCsPW749iHWAXJVn6RhV7fgbQzNQXhUb46wJpDhXCmA3a3NuxKDe1BfxTuoFBXF9sio4iVCuvBseBSRqBAjXrHGtK8H1njuk744C4ttf7acF6hejX3fftkDM2Yvyxt",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e invoke [1]",
"Program log: Instruction: BuyV2",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program log: Instruction: BuyV2",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]",
"Program log: Instruction: TransferChecked",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2562 of 258113 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 105 of 251489 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program data: vdt/007mYe4wLVmHbP9snyR8drbtFvCd5ld8m8scMo/VKWk60csGDwAAAAAAAAAAz8yLsmcAAAABootf0mq0eaapzGy/awsj62GIWjceASCsqRO+7z0TinjI82lqAAAAAAAAAAAAAAAA8WYcCgzLAwAAAAAAAAAAAPHOCb56zAIA6JMUH7GOnxV02BDheOGeMGBOMXWqLkoy38hgByfRBwkAAAAAAAAAAAAAAAAAAAAAxWk+W+Igi1It2c+yqT2JHBb11+RM14nMlwbpL7MbLsUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAGJ1eQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADG+nrzvtutOj1l82qryXQxsbvkwtL24OR8pgIDRS9dYQirNQAAAAAAOKkISAIAAADsun8BAAAAAA==",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [3]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2125 of 244477 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 94040 of 333666 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: MUh7LW5AsIUAootf0mq0eaapzGy/awsj62GIWjceASCsqRO+7z0TingwLVmHbP9snyR8drbtFvCd5ld8m8scMo/VKWk60csGDwAAAAAAAAAAz8yLsmcAAAAAAAAAAAAAACJFaDvWjwMAAAAAAAAAAAAAAAAAAAAAAN46Xmmo/f////////////8AAAAAAAAAAPFmHAoMywMAAAAAAAAAAAAAAAAAAAAAAMjzaWoAAAAAREVragAAAAAAAAAAAAAAAPHOCb56zAIACgAAALYgCKs1AAAAAAALgVl7MgAAAFye1wAAAAAAAAAAAAAAAAA4qQhIAgAAAPXGOq4cAAAAAAAAAAAAAADsun8BAAAAAMb6evO+2606PWXzaqvJdDGxu+TC0vbg5HymAgNFL11h",
"Program MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e invoke [2]",
"Program MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e consumed 518 of 231520 compute units",
"Program MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e success",
"Program MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e consumed 171799 of 399700 compute units",
"Program MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e success"
],
"preTokenBalances": [
{
"accountIndex": 2,
"mint": "4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"uiTokenAmount": {
"uiAmount": 1002129835.456595,
"decimals": 6,
"amount": "1002129835456595",
"uiAmountString": "1002129835.456595"
},
"owner": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
},
{
"accountIndex": 3,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 216821.345299,
"decimals": 6,
"amount": "216821345299",
"uiAmountString": "216821.345299"
},
"owner": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 5,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 21.630948,
"decimals": 6,
"amount": "21630948",
"uiAmountString": "21.630948"
},
"owner": "HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 6,
"mint": "4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"uiTokenAmount": {
"uiAmount": 995122876.94944,
"decimals": 6,
"amount": "995122876949440",
"uiAmountString": "995122876.94944"
},
"owner": "HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
},
{
"accountIndex": 8,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": null,
"decimals": 6,
"amount": "0",
"uiAmountString": "0"
},
"owner": "Ezz2ojEpLcYs3A7uMFW6pgnxtwbhHkJHRAU27zTfiYJU",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 10,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": null,
"decimals": 6,
"amount": "0",
"uiAmountString": "0"
},
"owner": "FGFrX2q1iAjyAojjeyFDxXqdmvegjPpSWsrPmrJjeQ2f",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 18,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 252.158865,
"decimals": 6,
"amount": "252158865",
"uiAmountString": "252.158865"
},
"owner": "GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 20,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 0.000806,
"decimals": 6,
"amount": "806",
"uiAmountString": "0.000806"
},
"owner": "5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
],
"postTokenBalances": [
{
"accountIndex": 2,
"mint": "4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"uiTokenAmount": {
"uiAmount": 1002575212.594466,
"decimals": 6,
"amount": "1002575212594466",
"uiAmountString": "1002575212.594466"
},
"owner": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
},
{
"accountIndex": 3,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 216817.828107,
"decimals": 6,
"amount": "216817828107",
"uiAmountString": "216817.828107"
},
"owner": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 5,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 25.14814,
"decimals": 6,
"amount": "25148140",
"uiAmountString": "25.14814"
},
"owner": "HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 6,
"mint": "4F4gGVBAWuKi3EpmYdhntXvCVFqZZqmrb1cqNGawpump",
"uiTokenAmount": {
"uiAmount": 994677499.811569,
"decimals": 6,
"amount": "994677499811569",
"uiAmountString": "994677499.811569"
},
"owner": "HR8M4iQmzagQ7vUDREycE2XSHuELmiQSFSrCa4eKytn5",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
},
{
"accountIndex": 8,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": null,
"decimals": 6,
"amount": "0",
"uiAmountString": "0"
},
"owner": "Ezz2ojEpLcYs3A7uMFW6pgnxtwbhHkJHRAU27zTfiYJU",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 10,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": null,
"decimals": 6,
"amount": "0",
"uiAmountString": "0"
},
"owner": "FGFrX2q1iAjyAojjeyFDxXqdmvegjPpSWsrPmrJjeQ2f",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 18,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 252.158865,
"decimals": 6,
"amount": "252158865",
"uiAmountString": "252.158865"
},
"owner": "GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 20,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"uiTokenAmount": {
"uiAmount": 0.000806,
"decimals": 6,
"amount": "806",
"uiAmountString": "0.000806"
},
"owner": "5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
],
"rewards": [],
"computeUnitsConsumed": 172099,
"costUnits": 181305
},
"version": 0,
"blockTime": 1785328584
}
}
@@ -1,706 +0,0 @@
{
"jsonrpc": "2.0",
"result": {
"blockTime": 1724128600,
"meta": {
"computeUnitsConsumed": 179064,
"err": null,
"fee": 88750,
"innerInstructions": [
{
"index": 3,
"instructions": [
{
"parsed": {
"info": {
"lamports": 1461600,
"newAccount": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 82
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"decimals": 6,
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"mintAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
},
"type": "initializeMint2"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"lamports": 1231920,
"newAccount": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"owner": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 49
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"wallet": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH"
},
"type": "create"
},
"program": "spl-associated-token-account",
"programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"stackHeight": 2
},
{
"parsed": {
"info": {
"extensionTypes": [
"immutableOwner"
],
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp"
},
"type": "getAccountDataSize"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 3
},
{
"parsed": {
"info": {
"lamports": 2039280,
"newAccount": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 165
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF"
},
"type": "initializeImmutableOwner"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH"
},
"type": "initializeAccount3"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 3
},
{
"accounts": [
"H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"11111111111111111111111111111111"
],
"data": "e5DmuZMrE66La6keggPtmZttXAHyPqrUdsWHGdAwjTu9Zi4QvU6WzPSyxrXtdgYkxfoP9G7ETiVjf1oBwq2u8NmkRUqrtiw4R1Hx6mNAPVHXxtGrCDcVg4AwcJ3hqcdndudCkB4b9GkJjFu",
"programId": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"lamports": 15616720,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"space": 679
},
"type": "allocate"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
},
"type": "assign"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"amount": "1000000000000000",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"mintAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
},
"type": "mintTo"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"authority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"authorityType": "mintTokens",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"newAuthority": null
},
"type": "setAuthority"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "5xcpNtotVBphT5Ckdf46pY6eeCiYbvrziarwLuSnoKaMkWNb2cZaD9feuADHprV4j7wcAP8E6tEGJk43TyUVXuCUjnP5YXBquQK7TCHwvqjiY1TM8sdvHQW9ciLj25dQuQC7JZ3Pgr832WvmExjr8F9mypGDRTavTfrBcfeUQzg4bTeYcGeTDCyEWFPgmGeT37grRSKj6PK5jP6JiW2q4gCEbgGxiLCfML9Qy2iovLEJ6uXwxLrTyiZ4x3G7eFLHkzjKN6CLRquMqD123t22UxZBhugGRT",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
},
{
"index": 4,
"instructions": [
{
"parsed": {
"info": {
"extensionTypes": [
"immutableOwner"
],
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp"
},
"type": "getAccountDataSize"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"lamports": 2039280,
"newAccount": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 165
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1"
},
"type": "initializeImmutableOwner"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "initializeAccount3"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
}
]
},
{
"index": 5,
"instructions": [
{
"parsed": {
"info": {
"amount": "37951768488745",
"authority": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"destination": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"source": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF"
},
"type": "transfer"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"lamports": 1100000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"lamports": 11000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "2K7nL28PxCW8ejnyCeuMpbXg4p3TxoCZETw2SodjK89Y1dHFkcjQaBAgMqnf4KDfhbC4774odcRcjDbB7G7xsGx95mVCrqiNQcX59kbAV5fx2XHu3WoCTiu9yyVbtyyuHqHPZuL18cevQMPTtggdQtDyzfxLKCEt4FnTfX2oRD7csmk3vFncJgCDcBQB",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Create",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeMint2",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2780 of 237974 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]",
"Program log: Create",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1595 of 214078 compute units",
"Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: InitializeImmutableOwner",
"Program log: Please upgrade to SPL Token 2022 for immutable owner support",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 207465 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: InitializeAccount3",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4214 of 203581 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 21990 of 221053 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s invoke [2]",
"Program log: IX: Create Metadata Accounts v3",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Allocate space for the account",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Assign the account to the owning program",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s consumed 36258 of 183748 compute units",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: MintTo",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4492 of 144975 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: SetAuthority",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2911 of 138336 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 131120 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: G3KpTd7rY3YHAAAAZXhjaXRlZAcAAABleGNpdGVkRwAAAGh0dHBzOi8vY2YtaXBmcy5jb20vaXBmcy9RbWNEaVA5d0FaOFFlaWpyTnJ0d0xlTUdrNDZ2S0FBZTh5dmZXdHVtQlpiVVJxx09pPxZatyeZoNyW2ve9tDfrT5dl7bJ0JjqTw0Orr0/T20gu0JUEOdSfmHbuZqF6sdH2JuMaAwa4lWuHXNGtQN0QsFdumei71UE0T9w/IatQ85pk4JEI1dEkqI1gmS5+",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 122356 of 249550 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]",
"Program log: Create",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 121831 compute units",
"Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeImmutableOwner",
"Program log: Please upgrade to SPL Token 2022 for immutable owner support",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 115244 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeAccount3",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 111364 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20301 of 127194 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Buy",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 86752 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 74664 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: vdt/007mYe7HT2k/Flq3J5mg3Jba9720N+tPl2XtsnQmOpPDQ6uvTwCrkEEAAAAAKeutVYQiAAAB3RCwV26Z6LvVQTRP3D8hq1DzmmTgkQjV0SSojWCZLn5YHcRmAAAAAABXtD0HAAAA1yQq8l6tAwAAq5BBAAAAANeMF6bNrgIA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 35957 of 106893 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"
],
"postBalances": [
122171125343,
1461600,
733959725969,
1101231920,
2039280,
15616720,
2039280,
279706994391733,
1,
1,
1141440,
323296939,
2500000,
1141440,
934087680,
731913600,
1009200,
0
],
"postTokenBalances": [
{
"accountIndex": 4,
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "962048231511255",
"decimals": 6,
"uiAmount": 962048231.511255,
"uiAmountString": "962048231.511255"
}
},
{
"accountIndex": 6,
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "37951768488745",
"decimals": 6,
"uiAmount": 37951768.488745,
"uiAmountString": "37951768.488745"
}
}
],
"preBalances": [
123308602893,
0,
733955725969,
0,
0,
0,
0,
279706983391733,
1,
1,
1141440,
323296939,
2500000,
1141440,
934087680,
731913600,
1009200,
0
],
"preTokenBalances": [],
"rewards": [],
"status": {
"Ok": null
}
},
"slot": 284682639,
"transaction": {
"message": {
"accountKeys": [
{
"pubkey": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "ComputeBudget111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "SysvarRent111111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"signer": false,
"source": "transaction",
"writable": false
}
],
"addressTableLookups": [],
"instructions": [
{
"accounts": [],
"data": "HnkkG7",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"parsed": {
"info": {
"destination": "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY",
"lamports": 4000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [],
"data": "3ZfX8LdfViHV",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "U5L9Srg16xJSo5n5mGEnUQaep1FgNe24zh1oYXVbcVpSyAPk5QWVT8RNVbaJeebkjgPqHUHnWwPyPFmJ21HDBYXgTd8HTU7QfbiY7cn26rn4zxi724rGkbWKwnJHghce74jdF8dLeGwvYnU",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"parsed": {
"info": {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"wallet": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "create"
},
"program": "spl-associated-token-account",
"programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "AJTQ2h9DXrBiKPvzMVAo11jUarcFAxcz3",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
}
],
"recentBlockhash": "4LkonCgzoF4HF4ZmrczNCntkk5QJzoBfwEG67o99S6yR"
},
"signatures": [
"52ar89rghM8EwKZkxFnBMC4LaMReqtVdpxqXxGWBCMYV1DnYdLrdsqJo8Hbn9KjVpckAokqGNHzTSVfK5xuLepdC",
"SpE85aiJConP43xzaqrri6TRmEbKZdiSJoXeTixJPuMkYUSQZbyjxrb3NbatshfoggYacnyd1YWJf98iPV5YYqm"
]
},
"version": 0
},
"id": 1
}
@@ -0,0 +1,938 @@
{
"jsonrpc": "2.0",
"result": {
"slot": 435946190,
"transaction": {
"signatures": [
"2RoRJxatbF9Qkv87jei19u7ei2ckyjjnrCHZBRRAXi4GFJi68kra2iPSk7aoQ9Ugnf5FK5Mdp274hMaVSzn6SN5M",
"JMq7H9uF7WZSDAXh87MZ35WK3VFQGFGvdMRDcfVibeyLn6R5Q7xCmsAUEtP334hgvozVi9n8axCTBVhHQxxJbJv"
],
"message": {
"accountKeys": [
{
"pubkey": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"writable": true,
"signer": true,
"source": "transaction"
},
{
"pubkey": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"writable": true,
"signer": true,
"source": "transaction"
},
{
"pubkey": "moonQBUKBpkifLcTd78bfxxt4PYLwmJ5admLW6cBBs8",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "DnZP8kkE9F1rjtRA5c6XV19pVy7jmejz3ogrQvXSiE28",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "FK84ZzCXoeEsuMv1xZVZt8C4d1Ga3aZmsT4pRBoyAx8",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "HgY6tnTruYkYVNxutwL2wNgJFQ6sNWUznAzY241sy3UN",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "HkugJFWzibGu4qpCcXRnhgtcLfzoUoFxvNVA53ntg3aL",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "AFqUN4G2XKAiZHn2g4WQvfc5h5V6F44RwJbc4xo8mwq7",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "J37uRkBuK3YTyKRDRQE2tBsCn4tSgych29jtov9xvT87",
"writable": true,
"signer": false,
"source": "transaction"
},
{
"pubkey": "11111111111111111111111111111111",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "CFL2VF5HJMMr594er6eFmNrGwtB9NFTFwkoPeS1j36JH",
"writable": false,
"signer": false,
"source": "transaction"
},
{
"pubkey": "uxtoRPdPjRekYmxs1uUqVRZWh38iqonc9KgPuZXPeSY",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "Hq2wp8uJ9jCPsYgNHex8RtqdvMPfVGoYwjvF1ATiwn2Y",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW",
"writable": true,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "13ec7XdrjF3h3YcqBTFDSReRcUFwbCnJaAQspM4j6DDJ",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "So11111111111111111111111111111111111111112",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"writable": false,
"signer": false,
"source": "lookupTable"
},
{
"pubkey": "8Wf5TiAheLUqBrKXeYg2JtAFFMWtKdG2BSFgqUcPVwTt",
"writable": false,
"signer": false,
"source": "lookupTable"
}
],
"recentBlockhash": "DJUAWKW6ZfJaZsCWVpNb6UxGZKzHrqii9PFSCgsXnLXG",
"instructions": [
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "moonQBUKBpkifLcTd78bfxxt4PYLwmJ5admLW6cBBs8",
"lamports": 3000000,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 1
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "uxtoRPdPjRekYmxs1uUqVRZWh38iqonc9KgPuZXPeSY",
"lamports": 27000000,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 1
},
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"11111111111111111111111111111111",
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e",
"13ec7XdrjF3h3YcqBTFDSReRcUFwbCnJaAQspM4j6DDJ",
"BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"DnZP8kkE9F1rjtRA5c6XV19pVy7jmejz3ogrQvXSiE28",
"FK84ZzCXoeEsuMv1xZVZt8C4d1Ga3aZmsT4pRBoyAx8",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"So11111111111111111111111111111111111111112",
"HgY6tnTruYkYVNxutwL2wNgJFQ6sNWUznAzY241sy3UN",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
],
"data": "4g1G41E9F3d9vExc4Do9u7QxfRzozMvDWZ7LG2YW2SfQo1zakKNegdCUVJ8hQdNbb8cpcZvz2LHX23G9uy7kggnr6wnws9BzxvYTozDqQM1WY7Zor5AYYvnqzYVshCX4MPZz5GSBrvfyfHZZtmS9nWpk4aw5EyMCMeQKowWH4ULLj7ywjHDS5SA9e",
"stackHeight": 1
},
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"11111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "gCzGGoTR6NG",
"stackHeight": 1
},
{
"program": "spl-associated-token-account",
"programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"parsed": {
"info": {
"account": "HkugJFWzibGu4qpCcXRnhgtcLfzoUoFxvNVA53ntg3aL",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"wallet": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "createIdempotent"
},
"stackHeight": 1
},
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV",
"CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"HkugJFWzibGu4qpCcXRnhgtcLfzoUoFxvNVA53ntg3aL",
"5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"11111111111111111111111111111111",
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"AFqUN4G2XKAiZHn2g4WQvfc5h5V6F44RwJbc4xo8mwq7",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"Hq2wp8uJ9jCPsYgNHex8RtqdvMPfVGoYwjvF1ATiwn2Y",
"J37uRkBuK3YTyKRDRQE2tBsCn4tSgych29jtov9xvT87",
"8Wf5TiAheLUqBrKXeYg2JtAFFMWtKdG2BSFgqUcPVwTt",
"pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
"CFL2VF5HJMMr594er6eFmNrGwtB9NFTFwkoPeS1j36JH",
"A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"
],
"data": "PvwdRapqdNv7Ry3voaEfX8BUqgdxDijhcK",
"stackHeight": 1
}
],
"addressTableLookups": [
{
"accountKey": "HQ4G6FjmW8yZ15XGoiQdGDvbi5C7fJKktNg6pzCzdHg4",
"writableIndexes": [
42,
4,
6,
43,
8,
10,
21
],
"readonlyIndexes": [
22,
11,
1,
5,
12,
23,
24,
9
]
}
]
}
},
"meta": {
"err": null,
"status": {
"Ok": null
},
"fee": 10000,
"preBalances": [
98807226520,
0,
6160686613,
0,
0,
0,
0,
0,
0,
23859389,
1844400,
1,
8502112342,
3388605256,
0,
422099136126,
11149834,
46700153690375,
23556978269591,
17016138,
6046720,
2044091537,
1020235880,
4089612038,
70128637,
3104160,
168261371,
1630911579072,
58238313,
37290293
],
"postBalances": [
95767458600,
3667920,
6163686613,
2964904802,
2074080,
0,
0,
0,
2074080,
23859389,
10733289,
1,
8502112342,
3388605256,
0,
422126136126,
11149834,
46700153690375,
23556992343666,
17016138,
6046720,
2058165611,
1020235880,
4089612038,
70128637,
3104160,
168261371,
1630911579072,
58238313,
37290293
],
"innerInstructions": [
{
"index": 2,
"instructions": [
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"lamports": 2519520,
"newAccount": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"owner": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"space": 234
},
"type": "createAccount"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"metadataAddress": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump"
},
"type": "initializeMetadataPointer"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"decimals": 6,
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"mintAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
},
"type": "initializeMint2"
},
"stackHeight": 2
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"lamports": 1691280,
"newAccount": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"owner": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"space": 115
},
"type": "createAccount"
},
"stackHeight": 2
},
{
"program": "spl-associated-token-account",
"programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"parsed": {
"info": {
"account": "Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"wallet": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3"
},
"type": "create"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"extensionTypes": [
"immutableOwner"
],
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump"
},
"type": "getAccountDataSize"
},
"stackHeight": 3
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"lamports": 2074080,
"newAccount": "Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"owner": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"space": 170
},
"type": "createAccount"
},
"stackHeight": 3
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"account": "Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF"
},
"type": "initializeImmutableOwner"
},
"stackHeight": 3
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"account": "Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"owner": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3"
},
"type": "initializeAccount3"
},
"stackHeight": 3
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"lamports": 1148400,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"metadata": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"mintAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"name": "The Ass Statue",
"symbol": "TAS",
"updateAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"uri": "https://meta.uxento.io/data/714b0bec-90cb-4cbb-9598-b7bcbcd3bd06"
},
"type": "initializeTokenMetadata"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"metadata": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"newAuthority": null,
"updateAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
},
"type": "updateTokenMetadataAuthority"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"account": "Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"amount": "1000000000000000",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"mintAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
},
"type": "mintTo"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"authority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"authorityType": "mintTokens",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"newAuthority": null
},
"type": "setAuthority"
},
"stackHeight": 2
},
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "4do6MfY17mvDg86G3wa87MbF75DmJaC7cBgnhtjcQbn9UzTH5Ncjub9UFW4hQS4qsriGnaXRED1wxWGrXLxmb5RuREEG5w2nTLgVJJ6cSCpzQoQTaqqwpobcRRLsbVzDVVY188Whbgn7dPi95hd91TYKCXuyvgkEWhacHfJJAyta1Pe51Ej9YoJJqyWdt3q68pfKgnU1L8usTUy31rj38fVcJvo6xHMUPvD7YpCg4gXW3rMpJbqRjjvLD9mW8Tvxjb79pe3DWmM6HorNcP8QW47gSULHrJMxWZbXvoPuTCXqeHRAoa252qKut5aSu91DnqVqBRH8xAULcCdMhekZAGYrvuqugBZz7jXGYCS3ce1hirxY2zvPhrUUah8ss2zxZhiVwa6xTsefwzhNQxuKNRK9Ff3W4cDBiM2ZjD7kef6m6HTGnoBN1NBokv6YYC9gyd38wi3PBXYiwTSKD3Rjoy8mMifRQa6b",
"stackHeight": 2
}
]
},
{
"index": 3,
"instructions": [
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"lamports": 250560,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 2
},
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "21448NTnPMYUBkX8r9jEFxShLqQHYei1N5cxdsxoe8cAXgrWuM1b46WUHHYJknU1k1xic4fTYpRZmztRmBatNfWd9RSzFrVMnQpaoJsaipjePKurznQLJgKhCnrmJjeXaxCup1xKfU7ttco",
"stackHeight": 2
}
]
},
{
"index": 4,
"instructions": [
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"extensionTypes": [
"immutableOwner"
],
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump"
},
"type": "getAccountDataSize"
},
"stackHeight": 2
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"lamports": 2074080,
"newAccount": "HkugJFWzibGu4qpCcXRnhgtcLfzoUoFxvNVA53ntg3aL",
"owner": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"space": 170
},
"type": "createAccount"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"account": "HkugJFWzibGu4qpCcXRnhgtcLfzoUoFxvNVA53ntg3aL"
},
"type": "initializeImmutableOwner"
},
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"account": "HkugJFWzibGu4qpCcXRnhgtcLfzoUoFxvNVA53ntg3aL",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"owner": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "initializeAccount3"
},
"stackHeight": 2
}
]
},
{
"index": 5,
"instructions": [
{
"programId": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
"accounts": [
"8Wf5TiAheLUqBrKXeYg2JtAFFMWtKdG2BSFgqUcPVwTt",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "6E5CZKNB2G93HVu9Syn6kkEUE5ZYBEkjrAW4Dfp9EBMjXR9",
"stackHeight": 2
},
{
"program": "spl-token",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
"parsed": {
"info": {
"authority": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"destination": "HkugJFWzibGu4qpCcXRnhgtcLfzoUoFxvNVA53ntg3aL",
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"source": "Cd4iC3Jndc2WVud6rAs1cwx8SkUQhCN5TxXbfRtbHLCF",
"tokenAmount": {
"amount": "96449438144093",
"decimals": 6,
"uiAmount": 96449438.144093,
"uiAmountString": "96449438.144093"
}
},
"type": "transferChecked"
},
"stackHeight": 2
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "J37uRkBuK3YTyKRDRQE2tBsCn4tSgych29jtov9xvT87",
"lamports": 8888889,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 2
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"lamports": 2962962962,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 2
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW",
"lamports": 14074074,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 2
},
{
"program": "system",
"programId": "11111111111111111111111111111111",
"parsed": {
"info": {
"destination": "62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV",
"lamports": 14074075,
"source": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM"
},
"type": "transfer"
},
"stackHeight": 2
},
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "Aa2dSnituwvkDoueD1F3asXiWzpxqmNfp9C24GrpjGgE6UHyGsZt48W7w6XScmSwucWX9oiKNrq9a2Lb1ckvnRT5dTRbWraqoWC3p1Lq6b24bzoMQ2cKJbC59Kp49F4uHZZWB4eARcWciKf5juykotVy9fKZCH27LrpHKtW454BLVkyVLSheDB7gtLxEemn5r6J8jwEs6dQUG9w6LzWbWoCxC1AZkEHj5DMwE7kZ4Z55sGJXR9auHiU7DwdYQPfN1xfLTV8tVY4xLrQ8pcMN4Bu2L89SjqMFNghEAvNEMtKfoCskSH1ibyDLGkis1aR22ezM9WJfHQFcrGoEmJS3WxB63paeXY59xB8uZoi8aFqWc9bKfFmbq4BNnq8cDtYMbiEFLwXc8JzwLpehM6FkfuZWGYmhGNcGK63G4uwJcVoF5qrJ5eJkKpLeYACAbZPoAWegLA7EGT6vgz3Wtu3wmiRMDBGCKMzhjVvJZMxFEarifxE6K71KKd5vYSDowKAido7wQb",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: CreateV2",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: MetadataPointerInstruction::Initialize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 925 of 792685 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: InitializeMint2",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1772 of 790097 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]",
"Program log: Create",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1447 of 768858 compute units",
"Program return: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb qgAAAAAAAAA=",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]",
"Program log: Instruction: InitializeImmutableOwner",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 736 of 762589 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]",
"Program log: Instruction: InitializeAccount3",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1969 of 759517 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 16947 of 774191 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: TokenMetadataInstruction: Initialize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 3522 of 732525 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: TokenMetadataInstruction: UpdateAuthority",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 3866 of 726753 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: MintTo",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1714 of 720713 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: SetAuthority",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1044 of 717060 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program data: G3KpTd7rY3YOAAAAVGhlIEFzcyBTdGF0dWUDAAAAVEFTQAAAAGh0dHBzOi8vbWV0YS51eGVudG8uaW8vZGF0YS83MTRiMGJlYy05MGNiLTRjYmItOTU5OC1iN2JjYmNkM2JkMDarDUVGkFAyRzCsYxVgJvZmb/09juzXRcgA2DNBRiFAnyiNIIamJQRxRzVeoOuuRwVPIoHsLN6K2zqPUbEf9bssRef0SuNtc2Y43Xotj2C0NWe2RcC/3hbdIrULc6ozrN5F5/RK421zZjjdei2PYLQ1Z7ZFwL/eFt0itQtzqjOs3gLwaWoAAAAAABDYR+PPAwAArCP8BgAAAAB4xftR0QIAAIDGpH6NAwAG3fbh7nWP3hhCXbzkbM3athr8TYO5DSf+vfko2KGL/AABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArCP8BgAAAA==",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2125 of 709816 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 99196 of 805700 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: ExtendAccount",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program data: YWHXkF2SFnwojSCGpiUEcUc1XqDrrkcFTyKB7Czeits6j1GxH/W7LEXn9ErjbXNmON16LY9gtDVntkXAv94W3SK1C3OqM6zecwAAAAAAAACXAAAAAAAAAALwaWoAAAAA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2125 of 697247 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 11575 of 706504 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]",
"Program log: CreateIdempotent",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1523 of 683669 compute units",
"Program return: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb qgAAAAAAAAA=",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: InitializeImmutableOwner",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 736 of 677324 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: InitializeAccount3",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2153 of 674255 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 23110 of 694929 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: BuyExactSolIn",
"Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ invoke [2]",
"Program log: Instruction: GetFees",
"Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ consumed 3302 of 633697 compute units",
"Program return: pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ AAAAAAAAAABfAAAAAAAAAB4AAAAAAAAA",
"Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ success",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]",
"Program log: Instruction: TransferChecked",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2562 of 625274 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program data: vdt/007mYe6rDUVGkFAyRzCsYxVgJvZmb/09juzXRcgA2DNBRiFAnxI6m7AAAAAAXdZ/YrhXAAABRef0SuNtc2Y43Xotj2C0NWe2RcC/3hbdIrULc6ozrN4C8GlqAAAAABLmvqwHAAAAozlY5Sp4AwASOpuwAAAAAKOhRZmZeQIASsL40N1cvJfjKJwZfLUGKlTz2Va5zm5RFfllZ6pcs+ZfAAAAAAAAALWBrQEAAAAARef0SuNtc2Y43Xotj2C0NWe2RcC/3hbdIrULc6ozrN4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAGJ1eV9leGFjdF9zb2xfaW4AHgAAAAAAAAA5oocAAAAAAIgTAAAAAAAA2sDWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASOpuwAAAAABLmvqwHAAAAEjqbsAAAAAA=",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2125 of 604471 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 71354 of 671819 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"
],
"preTokenBalances": [],
"postTokenBalances": [
{
"accountIndex": 4,
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"uiTokenAmount": {
"uiAmount": 903550561.855907,
"decimals": 6,
"amount": "903550561855907",
"uiAmountString": "903550561.855907"
},
"owner": "3jJ83NDorkbFkF1JKbEfFWGeX16aXUiwby9RwJm9kat3",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
},
{
"accountIndex": 8,
"mint": "CWiTGbCiDd8BKtNYNE2boT9fJGFG2MU53Uf6HQk4pump",
"uiTokenAmount": {
"uiAmount": 96449438.144093,
"decimals": 6,
"amount": "96449438144093",
"uiAmountString": "96449438.144093"
},
"owner": "5htGpHK2oV9g2BcDqLdRBqjCLdy8mc3fsESfR5DU73eM",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
}
],
"rewards": [],
"computeUnitsConsumed": 205535,
"costUnits": 215799
},
"version": 0,
"blockTime": 1785327618
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ dependencies = [
[dependency-groups]
dev = [
"ruff>=0.10.0",
# protoc; only needed to regenerate the geyser_pb2 stubs from proto/
# protoc; only needed to regenerate src/geyser/generated from src/geyser/proto
"grpcio-tools>=1.71.0",
]